Read and print XML with only small changes using PHP - php

I've been looking for a simple way to print an XML from a URL, exactly as it came, with only a few changes. I have this feed:
<products>
<product>
<name>Product example</name>
<image>http://example.com</image>
</product>
</products>
I want to take this and print it out like this:
<products>
<product>
<name>Product example</name>
<image>http://example.com?utm_campaign=changes</image>
</product>
</products>
Is this possible?
Thanks!

You can load an XML file using simplexml_load_file()
Doc : http://php.net/manual/fr/function.simplexml-load-file.php
It permits to create an object from the XML loaded. Just modify what you want on, then use dom_import_simplexml() to transform it into a DOMElement.
Doc : http://www.php.net/manual/en/function.dom-import-simplexml.php
Using DOMElement::saveXml() returning the XML result.
Doc : http://php.net/manual/fr/domdocument.savexml.php
Don't know if it's the easiest way, but it would work.
Thanks.

Related

How to call from XML

I have this following XML call from an API...
<response xmlns="http:/xml-api">
<result id="123123" status="Success">
<product>
<identifiers>
<store>
<keycode>abcdefghi123</keycode>
<title>Sweet Dreams Are Made out of these</title>
</store>
<location>
<origin>South Africia</origin>
<current>Brazil</current>
</location>
</identifiers>
</product>
</result>
</response>
I'm just trying to understand how to recall the keycode and the title values... Using my simplexml_load()...
I currently have set API call to $myXMLdata:
$xmlFile = simplexml_load_string($myXMLData) or die("Error!!!");
echo $xmlFile->response->result->product->identifiers->store[1];
But it doesn't seem to return anything from the XML page.
You set not correct path to needed tags. Write it so:
echo $xmlFile->result->product->identifiers->store->keycode;
echo $xmlFile->result->product->identifiers->store->title;
Pay attention that root tag (response in the case) should be not included in the path
demo

simplexml load multiple files at once

I'm using XML to fetch some language data.
The XML markup is as follows:
<language>
<item>
<key>KEY</key>
<string>STRING</string>
</item>
<item>
....
</item>
</language>
I have 2 XML-files with the same markup. I want to load them both with simplexml_load_file. Does anyone know what's the best approach to do this?
I tried something like this:
<?php
$xml = simplexml_load_file('...url_file_1...');
$xml .= simplexml_load_file('...url_file_2...');
?>
But thats not working. But thats what I want: all the data from the 2 (and eventually more) files in one variable.
Edit: I want to make use of the simpleXML library if possible.

Using unset() to delete node in XML; PHP/simplexml_load_file

I'm trying to use unset() to delete a node in an XML using PHP and can't figure out what is going on here. It doesn't seem to work correctly and I've seen a lot of other questions of similar nature on here but they don't seem to address this issue directly. Here's what my XML looks like:
<?xml version="1.0" encoding="UTF-8"?>
<data>
<user>
<name>Test Name 1</name>
<email>test#test.com</email>
<spouse/>
</user>
<user>
<name>Test Name 2</name>
<email>anotherone#test.com</email>
<spouse>Test Name 3</spouse>
</user>
</data>
My loop that I'm using is like this:
url = 'data/users.xml';
$xml = simplexml_load_file($url);
foreach($xml->user as $theUser){
if($theUser->email[0]=="test#test.com"){
echo "test";
unset($theUser);
}
}
When the e-mail matches "test#test.com" I want to be able to delete that whole user node. It seems that this should work but I can't figure out why it wouldn't? Any help would be greatly appreciated. Thank you!
SimpleXML is fine, no need to switch to DOM, unset() is working fine, if you do it right:
unset($theUser[0]);
see it working: https://eval.in/228773
However there will be a problem with your foreach() if you delete a node mid-loop.
I suggest to use xpath() instead of a loop, IMO elegant and the code is much simpler.
$users = $xml->xpath("/data/user[email='test#test.com']");
will create an array of all <user> with that email-address.
unset($users[0][0]);
will delete the first user in that array.
foreach ($users as $user) unset($user[0]);
will delete the whole array.
see this in action: https://eval.in/228779
SimpeXML is not really meant for changing to the XML structure. Just a simple way of reading the XML.
If you want to manipulate the XML structure you should use the dom functions and more specifically the dom_import_simplexml. This function allows you to import a SimpleXML element and turn it into a DomElement that can be used for manipulation and that includes deletion.
Here is a code sample that solves your problem and demonstrates the usage of dom_import_simplexml.
<?php
$xmlData = '<?xml version="1.0" encoding="UTF-8"?>
<data>
<user>
<name>Test Name 1</name>
<email>test#test.com</email>
<spouse/>
</user>
<user>
<name>Test Name 2</name>
<email>anotherone#test.com</email>
<spouse>Test Name 3</spouse>
</user>
</data>';
$xml = simplexml_load_string($xmlData);
foreach($xml->user as $theUser){
if($theUser->email == 'test#test.com'){
$dom = dom_import_simplexml($theUser);
$dom->parentNode->removeChild($dom);
}
}
echo $xml->asXml();
When reading this code you might be thinking why this works since we dont save the new structure anywhere after we have executed the removeChild function. This works because the DOM functions does not create copies of the underlying objects but instead manipulates them directly.
Result
<?xml version="1.0" encoding="UTF-8"?>
<data>
<user>
<name>Test Name 2</name>
<email>anotherone#test.com</email>
<spouse>Test Name 3</spouse>
</user>
</data>

update element from node in XML

First of all, I just found this site a few days ago and am very happy it exists.
I am facing a problem with updating a child element from a XML Node.
The xml looks like this:
<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="books.xsl"?>
<books>
<book>
<id>1</id>
<bookname>Title 1</bookname>
<bookurl>SomeURLToMyBook</bookurl>
<clicks>0</clicks>
</book>
<book>
<id>2</id>
<bookname>Title 2</bookname>
<bookurl>SomeURLToMyBook</bookurl>
<clicks>0</clicks>
</book>
</books>
I do know how to retrieve the node for book with (e.g.) ID 2 using:
$xml= simplexml_load_file('books.xml);
I then use xpath to find the correct node. as in:
$booknum= $_GET('booklist'); //booklist is the parameter in the querystring
$arrOutput = $xml->xpath("//*[id='".$booknum."']");
What I try to achieve is to update the clicks element and then save the outcome into the existing XML.
I found several code examples on this site but neither one seems to work for me.
I probably do something wrong but I am not really familiar with PHP (learning new things every day!)
So if anybody is willing to help me out I would be grateful.
TIA

PHP domDocument to remove child nodes of a child node

How do I remove a parent node of a child node, but keep all the children?
The XML file is this:
<?xml version='1.0'?>
<products>
<product>
<ItemId>531<ItemId>
<modelNumber>00000</modelNumber>
<categoryPath>
<category><name>Category A</name></category>
<category><name>Category B</name></category>
<category><name>Category C</name></category>
<category><name>Category D</name></category>
<category><name>Category E</name></category>
</categoryPath>
</product>
</products>
Basically, I need to remove the categoryPath node and the category node, but keep all of the name nodes inside of the product node. What I am aiming for is a document like this:
<?xml version='1.0'?>
<products>
<product>
<ItemId>531<ItemId>
<modelNumber>00000</modelNumber>
<name>Category A</name>
<name>Category B</name>
<name>Category C</name>
<name>Category D</name>
<name>Category E</name>
</product>
</products>
Is there PHP built in function to do this? Any pointers would be appreciated, I just do not know where to start because there are many child nodes.
Thanks
A good approach to process XML data is to use the DOM facility.
It's quite easy once you get introduced to it. For example:
<?php
// load up your XML
$xml = new DOMDocument;
$xml->load('input.xml');
// Find all elements you want to replace. Since your data is really simple,
// you can do this without much ado. Otherwise you could read up on XPath.
// See http://www.php.net/manual/en/class.domxpath.php
$elements = $xml->getElementsByTagName('category');
// WARNING: $elements is a "live" list -- it's going to reflect the structure
// of the document even as we are modifying it! For this reason, it's
// important to write the loop in a way that makes it work correctly in the
// presence of such "live updates".
while($elements->length) {
$category = $elements->item(0);
$name = $category->firstChild; // implied by the structure of your XML
// replace the category with just the name
$category->parentNode->replaceChild($name, $category);
}
// final result:
$result = $xml->saveXML();
See it in action.

Categories