Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using XPath to select through namespaces

Tags:

php

xpath

I've been trying to use XPath in PHP to access an Atom feed from the National Health Service API.

The data looks like this:

<feed xmlns:s="http://syndication.nhschoices.nhs.uk/services" xmlns="http://www.w3.org/2005/Atom">
 <title type="text">NHS Choices - GP Practices Near Postcode - W1T4LB - Within 5km</title>
 <entry>
  <id>http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/27369</id>
  <title type="text">Fitzrovia Medical Centre</title>
  <updated>2011-08-20T22:47:39Z</updated>
  <link rel="self" title="Fitzrovia Medical Centre" href="http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/27369?apikey="/>
  <link rel="alternate" title="Fitzrovia Medical Centre" href="http://www.nhs.uk/ServiceDirectories/Pages/GP.aspx?pid=303A92EF-EC8D-496B-B9CD-E6D836D13BA2"/>
  <content type="application/xml">
   <s:organisationSummary>
    <s:name>Fitzrovia Medical Centre</s:name>
    <s:address>
     <s:addressLine>31 Fitzroy Square</s:addressLine>
     <s:addressLine>London</s:addressLine>
     <s:postcode>W1T6EU</s:postcode>
    </s:address>
    <s:contact type="General">
     <s:telephone>020 7387 5798</s:telephone>
    </s:contact>
    <s:geographicCoordinates>
     <s:northing>182000</s:northing>
     <s:easting>529000</s:easting>
     <s:longitude>-0.140267259415255</s:longitude>
     <s:latitude>51.5224357586293</s:latitude>
    </s:geographicCoordinates>
    <s:Distance>0.360555127546399</s:Distance>
   </s:organisationSummary>
  </content>
 </entry>
</feed>

I'm now using this code to access the node.

<?php   

$feedURL = 'http://v1.syndication.nhschoices.nhs.uk/organisations/pharmacies/postcode/W1T4LB.xml?apikey=&range=5';
$xml = file_get_contents($feedURL);
$sxml = new SimpleXMLElement($xml);
$sxml->registerXPathNamespace('a', 'http://www.w3.org/2005/Atom');
$sxml->registerXPathNamespace('s', 'http://syndication.nhschoices.nhs.uk/services');

$addr = $sxml->xpath('//s:address');

var_dump($addr[0]);

?>

Here $addr is empty but it should have ten entries.

Please can someone explain a good way to print out each <s:addressLine> node contents, and to place the postcode into a var.

I am working with the namespace principle in practice, although this is fairly new to me. Appreciate any information you could convey about learning XPath, and the PHP SimpleXML model.

Appreciate the help.

EDIT -

In seeing the update given below I decided to put my final output code into this:

function doPharmacy($postcode, $request, $prev, $next)
{


    $feedURL = 'http://v1.syndication.nhschoices.nhs.uk/organisations/pharmacies/postcode/' . $postcode . '.xml?apikey=&range=5';
    $xml = file_get_contents($feedURL);
    $sxml = new SimpleXMLElement($xml);
    $sxml->registerXPathNamespace('a', 'http://www.w3.org/2005/Atom');
    $sxml->registerXPathNamespace('s', 'http://syndication.nhschoices.nhs.uk/services');

    ////////////// XPATH \\\\\\\\\\\\\\

    $addrLines = $sxml->xpath('/a:feed/a:entry[' . $request . ']/a:content/s:organisationSummary/s:address/s:addressLine');
    $nhsPostcode = $sxml->xpath('/a:feed/a:entry[' . $request . ']/a:content/s:organisationSummary/s:address/s:postcode');
    $tel = $sxml->xpath('/a:feed/a:entry[' . $request . ']/a:content/s:organisationSummary/s:contact/s:telephone');
    $distance = $sxml->xpath('/a:feed/a:entry[' . $request . ']/a:content/s:organisationSummary/s:Distance');
    $title = $sxml->xpath('/a:feed/a:entry[' . $request . ']/a:title');
    $link = $sxml->xpath('/a:feed/a:entry[' . $request . ']/a:link[@rel="alternate"]/@href');

    $nhsPostcode = array_pop($nhsPostcode); // always taking first node from set
    $tel = array_pop($tel);
    $distance = (double)array_pop($distance);
    $title = array_pop($title);
    $link = array_pop($link);


    ////////////// OUTPUT: JSON \\\\\\\\\\\\\\

    print '{"addr": "';

    foreach ($addrLines as $addr)
    {
        print $addr . '<br />'; // ok to use HTML tags in JSON
    }

    print '",';

    print '"postcode": "' . $nhsPostcode . '",';

    print '"tel": "' . $tel . '",';

    $num = number_format($distance, 2);

    print '"distance": "' . $num . '",';

    print '"title": "' . $title . '",';

    print '"link": "' . $link . '",';

    $nhsPostcode = urlencode($nhsPostcode);

    print'"mapsURL": "http://maps.googleapis.com/maps/api/staticmap?center=' . $nhsPostcode . '&zoom=15&size=155x137&sensor=false&scale=2",';

    print '"prev": "' . $prev . '",';

    print '"next": "' . $next . '"';

    print '}';
}

?>
like image 862
Alex Avatar asked Aug 22 '11 16:08

Alex


1 Answers

This works for me:

$addr = $sxml->xpath('//s:address');
foreach ($addr as $a) {
    $addressLine = $a->xpath('s:addressLine');
    foreach ($addressLine as $al) {
        echo (string)$al."<br/>";
    }
    $postalCode = $a->xpath('s:postcode');
    foreach ($postalCode as $p) {
        echo (string)$p."<br/>";
    }
}

Which displays:

31 Fitzroy Square
London
W1T6EU
like image 140
brian_d Avatar answered Oct 07 '22 02:10

brian_d