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
Related
SUMMARY
Load existing XML-File
Add 2 items to every child
Change order of children
Write new XML-File
DETAILED EXPLANATION
This is a shortened sample of the Source-XML-File
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<warehouse>
<inventory>
<name>Name 1</name>
<markers>
<marker>red</marker>
<marker>yellow</marker>
<marker>green</marker>
</markers>
(...)
</inventory>
<inventory>
<name>Name 2</name>
<markers>
<marker>blue</marker>
<marker>pink</marker>
<marker>brown</marker>
</markers>
(...)
</inventory>
<inventory>
<name>Name 3</name>
<markers>
<marker>black</marker>
<marker>white</marker>
<marker>marron</marker>
</markers>
(...)
</inventory>
</warehouse>
1. Load existing XML-File
Load the XML-File into a variable.
$source_xmlfile = "source.xml";
$source_xml_file_contents = simplexml_load_file($source_xmlfile);
2. Add 2 items to every child
Add 2 children to the first inventory with name and value.
$source_xml_file_contents->warehouse->inventory[0]->addChild("new1", "0.12345");
$source_xml_file_contents->warehouse->inventory[0]->addChild("new2", "17");
3. Change order of children
This is the part that doesn't work for me, no matter what I tried.
My idea was the following:
$destination_xml_file_contents = new SimpleXMLElement('<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?><warehouse></warehouse>');
foreach($source_xml_file_contents->warehouse->inventory as $inventory){
$destination_xml_file_contents->warehouse->addChild("inventory", $inventory);
}
The basic idea is that I take a child (<inventory>) out of <warehouse> and store in in a variable or maybe an array (which would be way better and easier) containing everything that <inventory> contains (including attributes and child nodes and so on).
After I have stored all <inventory> somewhere else I take a new XML and put the stored <inventory> in a new order into the new XML.
However it seems impossible to save a whole child into a variable (or an array) and add it to another XML later.
Since the order is not necessarily in order a simple sort wouldn't help me out here and since I wasn't able to get sorting to work I am at a loss here.
4. Write new XML-File
Save the new XML content to a new XML-File.
$new_xml_file = "destination.xml";
$destination_xml_file_contents->asXML($new_xml_file);
This is a shortened sample of the destination-XML-File
<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
<warehouse>
<inventory>
<name>Name 2</name>
<markers>
<marker>blue</marker>
<marker>pink</marker>
</marker>brown</marker>
</markers>
(...)
<new1>0.6789</new1>
<new2>115</new2>
</inventory>
<inventory>
<name>Name 1</name>
<markers>
<marker>red</marker>
<marker>yellow</marker>
</marker>green</marker>
</markers>
(...)
<new1>0.4567</new1>
<new2>4</new2>
</inventory>
<inventory>
<name>Name 3</name>
<markers>
<marker>black</marker>
<marker>white</marker>
</marker>marron</marker>
</markers>
(...)
<new1>0.1234</new1>
<new2>17</new2>
</inventory>
</warehouse>
Can someone help me to figure out how to make this work?
Right now I'm resorting to parse the whole XML-File and rewrite it line by line with string since SimpleXML doesn't seem to work.
There are a few things which I'm not sure about, but hopefully this code will show the principle of copying the nodes from one document to another (and adding content) using DOMDocument. I've added comments to the code to help, if there is anything you are unsure about, then let me know.
$inFile = "data.xml";
$input = new DOMDocument();
$input->load($inFile);
$all_inventory = $input->getElementsByTagName("inventory");
// Add new content to each item
foreach ( $all_inventory as $inventory ) {
$inventory->appendChild ( $input->createElement("new1", "0.12345"));
$inventory->appendChild ( $input->createElement("new2", "17"));
}
$outFile = "out.xml";
$output = new DOMDocument();
// Create base document for destination
$output->loadXML('<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?><warehouse />');
// Get the root element as we will be adding content to this
$outputRoot = $output->documentElement;
foreach ( $all_inventory as $inventory ) {
// Copy the element from the input document to the output document
// Note this does not add it anywhere, just makes it available
// The true option says make a deep copy
$import = $output->importNode($inventory, true);
// Add the newly imported node to the output document root
$outputRoot->appendChild($import);
}
$output->save($outFile);
The output is almost just a copy of the input document with the extra data. You could in the second foreach() loop add some logic to order the output elements in some other format, which I'm not sure what that is.
Also note there is a minor XML flaw in your document...
</marker>green</marker>
I have noticed a very strange thing in eBay in the last few days. I am using both GetItem and GetSingleItem calls to get the quantity of an item. Since Monday (I think), the quantity the calls are returning is not correct. For example, if I open the ItemID 231802662855 in eBay, I see the item being available, I am able to purchase it, and the available quantity is 1. But if I make the API calls to get the quantity, both GetItem and GetSingleItem return Quantity = 0.
Here are the request and response for GetItem:
<?xml version="1.0" encoding="utf-8"?>
<GetItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">
<RequesterCredentials>
<eBayAuthToken>...</eBayAuthToken>
</RequesterCredentials>
<ErrorLanguage>en_US</ErrorLanguage>
<WarningLevel>High</WarningLevel>
<ItemID>231802662855</ItemID>
<OutputSelector>Item.Quantity</OutputSelector>
</GetItemRequest>
<?xml version="1.0" encoding="UTF-8"?>
<GetItemResponse xmlns="urn:ebay:apis:eBLBaseComponents">
<Timestamp>2017-07-07T07:23:52.205Z</Timestamp>
<Ack>Success</Ack>
<Version>1009</Version>
<Build>E1009_INTL_API_18420867_R1</Build>
<Item>
<Quantity>0</Quantity>
</Item>
</GetItemResponse>
And here are the request and response for GetSingleItem:
<?xml version="1.0" encoding="utf-8"?>
<GetSingleItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">
<ItemID>231802662855</ItemID>
<IncludeSelector>Details</IncludeSelector>
</GetSingleItemRequest>
<?xml version="1.0" encoding="UTF-8"?>
<GetSingleItemResponse xmlns="urn:ebay:apis:eBLBaseComponents">
<Timestamp>2017-07-07T07:30:36.420Z</Timestamp>
<Ack>Success</Ack>
<Build>E1021_CORE_APILW_18481359_R1</Build>
<Version>1021</Version>
<Item>
...
<Quantity>0</Quantity>
...
</Item>
</GetSingleItemResponse>
And if you open the same item in eBay, you can see it's actually available and it has 1 quantity. Link
Does anyone else have this problem? Did you find a solution for it?
It was a bug from eBay. They have now fixed the Shopping API and they said they will fix the Trading API soon too.
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.
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>
Midified the xml file using DomDocument object?
Have a file.xml
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<Document xmlns="urn:iso:std">
<content>
<GrpHdr>
<MsgId>xxxxxx </MsgId>
<CreDtTm>2010-07-05T16:48:00</CreDtTm>
<BtchBookg>false</BtchBookg>
<NbOfTxs>2</NbOfTxs>
<CtrlSum>56653</CtrlSum>
<Grpg>Old</Grpg>
<InitgPty>
<Nm> Name </Nm>
</InitgPty>
</GrpHdr>
</content>
<Document>
How can modified the xml data and save back to file.xml (for example )
<NbOfTxs>1</NbOfTxs>
<CtrlSum>1223</CtrlSum>
<Grpg>NEW</Grpg>
Use save() function of the DomDocument Object, for example:
$dom->save("newfile.xml")
Look here for further details