i have a XML document that looks like this:
<body>
<item id="9982a">
<value>ab</value>
</item>
<item id="9982b">
<value>abc</value>
</item>
etc...
</body>
Now, i need to get the value for a key, the document is very very big, is there any way to go directly to the key when i know the id? Rather then loop it?
Something like:
$xml = simplexml_load_string(file_get_contents('http://somesite.com/new.xml'));
$body = $xml->body;
$body->item['id'][9982a]; // ab
?
xpathis your friend, you can stay with simplexml:
$xml = simplexml_load_string($x); // assume XML in $x
$result = $xml->xpath("/body/item[#id = '9982a']/value")[0]; // requires PHP >= 5.4
echo $result;
Comment:
in PHP < 5.4, do...
$result = $xml->xpath("/body/item[#id = '9982a']/value");
$result = $result[0];
see it working: https://eval.in/101766
Yes, use Simple HTML DOM Parser instead of SimpleXML.
It would be as easy as:
$xml->find('item[id="9982b"]',0)->find('value',0)->innertext;
It is possible with DOMXpath::evaluate() to fetch scalar values from a DOM using xpath expressions:
$xml = <<<'XML'
<body>
<item id="9982a">
<value>ab</value>
</item>
<item id="9982b">
<value>abc</value>
</item>
</body>
XML;
$dom = new DOMDocument;
$dom->loadXml($xml);
$xpath = new DOMXpath($dom);
var_dump(
$xpath->evaluate('string(//body/item[#id="9982b"]/value)')
);
Related
I load the following XML data into SimpleXML like this:
<?php
$xmlString = <<<'XML'
<?xml version="1.0"?>
<response>
<item key="0">
<title>AH 2308</title>
<field_a>3.00</field_a>
<field_b>7.00</field_b>
<field_d1>35.00</field_d1>
<field_d2>40.00</field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g>M 45x1,5</field_g>
<field_gewicht>0.13</field_gewicht>
<field_gtin>4055953012781</field_gtin>
<field_l>40.00</field_l>
<field_t></field_t>
<field_abdrueckmutter>KM 9</field_abdrueckmutter>
<field_sicherung>MB 7</field_sicherung>
<field_wellenmutter>KM 7</field_wellenmutter>
</item>
<item key="1">
<title></title>
<field_a></field_a>
<field_b></field_b>
<field_d1></field_d1>
<field_d2></field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g></field_g>
<field_gewicht></field_gewicht>
<field_gtin></field_gtin>
<field_l></field_l>
<field_t></field_t>
<field_abdrueckmutter></field_abdrueckmutter>
<field_sicherung></field_sicherung>
<field_wellenmutter></field_wellenmutter>
</item>
</response>
XML;
$xml = simplexml_load_string($xml);
How can I achieve the following result:
<?xml version="1.0"?>
<response>
<item key="0">
<title>AH 2308</title>
<field_a>3.00</field_a>
<field_b>7.00</field_b>
<field_d1>35.00</field_d1>
<field_d2>40.00</field_d2>
<field_e></field_e>
<field_g2></field_g2>
<field_g>M 45x1,5</field_g>
<field_gewicht>0.13</field_gewicht>
<field_gtin>4055953012781</field_gtin>
<field_l>40.00</field_l>
<field_t></field_t>
<field_abdrueckmutter>KM 9</field_abdrueckmutter>
<field_sicherung>MB 7</field_sicherung>
<field_wellenmutter>KM 7</field_wellenmutter>
</item>
<item key="1"></item>
</response>
To delete all empty elements, I could use the following working code:
foreach ($xml->xpath('/child::*//*[not(*) and not(text()[normalize-space()])]') as $emptyElement) {
unset($emptyElement[0]);
}
But that's not exactly what I want.
Basically, when the <title> element is empty, I want to remove it with all its siblings and keep the parent <item> element.
What's important: I also want to keep empty element, if the <title> is not empty. See <item key="0"> for example. The elements <field_e>, <field_g2> and <field_t>will be left untouched.
Is there an easy xpath query which can achieve that? Hope anyone can help. Thanks in advance!
This xpath query is working:
foreach ($xml->xpath('//title[not(text()[normalize-space()])]/following-sibling::*') as $emptyElement) {
unset($emptyElement[0]);
}
It keeps the <title> element but I can live with that.
DOM is more flexible manipulating nodes:
$document = new DOMDocument();
$document->loadXML($xmlString);
$xpath = new DOMXpath($document);
$expression = '/response/item[not(title[normalize-space()])]';
foreach ($xpath->evaluate($expression) as $emptyItem) {
// replace children with an empty text node
$emptyItem->textContent = '';
}
echo $document->saveXML();
I have to parse the following XML:
<BMECAT version="2005" xmlns="http://www.bmecat.org/bmecat/2005fd">
<T_NEW_CATALOG prev_version="0">
<PRODUCT>
<NAME>Test</NAME>
<USER_DEFINED_EXTENSIONS>
<UDX.VENDOR.ATTRIBUTE lang="de">German</UDX.VENDOR.ATTRIBUTE>
<UDX.VENDOR.ATTRIBUTE lang="en">English</UDX.VENDOR.ATTRIBUTE>
</USER_DEFINED_EXTENSIONS>
</PRODUCT>
</T_NEW_CATALOG>
</BMECAT>
I need to get the value "German" via xpath. Everything I have tried so far didn't work so I need some help. I think the problem is that the tagname includes dots. I have found no way to escape the xpath expression.
The XML you show cannot be parsed because it is malformed (USER_DEFINED_EXTENSIONS is not closed properly). Assuming well-formed input, you could use DOMDocument instead of SimpleXML:
<?php
$xml = <<<'XML'
<BMECAT version="2005" xmlns="http://www.bmecat.org/bmecat/2005fd">
<T_NEW_CATALOG prev_version="0">
<PRODUCT>
<NAME>Test</NAME>
<USER_DEFINED_EXTENSIONS>
<UDX.VENDOR.ATTRIBUTE lang="de">German</UDX.VENDOR.ATTRIBUTE>
<UDX.VENDOR.ATTRIBUTE lang="en">English</UDX.VENDOR.ATTRIBUTE>
</USER_DEFINED_EXTENSIONS>
</PRODUCT>
</T_NEW_CATALOG>
</BMECAT>
XML;
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace("bme",
"http://www.bmecat.org/bmecat/2005fd");
$expression = 'string(
/bme:BMECAT
/bme:T_NEW_CATALOG
/bme:PRODUCT
/bme:USER_DEFINED_EXTENSIONS
/bme:UDX.VENDOR.ATTRIBUTE[#lang = "de"]
)';
var_dump($xpath->evaluate($expression));
And the result will be
German
If you need to use SimpleXML, you really need to show your current PHP code.
I have this xml example
<items>
<item>
<id>k1</id>
<price>456</price>
</item>
<item>
<id>k2</id>
<price>609</price>
</item>
</items>
php code
$xml = simplexml_load_file(address of xml file);
foreach ($xml->item as $item){
if($item->id == 'k2') {
item->price = 800;
}
}
if i want to change the value of second item with simpleXML how can i do that?I know that i can read and save the value to a variable with this $val=item->price; but if i want to change the value with this simple code item->price = 800; it's not working.why happens that?It's a simple thing but still difficult.. Thanks
Use xpath to select the <item> you want and update it:
$xml = simplexml_load_string($x); // assume XML in $x
$result = $xml->xpath("/items/item[id = 'k2']");
$result[0]->price = 800;
echo $xml->asXML();
see it working: https://eval.in/88021
Hello I have xml like this:
<specs><my>base</my><root>none</root></specs>
<books>
<item>
<id>14</id>
<title>How to live</title>
</item>
<item>
...
</item>
</books>
How can I extract value from < my > ? and then < title >?
when I have data such as :<specs><my>base</my><root>none</root></specs> in xml this code works for me. So how should I modify it to work with data such as books as well in xml?
$dom = new DOMDocument();
$dom->loadXml($xml);
$xpath = new DOMXPath($dom);
$entry = $xpath->query("//xml/specs/my");
foreach($entry as $ent){
echo $ent->nodeValue;
}
simply I added this:
$xml="<xml>".$xml."</xml>";
and now this works $xpath->query("//xml/specs/my"); as well as $xpath->query("//xml/books/item");
Consider the following code :
$dom = new DOMDocument();
$dom->loadXML($file);
$xmlPath = new DOMXPath($dom);
$arrNodes = $xmlPath->query('*/item');
foreach($arrNodes as $item){
//missing code
}
The $file is an xml and each item has a title and a description.
How can I display them (title and description)?
$file = "<item>
<title>test_title</title>
<desc>test</desc>
</item>";
I suggest using php's simplexml, with that, you still get xpath functionality, but with easier approach, for example you would access attributes like this:
$name = $item['name'];
Here's an example:
xmlfile.xml:
<?xml version="1.0" encoding="UTF-8"?>
<xml>
<items>
<item title="Hello World" description="Hellowing the world.." />
<item title="Hello People" description="greeting people.." />
</items>
</xml>
do.php:
<?php
$xml_str = file_get_contents('xmlfile.xml');
$xml = new SimpleXMLElement($xml_str);
$items = $xml->xpath('*/item');
foreach($items as $item) {
echo $item['title'], ': ', $item['description'], "\n";
}
If your item looks like this:
<item>
<title>foo</title>
<description>frob</description>
</item>
You could use getElementsByTagName() and nodeValue:
foreach($arrNodes as $item){
print $item->getElementsByTagName('title')->item(0)->nodeValue;
}
Are title and description attributes? E. g. does an item look like this:
<item title="foo" description="frob" />
If so, you could just use getAttribute():
...
foreach($arrNodes as $item){
print $item->getAttribute('title');
}
The right XPath expression should be:
/*/item/title | /*/item/desc
Or
/*/item/*[self::title or self::desc]
This is evaluate to a node set with title and desc element in document order