Filtering certain elements of an XML

4

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

link

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 get these values individually, probably the best way is to store them in an array and then filter, something like that.

Does anyone have a good solution? To get the data via XML I'm using the solution I got on another question .

    
asked by anonymous 15.06.2014 / 04:08

1 answer

4

You can use 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 also be filtered with predicates, which operate in the context of the step and make the selection with Boolean expressions.

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

/weatherdata/location/name
The latitude is inside an attribute , which can be selected with an additional step inside a special axis %):

/weatherdata/location/location/@latitude
You can also use descendant axes , which selects multiple elements without taking intermediate contexts into account:

//location

returns a set containing two elements: @ that is the child of location ( weatherdata ), and the other /weatherdata/location that is net of location and child of first weatherdata ( location ).

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

(//location)[2]

filters the set so that only the second element is selected. The parentheses ensure that the position is absolute relative to all localized elements (and not to the position of /weatherdata/location/location within its context, which is default )

In the example you posted, you can retrieve all location objects with a very simple expression:

//time

This expression returns a set of nodes, which you can manipulate in a for-each and extract what you want from them: attribute values, child elements, and so on. You can also perform contextual XPath expressions . Once in the context of the time element, you can use expressions like time (which do not start with precipitation/@value ) to get the value of the / attribute of the value element object% with% selected.

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

<?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";

?>

Elements were selected with XPath, but the attributes used the max function of the XML DOM. You could have done everything with XPath too, for example:

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

Elements are always returned as a set , even if unary, so they need min to extract the first. Attributes do not need to. When the expression returns a node that has a value (such as a text node), you can assign that value to a string using getAttribute() .

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

    
15.06.2014 / 05:44