I have an XML like the one below, I am trying to do an xpath query and parse it with simplexml. The XML is a CURL response and is stored in a $response variable. I need to look the Code attribute inside the <Item> and select the parent <Product> to parse it.
$response:
<Items>
<Product>
<Item Code="123">
</Item>
<Price>170
</Price>
</Product>
<Product>
<Item Code="456">
</Item>
<Price>150
</Price>
</Product>
</Items>
This is what I am doing:
$xml = simplexml_import_dom($response);
function loadNode($code){
global $xml;
$scode = $xml->xpath('//Item[contains(#Code,"' . $code . '")]/..');
echo $scode->Items->Product->Price;
}
loadNode("123");
This is the Notice I get:
Notice: Trying to get property of non-object
A couple of observations:
The xpath() method returns an array of SimpleXMLElement
objects, not a single SimpleXMLElement. (Yes, even though there can only be a single parent of an element, you still have to get it as the first member of the array ([0]).
$scode->Items->Product->Price should be changed to just
$scode->Price.
These modifications to your PHP code:
<?php
$response = <<<XML
<Items>
<Product>
<Item Code="123">
</Item>
<Price>170
</Price>
</Product>
<Product>
<Item Code="456">
</Item>
<Price>150
</Price>
</Product>
</Items>
XML;
$xml = simplexml_load_string($response);
function loadNode($code) {
global $xml;
$scode = $xml->xpath('//Item[contains(#Code,' . $code . ')]/..')[0];
echo $scode->Price;
}
loadNode("123");
?>
When run will yield this output:
170
as expected.
Related
I want to get the ISBN number of a book from an Amazon XML File. I already checked other posts and tried to solve the problem with them but without any success. The $xml looks like:
<itemlookupresponse>
<items>
<item>
<itemattributes>
<studio>Pottermore from J.K. Rowling</studio>
<eisbn>9781781100769</eisbn>
</itemattributes>
</item>
<item>
<itemattributes>
<studio>Carlsen Verlag GmbH</studio>
<isbn>3551551677</isbn>
</itemattributes>
</item>
<item>
<itemattributes>
<studio>Carlsen</studio>
<isbn>3551551677</isbn>
</itemattributes>
</item>
</items>
</itemlookupresponse>
I want to get the items, where the ISBN equals 3551551677. For that reason, I used the following command, which unfortunately returns an empty array.
$item = $xml->xpath('//items/item[itemattributes/isbn=3551551677]');
I would be glad, if someone could help me and explain, what I made wrong.
XML and XPath are case-sensitive. Amazon's XML is not all lowercase, despite what you've posted in your question. Adjust your XPath to match the exact case used in Amazon's actual XML.
Note also that if there are namespaces involved in the actual XML, those too must be accounted for in your XPath. See How does XPath deal with XML namespaces?
You didn't show something important (namespaces?) because this code works for me:
$string = <<<XML
<itemlookupresponse>
<items>
<item>
<itemattributes>
<studio>Pottermore from J.K. Rowling</studio>
<eisbn>9781781100769</eisbn>
</itemattributes>
</item>
<item>
<itemattributes>
<studio>Carlsen Verlag GmbH</studio>
<isbn>3551551677</isbn>
</itemattributes>
</item>
<item>
<itemattributes>
<studio>Carlsen</studio>
<isbn>3551551677</isbn>
</itemattributes>
</item>
</items>
</itemlookupresponse>
XML;
$xml = new SimpleXMLElement($string);
/* Поиск <a><b><c> */
$items = $xml->xpath('//items/item[ ./itemattributes/isbn[.="3551551677"] ]');
//$items = $xml->xpath('//items/item[itemattributes/isbn=3551551677]');
echo "Result size: " . count($items) . "\n";
foreach ( $items as $item) {
echo $item->asXML() . "\n";
}
HI I have a php script which finds certain Words in an XML file. I would like to add a new XML element if a certain word was found at the end of the file. But in my code it add one every time it finds one.
What I am doing wrong?
XML:
<products>
<product>
<title>TestProduct</title>
<Specifications>
<item name="Specifications1">Test</item>
<item name="Specifications2">Hello World</item>
</Specifications>
<body>
<item name="Color">Black</item>
</body>
</product>
</products>
PHP:
$dom = new DOMDocument;
$dom->load('Test.xml');
$xpath = new DOMXPath($dom);
foreach ($xpath->query("//*[contains(., 'Black')]") as $item) {
$element = $dom->createElement('ID', '123');
$item->appendChild($element);
}
echo $dom->saveXML();
should look like that:
<products>
<product>
<title>TestProduct</title>
<Specifications>
<item name="Specifications1">Test</item>
<item name="Specifications2">Hello World</item>
</Specifications>
<body>
<item name="Color">Black</item>
</body>
<ID>123</ID>
</product>
</products>
If I undertood correctly, you can your change xpath with
//product[contains(body/item, 'Black')]
Then the code will add new ID tag to the product, having item with the value 'Black'
demo
i'm trying to remove one item from a xml with all of it's child nodes but when i excecute following php only the child nodes will be removed.
following is my php
<?php
header('Content-Type: text/xml');
$doc = new DOMDocument('1.0');
$url = '../../data/auction.xml';
$itemNo ="0";
$xml=simplexml_load_file($url);
foreach($xml->xpath('/items/item[itemNumber="'.$itemNo.'"]')as $child)
{
unset($child[0]);
//$child->parentNode->removeChild($node);
}
print $xml->asXML();
?>
the original XML
<?xml version="1.0"?>
<items>
<item>
<itemNumber>0</itemNumber>
<itemName>item1</itemName>
<category>Phones</category>
</item>
<item>
<itemNumber>2</itemNumber>
<itemName>item3</itemName>
<category>laptops</category>
</item>
</items>
Actual output
<items>
<item>
</item>
<item>
<itemNumber>2</itemNumber>
<itemName>item3</itemName>
<category>laptops</category>
</item>
</items>
Desired output
<items>
<item>
<itemNumber>2</itemNumber>
<itemName>item3</itemName>
<category>laptops</category>
</item>
</items>
Please tell me what i'm doing wrong
For example I have 2 types of nodes in my xml file:
1) <book>
2) <author>
A variable named $node points to specific node(of unknown type).
How can I access this node's name? It must be something like this:
if($node->name()=="book")
process_book($node);
else
process_author;
SimpleXMLElement has a getName() method:
echo $node->getName();
Assumption: $node is a SimpleXMLElement object.
I may be missing something, but here is a simlpe solution. Change simplexml_load_string to simplexml_load_file if your using a file.
$xml_string = <<<XML
<root>
<item>
<book>Book 1</book>
<author>Author 1</author>
</item>
<item>
<book>Book 2</book>
<author>Author 2</author>
</item>
<item>
<book>Book 3</book>
<author>Author 3</author>
</item>
</root>
XML;
$xml = simplexml_load_string($xml_string);
foreach($xml->item as $node){
if(isset($node->book)){
process_book($node);
}
}
I have an xml document with the following structure:
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>
<id>1</id>
<url>www.test.com</url>
</item>
<item>
<id>2</id>
<url>www.test2.com</url>
</item>
</items>
I would like to be able to search for a node value, such as the value of 1 for the id field. Then, once that node is found, select the parent node, which would be < item > and insert a new child within.
I know the concept of using dom document, but not sure how to do it in this instance.
This should be a start:
$dom = new DOMDocument;
$dom->loadXML($input);
$ids = $dom->getElementsByTagName('id');
foreach ($ids as $id) {
if ($id->nodeValue == '1') {
$child = $dom->createElement('tagname');
$child->appendChild($dom->createTextNode('some text'));
$id->parentNode->appendChild($child);
}
}
$xml = $dom->saveXML();
or something close to it.
You can do the same thing in a simpler way. Instead of looking for an <id/> node whose value is 1 then selecting its parent, you can reverse the relation and look for any node which has an <id/> child whose value is 1.
You can do that very easily in XPath, and here's how to do it in SimpleXML:
$items = simplexml_load_string(
'<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>
<id>1</id>
<url>www.test.com</url>
</item>
<item>
<id>2</id>
<url>www.test2.com</url>
</item>
</items>'
);
$nodes = $items->xpath('*[id = "1"]');
$nodes[0]->addChild('new', 'value');
echo $items->asXML();