Find a node with xpath - php

I'd like to parse google geocode api respond, but the structure of the result is not always the same. I need to know the postal code for example, but it is sometimes in the Locality/DependentLocality/PostalCode/PostalCodeNumber node and sometimes in the Locality/PostalCode/PostalCodeNumber node. I don't really know the logic behind this, just want to get the value of the PostalCodeNumber node, no matter where is it exactly. Can I do it with XPath? If so, how?
UPDATE
Tried with //PostalCodeNumber but it returns an empty array. The code snippet is the following:
$xml = new \SimpleXMLElement($response);
var_dump($xml->xpath('//PostalCodeNumber'));
The $response is the content of http://maps.google.com/maps/geo?q=1055+Budapest&output=xml
(copy paste the url instead of clicking on it because of some character problems...)

Try to use this XPath:
Locality//PostalCodeNumber
It will find all descendants PostalCodeNumber of Locality element.

//PostalCode/PostalCodeNumber
Should do the trick. A quick google search yields the following schema snippet, indicating that there may be multiple DependentLocality elements, nested, so you'll want to check for multiple results, and have some idea of whether you want the most specific (most deeply nested) or least specific.
Update:
To guard against namespace issues, explicitly add the namespace to the query:
$xml = new SimpleXMLElement($response);
$xpath->registerXPathNamespace('ns', 'urn:oasis:names:tc:ciq:xsdschema:xAL:2.0');
var_dump($xml->xpath('//ns:PostalCodeNumber'));
Update 2: fixed a couple of typos
Update 3:
<?php
$result = file_get_contents('http://maps.google.com/maps/geo?q=1055+Budapest&output=xml');
$sxe = new SimpleXMLElement($result);
$sxe->registerXPathNamespace('c', 'urn:oasis:names:tc:ciq:xsdschema:xAL:2.0');
$search = $sxe->xpath('//c:PostalCodeNumber');
foreach($search as $code) {
echo $code;
}
?>

Related

Getting an XML value from a named field

Sorry to be asking this, but it's driving me crazy.
I've been using the php SimpleXMLElement as my XML go to parser, and I've looked at many examples, and have given up on this many times. But, now, I just need to have this working. There are many examples on how to get simple fields, but not so many with values in the fields...
I'm trying to get the "track_artist_name" value from this XML as a named variable in php.
<nowplaying-info-list>
<nowplaying-info >
<property name="track_title"><![CDATA[Song Title]]></property>
<property name="track_album_name"><![CDATA[Song Album]]></property>
<property name="track_artist_name"><![CDATA[Song Artist]]></property>
</nowplaying-info>
</nowplaying-info-list>
I've tried using xpath with:
$sxml->xpath("/nowplaying-info-list[0]/nowplaying-info/property[#name='track_artist_name']"));
But, I know it's all mucked up and not working.
I originally tried something like this too, thinking it made sense - but no:
attrs = $sxml->nowplaying_info[0]->property['#name']['track_artist_name'];
echo $attrs . "\n\n";
I know I can get the values with something such as this:
$sxml->nowplaying_info[0]->property[2];
Sometimes there are more lines in the XML results than other times, and so because of this, it is breaks the calculations with the wrong data.
Can someone shed some light on my problem? I'm just trying to the name of the artist to a variable. Many thanks.
*** WORKING UPDATE: **
I was unaware there were different XML interpreter methods, and was using the following XML interpreter version:
// read feed into SimpleXML object
$sxml = new SimpleXMLElement($json);
That didn't work, but have now updated to the following (for that section of code) thanks to the help here.
$sxml_new = simplexml_load_string($json_raw);
if ( $sxml_new->xpath("/nowplaying-info-list/nowplaying-info/property[#name='track_artist_name']") != null )
{
$results = $sxml_new->xpath("/nowplaying-info-list/nowplaying-info/property[#name='track_artist_name']");
//print_r($results);
$artist = (string) $results[0];
// var_dump($artist);
echo "Artist: " . $artist . "\n";
}
Your xpath expression is pretty much right, but you don't need to specify an index for the <nowplaying-info-list> element - it'll deal with that itself. If you were to supply an index, it would need to start at 1, not 0.
Try
$results = $sxml->xpath("/nowplaying-info-list/nowplaying-info/property[#name='track_artist_name']");
echo (string) $results[0];
Song Artist
See https://3v4l.org/eH4Dr
Your second approach:
$sxml->nowplaying_info[0]->property['#name']['track_artist_name'];
Would be trying to access the attribute named #name of the first property element, rather than treating it as an xpath-style # expression. To do this without using xpath, you'd need to loop over each of the <property> elements, and test their name attibrute.
Just in case if the node you are looking for is deeply residing some where, you could just add a double slash at the start.
$results = $sxml->xpath("//nowplaying-info-list/nowplaying-info/property[#name='track_artist_name']");
Also in case if you have multiple <nowplaying-info> elements. You could make of use of the index for that. (note the [1] index)
$results = $sxml->xpath("//nowplaying-info-list/nowplaying-info[1]/property[#name='track_artist_name']");

How to read child of interleaved XML in PHP

We need to update a somewhat old API a customer is using. We're getting the data with simplexml_load_file. The new structure is a bit more complex and I could not find a way to retrieve the new data.
The new structure looks like this:
Before we used $ratingPrice = $xml->hotel->ratingPrice; to get a value.
Now, I need to retrieve $xml->business->subcategoryRating->subcategoryRating->averageRating. I'm now stuck with that.
How am I able to get the average rating of wifi, or location and have them outputted in single variables?
If the order of your information is always the same (eg. Wi-Fi, Location, Apartment, Cleanliness) then you can do
$xml->business->subcategoryRating->subcategoryRating[x]->averageRating
so the x is the index of your xml list. Then
...subcategoryRating[0]->averageRating
corresponds to Wi-Fi and
...subcategoryRating[1]->averageRating
corresponds to Location and so forth.
You can extract the various ratings into an array and then use the relevant index to process the data your after. This uses the id attribute of the (for example) <category id="location"> element to use as the index...
$ratings = [];
foreach ( $xml->business->subcategoryRatings->subcategoryRating as $rating ) {
$ratings[(string)$rating->category['id']] = (string)$rating->averageRating;
}
echo $ratings["location"].PHP_EOL;
This last line will need to be updated to access the particular element your after.
As an alternative you could create an xpath expression and use xpath.
That would give you array of SimpleXMLElement objects.
$xml = simplexml_load_string($data);
$expression = '//business/subcategoryRatings/subcategoryRating[category[#id="wifi" or #id="location"]]';
foreach($xml->xpath($expression) as $item) {
$averageRating = (string)$item->averageRating;
}

Parsing deep XML with PHP SimpleXML and XPath

PHP noob here. I seem to be misunderstanding how to get the value of an XML node using XPath, and I haven't been able to find a StackOverflow answer that quite address what I'm doing wrong.
So, using RPG Geek's API, I'm trying to pull some information about the game Dread. (Here's a link to the URI.)
$rpggeekXML = simplexml_load_file('https://www.rpggeek.com/xmlapi/boardgame/166952?&stats=1');
$rating = $rpggeekXML->xpath('ratings/average');
$usersrated = $rpggeekXML->xpath('ratings/usersrated');
I know I'm successfully pulling in the rpggeek XML because if I do var_dump($rpggeekXML);, I can see all of the information I'm expecting. However, if I do var_dump($rating); or var_dump($usersrated);, it returns array(0) { }. So it seems I must be screwing up the XPath lines, but I can't figure out how. What am I doing wrong?
Use full path to find desired node:
$rating = $rpggeekXML->xpath( 'boardgame/statistics/ratings/average' );
echo $rating[0];
Collect all "average" nodes in document:
$rating = $rpggeekXML->xpath( '//average' );
echo $rating[0];
I think you xpath syntax is wrong. You can try this
$rpggeekXML = simplexml_load_file('https://www.rpggeek.com/xmlapi/boardgame/166952?&stats=1');
$rating = $rpggeekXML->xpath('//ratings/average');
$usersrated = $rpggeekXML->xpath('//ratings/usersrated');

Using PHP SimpleXML to parse an oBix XML feed?

I am rather new to development, but a long time sys-admin. I am trying to retrieve a specific value from the following XML feed. (Its oBix).
http://80.68.58.47:900/obix/config/Drivers/NiagaraNetwork/OSS_Tridium_Demo/points/kW_Sys/
I am trying to return the "Out" value within the 'Real' element (If element is the right name for it). The value is a number next to val=.
I have spent a fair few hours trying to work out how to isolate the 'val' attribute and return the number but I can't seem to do it. I can isolate the 'real' element but can't go any further in to get the actual number value.
Could someone show me how this is done using PHP SimpleXML so I can try to get my head round it?
This is my code so far:
<?php
$url = "http://80.68.58.47:900/obix/config/Drivers/NiagaraNetwork/OSS_Tridium_Demo/points/kW_Sys/";
$xml = simplexml_load_file($url);
$elementselection = $xml->real[0];
$outputvalue = $elementselection;
print_r ($outputvalue);
?>
Many Thanks!
Tom
If you just want the value from the first 'real' element you can use the following:
$url = "http://80.68.58.47:900/obix/config/Drivers/NiagaraNetwork/OSS_Tridium_Demo/points/kW_Sys/";
$xml = simplexml_load_file($url);
$value = (string) $xml->real[0]['val'];
var_dump($value);

PHP: How can I access this XML entity when its name contains a reserved word?

I'm trying to parse this feed: http://musicbrainz.org/ws/1/artist/c0b2500e-0cef-4130-869d-732b23ed9df5?type=xml&inc=url-rels
I want to grab the URLs inside the 'relation-list' tag.
I've tried fetching the URL with PHP using simplexml_load_file(), but I can't access it using $feed->artist->relation-list as PHP interprets "list" as the list() function.
I have a feeling I'm going about this wrong (not much XML experience), and even if I was able to get hold of the elements I want, I don't know how to extract their attributes (I just want the type and target fields).
Can anyone gently nudge me in the right direction?
Thanks.
Matt
Have a look at the examples on the php.net page, they actually tell you how to solve this:
// $feed->artist->relation-list
$feed->artist->{'relation-list'}
To get an attribute of a node, just use the attribute name as array index on the node:
foreach( $feed->artist->{'relation-list'}->relation as $relation ) {
$target = (string)$relation['target'];
$type = (string)$relation['type'];
// Do something with it
}
(Untested)

Categories