• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 492
  • Last Modified:

Help navigating an XML file with multiple namespaces using simplexml

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
dirknibleck
Asked:
dirknibleck
2 Solutions
 
Erdinç Güngör ÇorbacıPHP Development Team LeaderCommented:
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
 
Chris HarteThaumaturgeCommented:
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
 
Ray PaseurCommented:
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
 
dirknibleckAuthor Commented:
Thanks guys. You both had the same idea and made me realize I was complicating it...
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now