Filter certain elements of an XML

Asked

Viewed 640 times

4

I have the following weather forecast report generated by a third-party API:

http://api.openweathermap.org/data/2.5/forecast?q=qTubar%C3%A3o,br&mode=xml

If you repair the structure well we have the forecast set for every 3h.

<time from="2014-06-15T00:00:00" to="2014-06-15T03:00:00">
<time from="2014-06-15T03:00:00" to="2014-06-15T06:00:00">
<time from="2014-06-15T06:00:00" to="2014-06-15T09:00:00">

I would like to take these values individually, probably the best way is to store them in an array and then filter, something like.

Does anyone have a good solution? To get the data via XML I am using the solution I obtained in another question.

1 answer

4


You can use it Xpath. In Xpath you can express a path within an XML as a sequence of steps. Each step creates a context for the next step. The last step contains the elements you want to select. Contexts and selection can still be filtered with predicates, which operate in the context of the step and make the selection with boolean expressions.

In the example XML you presented, you can select the city with:

/weatherdata/location/name

To latitude is inside a attribute, which can be selected with an additional step within a axle special (with prefix @):

/weatherdata/location/location/@latitude

You can also use descending axes, which select several elements without taking into account intermediate contexts:

//location

returns a set containing two elements: the location who is the son of weatherdata (/weatherdata/location), and the other location who is the grandson of weatherdata and son of the first location (/weatherdata/location/location).

A predicate can be used to filter these results. The expression:

(//location)[2]

filters the set to select only the second element. The parentheses ensure that the position is absolute for all elements located (and not for the position of location within its context, which is default)

In the example you posted, you can recover all the objects time with a very simple expression:

//time

This expression returns a set of nodes, which you can manipulate into a for-each and extract whatever you want from them: attribute values, child elements, etc. You can also perform Xpath expressions contextual. Once within of the context of the element time, you can use expressions like precipitation/@value (that do not begin with /) to obtain the attribute value value of the element precipitation of the object time selected.

The following example reads the document in the URL you passed, selects all elements time, and assembles an HTML table containing the attributes to and from, in addition to two attributes of the child element temperature: max and min.

<?php

$doc = new DOMDocument();
$doc->load( "http://api.openweathermap.org/data/2.5/forecast?q=Tubar%C3%A3o,br&mode=xml" ); 
$xpath = new DOMXpath($doc);

echo '<table border="1">'."\n";
echo '<tr><th>From</th><th>To</th><th>Temp min</th><th>Temp max</th></tr>'."\n";
foreach ($xpath->evaluate("//time") as $time) {
    echo '<tr>'."\n";
    echo '<td>'.$time->getAttribute('from').'</td>'."\n";
    echo '<td>'.$time->getAttribute('to').'</td>'."\n";
    $temp = $xpath->evaluate('temperature', $time)->item(0);
    echo '<td>'.$temp->getAttribute('min').' '.$temp->getAttribute('unit').'</td>'."\n";
    echo '<td>'.$temp->getAttribute('max').' '.$temp->getAttribute('unit').'</td>'."\n";
    echo '<tr>'."\n";
}
echo '</table>'."\n";

?>

The elements were selected with Xpath, but the attributes used the function getAttribute() XML DOM. You could have done everything with Xpath as well, for example:

$tempMax = $xpath->evaluate('temperature/@max', $time);

The elements are always returned as a set, even if unitary, why they need the ->item(0) to extract the first. Attributes do not need. When the expression returns a node that has a value (like a text node), you can assign this value to a string using ->nodeValue.

The above example should serve as a starting point for what you want to do. See it working in real time on this Fiddle PHP

Browser other questions tagged

You are not signed in. Login or sign up in order to post.