?
Solved

Help navigating an XML file with multiple namespaces using simplexml

Posted on 2011-05-08
4
Medium Priority
?
453 Views
Last Modified: 2012-05-11
I am working on a program to collect meteorological data from an XML file. In particular I would like to navigate through a file such as the one referenced below and pull out wind statistics for specific locations.

Locations are identified in the metadata of the Observation tag in the element with name="station_name". The wind data is contained in Observation -> elements.

The use of multiple namespaces seems to be stymying my limited knowledge of how to use simplexml to parse an xml file.

An xml file I am trying to parse is: http://dd.weatheroffice.gc.ca/observations/xml/MB/hourly/hourly_mb_2011050723_e.xml

I have cut this down for testing to one observation (per below):
<?xml version="1.0" encoding="UTF-8"?>
    <om:ObservationCollection xmlns:om="http://www.opengis.net/om/1.0" xmlns="http://dms.ec.gc.ca/schema/point-observation/2.0" xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<om:member>
    <om:Observation>
        <om:metadata>
            <set><general><author name="MSC-DMS-PG-WXO-HOURLY" version="1.5"/><dataset name="msc/observation/atmospheric/surface_weather/wxo-2.0-ascii"/><phase name="product-hourly_en-xml-2.0"/><id xlink:href="/data/msc/observation/atmospheric/surface_weather/wxo-2.0-ascii/product-hourly_en-xml-2.0/201105072356/mb"/><parent xlink:href="/data/msc/observation/atmospheric/surface_weather/cs-1.0-binary/decoded-xml-2.0/201105072300/cpgh"/></general>
            <identification-elements>
                <element name="station_name" uom="unitless" value="Gimli"/>
                <element name="latitude" uom="degree" value="50.63"/>
                <element name="longitude" uom="degree" value="-97.05"/>
                <element name="transport_canada_id" uom="unitless" value="PGH"/>
                <element name="observation_date_utc" uom="unitless" value="2011-05-07T23:00:00.000Z"/>
                <element name="observation_date_local_time" uom="unitless" value="2011-05-07T18:00:00.000 CDT"/>
                <element name="climate_station_number" uom="unitless" value="5031042"/>
                <element name="wmo_station_number" uom="unitless" value="71748"/>
            </identification-elements>
            </set>
        </om:metadata>
        <om:samplingTime><gml:TimeInstant><gml:timePosition>2011-05-07T23:00:00.000Z</gml:timePosition></gml:TimeInstant></om:samplingTime>
        <om:resultTime><gml:TimeInstant><gml:timePosition>2011-05-07T23:56:09.099Z</gml:timePosition></gml:TimeInstant></om:resultTime>
        <om:procedure xlink:href=""/>
        <om:observedProperty gml:remoteSchema="/schema/point-observation/2.0.xsd"/>
        <om:featureOfInterest>
            <gml:FeatureCollection>
                <gml:location><gml:Point><gml:pos>50.63333333333333 -97.05</gml:pos></gml:Point></gml:location>
            </gml:FeatureCollection>
        </om:featureOfInterest>
        <om:result>
        <orig-header/>
        <elements>
            <element name="present_weather" uom="code" value=""/>
            <element name="mean_sea_level" uom="kPa" value="100.89"/>
            <element name="tendency_amount" uom="kPa" value="0.07"/>
            <element name="tendency_characteristic" uom="code" value="rising"/>
            <element name="horizontal_visibility" uom="km" value=""/>
            <element name="air_temperature" uom="Celsius" value="11.4"/>
            <element name="dew_point" uom="Celsius" value="8.2"/>
            <element name="relative_humidity" uom="percent" value="81.0"/>
            <element name="wind_speed" uom="km/h" value="24.8"/>
            <element name="wind_direction" uom="code" value="SW"/>
            <element name="wind_gust_speed" uom="km/h" value="36.4"/>
            <element name="total_cloud_cover" uom="code" value=""/>
            <element name="wind_chill" uom="unitless" value=""/>
            <element name="humidex" uom="unitless" value=""/>
        </elements>
        </om:result>
    </om:Observation>
</om:member>
</om:ObservationCollection>

Open in new window


This is what I have so far, and it is getting me nowhere...

<?php
	$xml = simplexml_load_file("http://dd.weatheroffice.gc.ca/observations/xml/MB/hourly/hourly_mb_2011050723_e.xml");
	$xml->registerXPathNamespace("om", "http://www.opengis.net/om/1.0");
	$elements = $xml->xpath("//om:Observation");
	
	$location = $xml->xpath("/om:ObservationCollection/om:member/om:Observation/om:metadata");

	$test[0] = $location->xpath("/set");
	
	foreach($test as $k=>$v){
		echo "<br/>$k=$v";
	}
?>

Open in new window

0
Comment
Question by:dirknibleck
4 Comments
 
LVL 9

Expert Comment

by:Erdinç Güngör Çorbacı
ID: 35716959
You may try parsing XML with
http://php.net/manual/en/book.xml.php

lot to read but you may find useful snipplets to make it work quickly from google...

Good luck
0
 
LVL 17

Accepted Solution

by:
Chris Harte earned 1000 total points
ID: 35720274
In the xml your required values are stored as attributes.

I have loaded the file into a string, removing the colon (they were causing me problems). That string is then converted in to an xml object.

The foreach does not like hyphens so I have bracketed them.
The attributes are parsed with the attributes() function.
Each required member is called <element> with attributes called name and value, but if you tunnel down to the right member, this should not be a problem.

Wind speeds are all empty at the moment, but I think this code works.

function get_file_data($url)
{
    $data = file_get_contents($url);
    $data = str_replace('om:', 'om_', $data);

    return $data;
}

$name = "name";
$sta_name = "value";
$wind_speed = "value";


$url = "http://dd.weatheroffice.gc.ca/observations/xml/MB/hourly/hourly_mb_2011050723_e.xml";

$file = get_file_data($url);

$xml = simplexml_load_string($file);

foreach ($xml->om_member as $wind)
{
    foreach ($wind->om_Observation as $obser)
    {
        if ($obser->om_metadata->set->{'identification-elements'}->element->attributes()->$name == 'station_name')
        {
            echo "<br />station name : ".$obser->om_metadata->set->{'identification-elements'}->element->attributes()->$sta_name ." <br />";
        }

        if ($obser->om_result->elements->element->attributes()->$name == 'wind_speed')
        {
            echo "<br />wind speed :".$obser->om_result->elements->element->attributes()->$wind_speed."<br />";
        }

    }
}

Open in new window

0
 
LVL 111

Assisted Solution

by:Ray Paseur
Ray Paseur earned 1000 total points
ID: 35721486
http://www.laprbass.com/RAY_temp_dirknibleck.php
Outputs:
AT Gimli THE WIND SPEED IS 24.8km/h
<?php // RAY_temp_dirknibleck.php
error_reporting(E_ALL);
echo "<pre>";



$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<om:ObservationCollection xmlns:om="http://www.opengis.net/om/1.0" xmlns="http://dms.ec.gc.ca/schema/point-observation/2.0" xmlns:gml="http://www.opengis.net/gml" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<om:member>
    <om:Observation>
        <om:metadata>
            <set><general><author name="MSC-DMS-PG-WXO-HOURLY" version="1.5"/><dataset name="msc/observation/atmospheric/surface_weather/wxo-2.0-ascii"/><phase name="product-hourly_en-xml-2.0"/><id xlink:href="/data/msc/observation/atmospheric/surface_weather/wxo-2.0-ascii/product-hourly_en-xml-2.0/201105072356/mb"/><parent xlink:href="/data/msc/observation/atmospheric/surface_weather/cs-1.0-binary/decoded-xml-2.0/201105072300/cpgh"/></general>
            <identification-elements>
                <element name="station_name" uom="unitless" value="Gimli"/>
                <element name="latitude" uom="degree" value="50.63"/>
                <element name="longitude" uom="degree" value="-97.05"/>
                <element name="transport_canada_id" uom="unitless" value="PGH"/>
                <element name="observation_date_utc" uom="unitless" value="2011-05-07T23:00:00.000Z"/>
                <element name="observation_date_local_time" uom="unitless" value="2011-05-07T18:00:00.000 CDT"/>
                <element name="climate_station_number" uom="unitless" value="5031042"/>
                <element name="wmo_station_number" uom="unitless" value="71748"/>
            </identification-elements>
            </set>
        </om:metadata>
        <om:samplingTime><gml:TimeInstant><gml:timePosition>2011-05-07T23:00:00.000Z</gml:timePosition></gml:TimeInstant></om:samplingTime>
        <om:resultTime><gml:TimeInstant><gml:timePosition>2011-05-07T23:56:09.099Z</gml:timePosition></gml:TimeInstant></om:resultTime>
        <om:procedure xlink:href=""/>
        <om:observedProperty gml:remoteSchema="/schema/point-observation/2.0.xsd"/>
        <om:featureOfInterest>
            <gml:FeatureCollection>
                <gml:location><gml:Point><gml:pos>50.63333333333333 -97.05</gml:pos></gml:Point></gml:location>
            </gml:FeatureCollection>
        </om:featureOfInterest>
        <om:result>
        <orig-header/>
        <elements>
            <element name="present_weather" uom="code" value=""/>
            <element name="mean_sea_level" uom="kPa" value="100.89"/>
            <element name="tendency_amount" uom="kPa" value="0.07"/>
            <element name="tendency_characteristic" uom="code" value="rising"/>
            <element name="horizontal_visibility" uom="km" value=""/>
            <element name="air_temperature" uom="Celsius" value="11.4"/>
            <element name="dew_point" uom="Celsius" value="8.2"/>
            <element name="relative_humidity" uom="percent" value="81.0"/>
            <element name="wind_speed" uom="km/h" value="24.8"/>
            <element name="wind_direction" uom="code" value="SW"/>
            <element name="wind_gust_speed" uom="km/h" value="36.4"/>
            <element name="total_cloud_cover" uom="code" value=""/>
            <element name="wind_chill" uom="unitless" value=""/>
            <element name="humidex" uom="unitless" value=""/>
        </elements>
        </om:result>
    </om:Observation>
</om:member>
</om:ObservationCollection>
XML;

// MUNG THE XML TO REMOVE THE NAMESPACE COLONS
$xml = str_replace('<om:',   '<om_',   $xml);
$xml = str_replace('</om:',  '</om_',  $xml);
$xml = str_replace('<gml:',  '<gml_',  $xml);
$xml = str_replace('</gml:', '</gml_', $xml);

// MAKE AN OBJECT
$obj = SimpleXML_Load_String($xml);

// ACTIVATE THIS TO SEE THE OBJECT
// var_dump($obj);

foreach ($obj->om_member->om_Observation as $o)
{

    // GET STATION NAME FROM THE ELEMENTS
    $ide = $o->om_metadata->set->{"identification-elements"};
    $nom = 'UNKNOWN';
    foreach ($ide->element as $e)
    {
        if ($e["name"] == "station_name") $nom = $e["value"];
    }

    // GET THE WIND SPEED
    $res = $o->om_result->elements;
    $wnd = 'UNKNOWN';
    foreach ($res->element as $e)
    {
        if ($e["name"] == "wind_speed") $wnd = $e["value"] . $e["uom"];
    }

    // SHOW THE WORK PRODUCT
    echo "AT $nom THE WIND SPEED IS $wnd";
}

Open in new window

0
 
LVL 15

Author Closing Comment

by:dirknibleck
ID: 35725812
Thanks guys. You both had the same idea and made me realize I was complicating it...
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The Confluence of Individual Knowledge and the Collective Intelligence At this writing (summer 2013) the term API (http://dictionary.reference.com/browse/API?s=t) has made its way into the popular lexicon of the English language.  A few years ago, …
Password hashing is better than message digests or encryption, and you should be using it instead of message digests or encryption.  Find out why and how in this article, which supplements the original article on PHP Client Registration, Login, Logo…
Learn how to match and substitute tagged data using PHP regular expressions. Demonstrated on Windows 7, but also applies to other operating systems. Demonstrated technique applies to PHP (all versions) and Firefox, but very similar techniques will w…
The viewer will learn how to look for a specific file type in a local or remote server directory using PHP.
Suggested Courses
Course of the Month15 days, 12 hours left to enroll

850 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question