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 '}';
}
?>
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
Previous answers have helped me a lot! So here go the complete solution.
$feedURL = "http://v1.syndication.nhschoices.nhs.uk/organisations/pharmacies/postcode/{$user->postcode}.xml?apikey=XXXX&range=100";
$xml = simplexml_load_file($feedURL);
$xml->registerXPathNamespace('s', 'http://syndication.nhschoices.nhs.uk/services');
$org = $xml->xpath('//s:organisationSummary');
$i = 0;
$item = array();
foreach ($org as $o)
{
$aux = $o->xpath('s:name');
$item[$i]['name'] = (string) $aux[0];
$addr = $o->xpath('s:address');
foreach ($addr as $a)
{
$aux = '';
$addressLine = $a->xpath('s:addressLine');
foreach ($addressLine as $a2)
{
$aux .= (string) $a2[0] . "\n";
}
$aux2 = $a->xpath('s:postcode');
if (is_array($aux2))
{
$aux .= (string) $aux2[0];
}
$item[$i]['address'] = $aux;
}
$i ++;
}
This will provide:
array (
0 =>
array (
'name' => 'Your Local Boots Pharmacy',
'address' => 'Century House
Station Road
Manningtree
CO11 1AA',
),
1 =>
array (
'name' => 'The Pharmacy',
'address' => 'The Street
East Bergholt
CO7 6SE',
), and so on...
Related
How can I read the xml:lang Value from this xml File???
<Catalog><Products>
<Product>
<Id>123</Id>
<Name xml:lang="en">name english product</Name>
<Description xml:lang="en">desc xyz</Description>
<Name xml:lang="de">name german</Name>
<Description xml:lang="de">desc germa</Description>
<Image num="1"><Url>pic.jpg</Url></Image>
<Image num="2"><Url>pic2.jpg</Url></Image>
</Product>
<Product>...
I want the value of the xml:lang="de" - Tag and the Image-Values.
Does anybody have an idea???
Thanx :-)
Update: I parse the xml like this, but how do i get this values???
$datei = "test.xml";
$z = new XMLReader;
$z->open($datei);
$doc = new DOMDocument;
while ($z->read() && $z->name !== 'Product');
$i = 0; while ($z->name === 'Product')
{ $i++;
$node = simplexml_import_dom($doc->importNode($z->expand(), true));
...
I think this should do it.
$simpleXml = new SimpleXMLElement(file_get_contents($datei));
foreach ($simpleXml->Products->Product as $product) {
$name = $product->xpath('Name[#xml:lang="en"]')[0];
echo $name . "\n";
foreach($product->Image as $img) {
echo $img->Url . "\n";
}
}
xpath use to many resurses. You can scan it, taking needed nodes. In the code you will see how take name and value of nodes and attributes, which have prefix.
$simpleXml = new SimpleXMLElement(file_get_contents($datei)));
foreach ($simpleXml->Products->Product as $products) // list of nodes with same name
foreach($products as $product) { // every node
if ($product->getName() === 'Image') { // for image take child
echo $product->Url->getName() . " = " . $product->Url ."\n";
$attrs = $product->attributes(); // Attribute without prefix
if(isset($attrs['num'])) echo " num = " . $attrs['num'] . "\n";
}
else echo $product->getName() . " = " . $product ."\n";
$attrs = $product->attributes('xml', true); // if 2nd true, 1st is prefix
if(isset($attrs['lang'])) echo " lang = " . $attrs['lang'] . "\n";
}
result
Id = 123
Name = name english product
lang = en
Description = desc xyz
lang = en
Name = name german
lang = de
Description = desc germa
lang = de
Url = pic.jpg
num = 1
Url = pic2.jpg
num = 2
i am doing something wrong with my foreach cycle. But looks my knowledge is not enugh to figure out what's wrong. My code is pretty simple:
$xnl_file = "xml.xml";
$xml = simplexml_load_file($xnl_file);
$my_file = 0;
foreach ($xml as $value){
var_dump($value);
$CountryOrganizationId = "<CountryOrganizationId>".$xml->Partnership->CountryOrganizationId."</CountryOrganizationId>";
$PartnershipId = "<PartnershipId>".$xml->Partnership->PartnershipId."</PartnershipId>";
$OwnerId = "<OwnerId>".$xml->Partnership->OwnerId."<OwnerId>";
$PartnerIdList = "<PartnerIdList><String>".$xml->Partnership->PartnerIdList->String."</String></PartnerIdList>";
$CountryOrganizationId_contact = "<Contract><CountryOrganizationId>".$xml->Partnership->Contract->CountryOrganizationId."</CountryOrganizationId>";
$ContractId = "<ContractId>".$xml->Partnership->Contract->ContractId."</ContractId>";
$data = "<Partnership>".$CountryOrganizationId.$PartnershipId.$OwnerId.$PartnerIdList.$CountryOrganizationId_contact.$ContractId.$Role1.$Category1.$Rate1.
$Role2.$Category2.$Rate2.$Role3.$Category3.$Rate3."</Partnership>";
echo $data;
}
I am getting data from XML and try to parse it on multiple one, but this just copy same data again and again. I am not sure what i am doing wrong. In my opinion data should rewrite each other every time cycle is doing same but they are not changing. At echo $data i get as many results as i should, problem is just they are same.
If I var_dump $value at start i get nice result that data are coming to cycle but why the output is the same all the time?
Please can somebody give me advise?
Thanks
The $value variable is never used, you're always using the $xml. Try it like:
$xnl_file = "xml.xml";
$xml = simplexml_load_file($xnl_file);
$my_file = 0;
foreach ($xml as $value){
var_dump($value);
$CountryOrganizationId = "<CountryOrganizationId>" . $value->CountryOrganizationId . "</CountryOrganizationId>";
$PartnershipId = "<PartnershipId>" . $value->PartnershipId . "</PartnershipId>";
$OwnerId = "<OwnerId>" . $value->OwnerId . "<OwnerId>";
$PartnerIdList = "<PartnerIdList><String>" . $value->PartnerIdList->String . "</String></PartnerIdList>";
$CountryOrganizationId_contact = "<Contract><CountryOrganizationId>" . $value->Contract->CountryOrganizationId . "</CountryOrganizationId>";
$ContractId = "<ContractId>" . $value->Contract->ContractId . "</ContractId>";
$data = "<Partnership>" . $CountryOrganizationId . $PartnershipId . $OwnerId . $PartnerIdList . $CountryOrganizationId_contact .
$ContractId . $Role1 . $Category1 . $Rate1 . $Role2 . $Category2 . $Rate2 . $Role3 . $Category3 . $Rate3 .
"</Partnership>"afdsf
echo $data;
}
Concat $data to its previous value { $data .= "......"}
foreach ($xml as $value)
{
var_dump($value);
$CountryOrganizationId = "<CountryOrganizationId>".$xml->Partnership->CountryOrganizationId."</CountryOrganizationId>";
$PartnershipId = "<PartnershipId>".$xml->Partnership->PartnershipId."</PartnershipId>";
$OwnerId = "<OwnerId>".$xml->Partnership->OwnerId."<OwnerId>";
$PartnerIdList = "<PartnerIdList><String>".$xml->Partnership->PartnerIdList->String."</String></PartnerIdList>";
$CountryOrganizationId_contact = "<Contract><CountryOrganizationId>".$xml->Partnership->Contract->CountryOrganizationId."</CountryOrganizationId>";
$ContractId = "<ContractId>".$xml->Partnership->Contract->ContractId."</ContractId>";
$data .= "<Partnership>".$CountryOrganizationId.$PartnershipId.$OwnerId.$PartnerIdList.$CountryOrganizationId_contact.$ContractId.$Role1.$Category1.$Rate1.
$Role2.$Category2.$Rate2.$Role3.$Category3.$Rate3."</Partnership>";
}
echo $data;
I have a xml. as shown in the attachment ..
How can I read the contents via php
http://agency.lastminute-hr.com/slike/xml_read1.jpg "XML"
Now I read this xml:
<?
$request = new SimpleXMLElement('<HotelInfoRequest/>');
$request->Username = 'SERUNCD';
$request->Password = 'TA78UNC';
$request->HotelID = '123';
$url = "http://wl.filos.com.gr/services/WebService.asmx/HotelInfo";
$result = simplexml_load_file($url . "?xml=" . urlencode($request->asXML()));
function RecurseXML($xml,$parent="")
{
$child_count = 0;
foreach($xml as $key=>$value)
{
$child_count++;
if(RecurseXML($value,$parent.".".$key) == 0) // no childern, aka "leaf node"
{
print($parent . "." . (string)$key . " = " . (string)$value . "<BR>\n");
}
}
return $child_count;
}
RecurseXML($result);
?>
this result look:
..
..
.Response.Hotels.Hotel.Rooms.Room.Quantity = 0
.Response.Hotels.Hotel.Rooms.Room.MaxPax = 3
.Response.Hotels.Hotel.Rooms.Room.MinPax = 2
.Response.Hotels.Hotel.Rooms.Room.RoomType.languages.lang = Room Double Standard
.Response.Hotels.Hotel.Rooms.Room.RoomType.languages.lang = Camera single standard
...
...
I need you to display the value and adttribut
<Rooms>
<Room ID = "5556">
<Quantity> 0 </ Quantity>
<MaxPax> 3 </ MaxPax>
<MinPax> 2 </ MinPax>
<Roomtype> </ roomtype>
</ Room>
....
..
Try (the first part is only for testing):
$string = <<<XML
<?xml version='1.0'?>
<Rooms>
<Room ID = "5556">
<Quantity> 0 </Quantity>
<MaxPax> 3 </MaxPax>
<MinPax> 2 </MinPax>
<Roomtype> </Roomtype>
</Room>
</Rooms>
XML;
$result = simplexml_load_string($string);
function RecurseXML($xml,$parent=".Response.Hotels.Hotel.Rooms"){
$children = $xml->children();
if ( empty($children) ) {
print($parent . "." . $xml->nodeName . " = " . (string)$xml . "<BR>\n");
}
else {
foreach($children as $key=>$value) {
RecurseXML($value, $parent . "." . $key);
}
}
}
RecurseXML($result);
I am getting attributes from XML nodes and saving them to variables with a for loop as such:
for ($i = 0; $i < 10; $i++){
$group = $xml->Competition->Round[0]->Event[$i][Group];
if($group == "MTCH"){
$eventid = $xml->Competition->Round[0]->Event[$i][EventID];
$eventname = $xml->Competition->Round[0]->Event[$i][EventName];
$teamaname = $xml->Competition->Round[0]->Event[$i]->EventSelections[0][EventSelectionName];
$teambname = $xml->Competition->Round[0]->Event[$i]->EventSelections[1][EventSelectionName];
echo "<br/>" . $eventid . ": " . $eventname . ", " . $teamaname . "VS" . $teambname;
}//IF
}//FOR
I can save each Event[EventID] and each Event[EventName] but I cannot get the EventSelections[EventSelectionNames] to save.
I am guessing this is because there are multiple (2) <EventSelection>s for each <Event>, this is why I tried to get them individually uising [0] and [1].
The part of the XML file in question looks like:
<Event EventID="1008782" EventName="Collingwood v Fremantle" Venue="" EventDate="2014-03-14T18:20:00" Group="MTCH">
<Market Type="Head to Head" EachWayPlaces="0">
<EventSelections BetSelectionID="88029974" EventSelectionName="Collingwood">
<Bet Odds="2.10" Line=""/>
</EventSelections>
<EventSelections BetSelectionID="88029975" EventSelectionName="Fremantle">
<Bet Odds="1.70" Line=""/>
</EventSelections>
</Market>
</Event>
Can anyone point me in the right direction to save the EventSelectionNames to variables?
Rather than looping and checking for $group, use xpath to select data directly:
$xml = simplexml_load_string($x); // assume XML in $x
$group = $xml->xpath("/Event[#Group = 'MTCH']")[0];
echo "ID: $group[EventID], name: $group[EventName]" . PHP_EOL;
If there are always two <EventSelections>, you can:
echo "Team A: " . $group->Market->EventSelections[0]['EventSelectionName']" . PHP_EOL;
echo "Team B: " . $group->Market->EventSelections[1]['EventSelectionName']" . PHP_EOL;
Otherwise, use foreach:
foreach ($group->Market->EventSelections as $es)
$teamnames[] = $es['EventSelectionName'];
echo "There are " . count($teamnames) . "Teams:" . PHP_EOL;
foreach ($teamname as $teamname) echo $teamname . PHP_EOL;
see it in action: https://eval.in/105642
Note:
The [0] at the end of the code-line starting with $group = $xml->xpath...requires PHP >= 5.4. If you are on a lower version, update PHP or use:
$group = $xml->xpath("/Event[#Group = 'MTCH']");
$group = $group[0];
Michi's answer is more correct and better coded but I also found the adding the node 'Market' to my code worked as well:
$teamaname = $xml->Competition->Round[0]->Event[$i]->Market->EventSelections[0][EventSelectionName];
$teambname = $xml->Competition->Round[0]->Event[$i]->Market->EventSelections[1][EventSelectionName];
I'm retrieving multiple weather forecasts through Yahoo's weather API -
$stockholm = simplexml_load_file("http://weather.yahooapis.com/forecastrss?w=906057&u=c");
$stockholm->registerXpathNamespace('yweather', 'http://xml.weather.yahoo.com/ns/rss/1.0');
$children = $stockholm->xpath('//channel/item/yweather:condition');
echo '<li><img class="c' . $children[0]['code'] . '" src="img/spacer.gif" alt=""><h2>' . $children[0]['temp'] . '°</h2><p><strong>Stockholm</strong></p></li>';
$alicante = simplexml_load_file("http://weather.yahooapis.com/forecastrss?w=752101&u=c");
$alicante->registerXpathNamespace('yweather', 'http://xml.weather.yahoo.com/ns/rss/1.0');
$children = $alicante->xpath('//channel/item/yweather:condition');
echo '<li><img class="c' . $children[0]['code'] . '" src="img/spacer.gif" alt=""><h2>' . $children[0]['temp'] . '°</h2><p><strong>Alicante</strong></p></li>';
$marbella = simplexml_load_file("http://weather.yahooapis.com/forecastrss?w=766537&u=c");
$marbella->registerXpathNamespace('yweather', 'http://xml.weather.yahoo.com/ns/rss/1.0');
$children = $marbella->xpath('//channel/item/yweather:condition');
echo '<li><img class="c' . $children[0]['code'] . '" src="img/spacer.gif" alt=""><h2>' . $children[0]['temp'] . '°</h2><p><strong>Marbella</strong></p></li>';
$torrevieja = simplexml_load_file("http://weather.yahooapis.com/forecastrss?w=775868&u=c");
$torrevieja->registerXpathNamespace('yweather', 'http://xml.weather.yahoo.com/ns/rss/1.0');
$children = $torrevieja->xpath('//channel/item/yweather:condition');
echo '<li><img class="c' . $children[0]['code'] . '" src="img/spacer.gif" alt=""><h2>' . $children[0]['temp'] . '°</h2><p><strong>Torrèvieja</strong></p></li>';
Is there a more effective way to load these feeds, possibly together? The response time is fairly minimal but if there's any way this could be optimized I'd like to know.
This does the same, but looks a bit more elegeant
<?php
$xml = array('stockholm' => 906057, 'alicante' => 752101, 'marbella' => 766537, 'torrevieja' => 775868);
foreach($xml as $city => $code) {
$smplxml = simplexml_load_file('http://weather.yahooapis.com/forecastrss?w=' .$code. '&u=c');
$smplxml->registerXpathNamespace('yweather', 'http://xml.weather.yahoo.com/ns/rss/1.0');
$children = $smplxml->xpath('//channel/item/yweather:condition');
echo '<li><img class="c' . $children[0]['code'] . '" src="img/spacer.gif" alt=""><h2>' . $children[0]['temp'] . '°</h2><p><strong>' .$city. '</strong></p></li>';
}
?>
(since I'm behind a proxy right now, I wasn't able to test it, sorry, but it may helps)
Well if you did something like:
function curlGet( $url ) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
$xml = array('stockholm' => 906057, 'alicante' => 752101, 'marbella' => 766537, 'torrevieja' => 775868);
$buffer = "<rsses>";
foreach($xml as $city => $code)
$buffer .= curlGet('http://weather.yahooapis.com/forecastrss?w=' .$code. '&u=c');
$buffer .= "</rsses>";
$smplxml = simplexml_load_string($buffer);
$smplxml->registerXpathNamespace('yweather', 'http://xml.weather.yahoo.com/ns/rss/1.0');
$children = $smplxml->xpath('//rss/channel/item/yweather:condition');
print_r($children);
Might work. You need to make sure that the data you add to $buffer is not junk though. Or otherwise your entire parsing will fail.