Setting Parent Node Variable in SimpleXML and XPath - php

I am working with PHP and SimpleXML/XPath, and I'm just wondering how to set a certain parent (with a certain attribute value) equal to a variable, which I could use in a 'foreach'?
I'm currently getting this error:
Notice: Array to string conversion
and this output
Array
Thanks for any leads.
Here is the php code:
<?php
$url = "test_b.xml";
$xml = simplexml_load_file($url);
$xml_report_abbrev_b = $xml->xpath('//poster[#name="U-Verify"]')[0];
if($xml_report_abbrev_b){
foreach($xml_report_abbrev_b as $node_a) {
echo '<h1>'.$node_a->xpath('/full_image/#url').'</h1>';
}
} else {
echo 'XPath query failed';
}
?>
Here's the xml:
<data>
<poster name="U-Verify" id="uverify">
<full_image url="u-verify.jpg"/>
<full_other url=""/>
</poster>
<poster name="Minimum" id="min">
<full_image url="min.jpg"/>
<full_other url="spa_min.jpg"/>
</poster>
</data>

Using SimpleXML's element access and attribute access directly instead of using the XPath query will make the code simpler and perform better.
Your code could be reduced to...
$xml_report_abbrev_b = $xml->xpath('//poster[#name="U-Verify"]');
if($xml_report_abbrev_b){
echo '<h1>'.$xml_report_abbrev_b[0]->full_image['url'].'</h1>';
} else {
echo 'XPath query failed';
}
Note the way the echo line says - with the <poster> element you found from the XPath expression, use the <full_image> element and fetch the url attribute.
I also moved the [0] into the if because if the XPath didn't find a value, this produced an error as there isn't any data to get a value from.
This outputs...
<h1>u-verify.jpg</h1>

Related

Query XML File using PHP for Values

I am currently working on a project that requires me to query an XML file like php to return a value that matches the request. Take a look at the XML:
<ENVELOPE>
<MASTER>
<STKDETNAME>004-011</STKDETNAME>
<STKPNO>PTN771</STKPNO>
<STKPRICE></STKPRICE>
<STKOPBAL>500</STKOPBAL>
</MASTER>
<MASTER>
<STKDETNAME>004-012</STKDETNAME>
<STKPNO>PTN772</STKPNO>
<STKPRICE></STKPRICE>
<STKOPBAL>500</STKOPBAL>
</MASTER>
<MASTER>
<STKDETNAME>004-013</STKDETNAME>
<STKPNO>PTN773</STKPNO>
<STKPRICE></STKPRICE>
<STKOPBAL>1000</STKOPBAL>
</MASTER>
<MASTER>
<STKDETNAME>004-014</STKDETNAME>
<STKPNO>PTN774</STKPNO>
<STKPRICE></STKPRICE>
<STKOPBAL>1000</STKOPBAL>
</MASTER>
<MASTER>
<STKDETNAME>004-015</STKDETNAME>
<STKPNO>PTN775</STKPNO>
<STKPRICE>400</STKPRICE>
<STKOPBAL>1000</STKOPBAL>
</MASTER>
</ENVELOPE>
Now, I want to get the STKPRICE AND STKOPBAL for a SKTPNO= PTN773. This is what i have seen so far, but i don't know how to get the two values. I am new to XML.
$file = 'stocksum.xml';//same file as above
$xmlfile = simplexml_load_file($file);
$partno = PTN775;
$fnd = $xmlfile->xpath('/ENVELOPE/MASTER/STKPNO[.="$partno"]');
There are a couple of issues with the code which are just syntax problems, these are the partno needing quotes and when building the XPath expression, you use single quotes so it doesn't insert the actual part number.
BUT to get to your actual problem, if you change your XPath to the one used here, this will find the <MASTER> element whose <STKPNO> is the one your after. So then you can refer to the elements withing the <MASTER> element using standard SimpleXML object notation...
$partno = 'PTN775';
$fnd = $xmlfile->xpath('/ENVELOPE/MASTER[STKPNO="'.$partno.'"]');
echo $fnd[0]->STKPRICE.PHP_EOL;
Note that as xpath() returns a list of matches, I use $fnd[0] to get the first one.
Code which also has a check to see if the part actually exists...
$xmlfile = simplexml_load_file($file);
$partno = 'PTN7751';
$fnd = $xmlfile->xpath('/ENVELOPE/MASTER[STKPNO="'.$partno.'"]');
if ( count($fnd) == 0 ) {
echo "Not found";
}
else {
echo $fnd[0]->STKPRICE.PHP_EOL;
}

PHP SimpleXML Get One Node with Children via Attribute

Have not found a direct solution and would prefer to do this with SimpleXML ... want to get a single node and children via an attribute (id) from a sent url
Address is clicked ...
www.website.com/index.php#929495820
XML
<archive>
<unit id="925535820">
<data>Blah</data>
<link>url</link>
</unit>
<unit id="929495820">
<data>Blah</data>
<link>url</link>
</unit>
<unit id="929495821">
<data>Blah</data>
<link>url</link>
</unit> ... and many more ...
</archive>
I have php that turns the entire XML in to an array and then splice to limit what is shown (see below) but what I want is the url to grab the single value from the array. Can it be done and if so, Simple or Dom? Please say Simple. I have the worst luck working Dom.
$xml_get = 'filename.xml'
$xml_array = json_decode(json_encode($xml_get), 1);
$master = $xml_array['unit'];
// Show Last 200
$master = array_slice($master, 1, 200);
foreach(array_reverse($master) as $arc)
{
$last_id = $arc['#attributes']['id'];
$last_data = $arc['data'];
$last_link = $arc['link'];
// Do stuff with values...
}
If you want to use SimpleXML you could load the file with simplexml_load_file and check the attributes for your id.
Then use for example a foreach or an xpath expression:
$elm = simplexml_load_file("filename.xml");
foreach ($elm->unit as $item) {
if ((string)$item->attributes()->id === "929495820") {
echo $item->data;
echo "<br>";
echo $item->link;
}
}
$result = $elm->xpath("/archive/unit[#id='929495820']");
echo $result[0]->data;
echo "<br>";
echo $result[0]->link;
Demo

PHP - Unable to parse attribute using SimpleXML

Given the following xml:
<data xmlns:ns2="...">
<versions>
<ns2:version type="HW">E</ns2:version>
<ns2:version type="FW">3160</ns2:version>
<ns2:version type="SW">3.4.1 (777)</ns2:version>
</versions>
...
</data>
I am trying to parse the third attribute ~ns2:version type="SW" but when running the following code I get nothing..
$s = simplexml_load_file('data.xml');
echo $s->versions[2]->{'ns2:version'};
Running this gives the following output:
$s = simplexml_load_file('data.xml');
var_dump($s->versions);
How can I properly get that attribute?
You've got some quite annoying XML to work with there, at least as far as SimpleXML is concerned.
Your version elements are in the ns2 namespace, so in order to loop over them, you need to do something like this:
$s = simplexml_load_string($xml);
foreach ($s->versions[0]->children('ns2', true)->version as $child) {
...
}
The children() method returns all children of the current tag, but only in the default namespace. If you want to access elements in other namespaces, you can pass the local alias and the second argument true.
The more complicated part is that the type attributes is not considered to be part of this same namespace. This means you can't use the standard $element['attribute'] form to access it, since your element and attribute are in different namespaces.
Fortunately, SimpleXML's attributes() method works in the same way as children(), and so to access the attributes in the global namespace, you can pass it an empty string:
$element->attributes('')->type
In full, this is:
$s = simplexml_load_string($xml);
foreach ($s->versions[0]->children('ns2', true)->version as $child) {
echo (string) $child->attributes()->type, PHP_EOL;
}
This will get you the output
HW
FW
SW
To get the third attribute.
$s = simplexml_load_file('data.xml');
$sxe = new SimpleXMLElement($s);
foreach ($sxe as $out_ns) {
$ns = $out_ns->getNamespaces(true);
$child = $out_ns->children($ns['ns2']);
}
echo $child[2];
Out put:
3.4.1 (777)

Parsing complex xml with simplexml

I have got this xml structure below. For every 'locatie' (in every 'land') I need the 'id' value and it's 'sneeuwkwaliteit'.
My effort so far, does not return the value of 'sneeuwkwaliteit':
$sneeuw = simplexml_load_file('ski.xml');
echo $sneeuw->land[0]->locaties[0]->sneeuw->{'ski'}->sneeuwkwaliteit;
<sneeuw>
<aanmaak_tijd>09-01-2016 07:48</aanmaak_tijd>
<landen>
<land id="Andorra">
<locaties>
<locatie id="Arinsal/Pal">
<ski>
<datum_tijd>09-01-2016</datum_tijd>
<sneeuwhoogte_dal>40</sneeuwhoogte_dal>
<sneeuwhoogte_berg>70</sneeuwhoogte_berg>
<sneeuwkwaliteit>De aanwezige sneeuw is poedersneeuw.</sneeuwkwaliteit>
<datum_laatste_sneeuwval>07-01-2016</datum_laatste_sneeuwval>
<hoeveelheid_laatste_sneeuwval>20</hoeveelheid_laatste_sneeuwval>
<totaal_aantal_liften>25</totaal_aantal_liften>
<aantal_liften_geopend>25</aantal_liften_geopend>
</ski>
</locatie>
</locaties>
</land>
</landen>
</sneeuw>
Just carefully follow the path from the root of your XML to the target element :
$xml = <<<XML
<sneeuw>
<aanmaak_tijd>09-01-2016 07:48</aanmaak_tijd>
<landen>
<land id="Andorra">
<locaties>
<locatie id="Arinsal/Pal">
<ski>
<datum_tijd>09-01-2016</datum_tijd>
<sneeuwhoogte_dal>40</sneeuwhoogte_dal>
<sneeuwhoogte_berg>70</sneeuwhoogte_berg>
<sneeuwkwaliteit>De aanwezige sneeuw is poedersneeuw.</sneeuwkwaliteit>
<datum_laatste_sneeuwval>07-01-2016</datum_laatste_sneeuwval>
<hoeveelheid_laatste_sneeuwval>20</hoeveelheid_laatste_sneeuwval>
<totaal_aantal_liften>25</totaal_aantal_liften>
<aantal_liften_geopend>25</aantal_liften_geopend>
</ski>
</locatie>
</locaties>
</land>
</landen>
</sneeuw>
XML;
$sneeuw = simplexml_load_string($xml);
echo $sneeuw->landen[0]->land[0]->locaties[0]->locatie[0]->ski[0]->sneeuwkwaliteit;
eval.in demo
output :
De aanwezige sneeuw is poedersneeuw.
For more complex query against XML, look into XPath, which has it's own specification. Then you can execute XPath expression using SimpleXMLElement::xpath() function.
UPDATE :
You can use XPath, as mentioned above, to iterate through all sneeuwkwaliteit elements located in the same path :
....
$result = $sneeuw->xpath('/sneeuw/landen/land/locaties/locatie/ski/sneeuwkwaliteit');
foreach($result as $r){
echo $r ."<br>";
}

xml xpath does not return node value

I have a test file where I'm trying to parse an xml string using SimpleXML's xpath method.
When I try to access a nodes values directly using xpath I get empty output, but when I use xpath to grab the elements and then loop through them it works fine.
When I look at the documentation, it seems like my syntax should work. Is there something I'm missing?
<?php
$xmlstring = '<?xml version="1.0" encoding="iso-8859-1"?>
<users>
<user>
<firstname>Sheila</firstname>
<surname>Green</surname>
<address>2 Good St</address>
<city>Campbelltown</city>
<country>Australia</country>
<contact>
<phone type="mobile">1234 1234</phone>
<url>http://example.com</url>
<email>pamela#example.com</email>
</contact>
</user>
<user>
<firstname>Bruce</firstname>
<surname>Smith</surname>
<address>1 Yakka St</address>
<city>Meekatharra</city>
<country>Australia</country>
<contact>
<phone type="landline">4444 4444</phone>
<url>http://yakka.example.com</url>
<email>bruce#yakka.example.com</email>
</contact>
</user>
</users>';
// Start parsing
if(!$xml = simplexml_load_string($xmlstring)){
echo "Error loading string ";
} else {
echo "<pre>";
// Print all firstname values directly from xpath
// This outputs the elements, but the values are blank
print_r($xml->xpath("/users/user/firstname"));
// Set a variable with all of the user elements and then loop through and print firstname values
// This DOES output the values
$users = $xml->xpath("/users/user");
foreach($users as $user){
echo $user->firstname;
}
// Find all firstname values by tag
// This does not output the values
print_r($xml->xpath("//firstname"));
echo "</pre>";
}
As per the manual http://uk1.php.net/manual/en/simplexmlelement.xpath.php
The xpath method searches the SimpleXML node for children matching the XPath path.
In your first and third examples, you are being returned objects containing an array of the node's value, rather than the node itself. So you aren't going to be able to do e.g.
$results = $xml->xpath("//firstname");
foreach ($results as $result) {
echo $result->firstname;
}
Instead you can just echo out the value directly. Well, almost directly (they are still simplexml objects after all)...
$results = $xml->xpath("//firstname");
foreach ($results as $result) {
echo $result->__toString();
}

Categories