I have the following XML code that I'm trying to parse, but I'm sure of how to traverse some of the data in PHP:
<entry>
<id>http://data.treasury.gov:8001/Feed.svc/DailyTreasuryYieldCurveRateData(5360)</id>
<title type="text"></title>
<updated>2011-06-09T20:15:18Z</updated>
<author>
<name />
</author>
<link rel="edit" title="DailyTreasuryYieldCurveRateDatum" href="DailyTreasuryYieldCurveRateData(5360)" />
<category term="TreasuryDataWarehouseModel.DailyTreasuryYieldCurveRateDatum" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<content type="application/xml">
<m:properties>
<d:Id m:type="Edm.Int32">5360</d:Id>
<d:NEW_DATE m:type="Edm.DateTime">2011-06-01T00:00:00</d:NEW_DATE>
<d:BC_1MONTH m:type="Edm.Double">0.04</d:BC_1MONTH>
<d:BC_3MONTH m:type="Edm.Double">0.05</d:BC_3MONTH>
<d:BC_6MONTH m:type="Edm.Double">0.11</d:BC_6MONTH>
<d:BC_1YEAR m:type="Edm.Double">0.18</d:BC_1YEAR>
<d:BC_2YEAR m:type="Edm.Double">0.44</d:BC_2YEAR>
<d:BC_3YEAR m:type="Edm.Double">0.74</d:BC_3YEAR>
<d:BC_5YEAR m:type="Edm.Double">1.6</d:BC_5YEAR>
<d:BC_7YEAR m:type="Edm.Double">2.28</d:BC_7YEAR>
<d:BC_10YEAR m:type="Edm.Double">2.96</d:BC_10YEAR>
<d:BC_20YEAR m:type="Edm.Double">3.83</d:BC_20YEAR>
<d:BC_30YEAR m:type="Edm.Double">4.15</d:BC_30YEAR>
<d:BC_30YEARDISPLAY m:type="Edm.Double">4.15</d:BC_30YEARDISPLAY>
</m:properties>
</content>
</entry>
I can only get so far as
entry->content
As the following throws an error for having a colon:
entry->content->m:properties
How do I access what's inside content such as d:NEW_DATE?
In SimpleXML you can use the children('prefix', true) and attributes('prefix', true) functions to access namespaced content.
entry->content->children('m', true)->properties
or to access d:NEW_DATE
entry->content->children('m', true)->properties->children('d', true)->NEW_DATE
or one step further to access the m:type attribute
entry->content->children('m', true)->properties->children('d', true)->NEW_DATE->attributes('m', true)->type
You can use the SimpleXml's functions
SimpleXML
But my fav class is DOMDocument
Related
This is part of XML document:
<entry>
<author>
<name>Dunnock_D</name>
<uri>http://www.flickr.com/people/dunnock_d/</uri>
</author>
<link rel="license" type="text/html" href="https://creativecommons.org/licenses/by-nc/2.0/deed.en" />
<link rel="enclosure" type="image/jpeg" href="http://farm8.staticflickr.com/7548/26820724620_1d221c3187_b.jpg" />
</entry>
My code:
$xml = simplexml_load_string($result);
foreach ($xml->entry as $pixinfo) {
echo $pixinfo->link[1]['href'];
}
The problem is there can be one or more link strings and I need only particular with rel="enclosure" attribute.
What is the easiest way without extra IF and loops?
Thank you!
For that you can use DOMXPath, more specifically the query function. Let's say your $result variable contains the following:
<?xml version='1.0' encoding='UTF-8'?>
<entries>
<entry>
<author>
<name>Dunnock_D</name>
<uri>http://www.flickr.com/people/dunnock_d/</uri>
</author>
<link rel="license" type="text/html" href="https://creativecommons.org/licenses/by-nc/2.0/deed.en" />
<link rel="enclosure" type="image/jpeg" href="http://farm8.staticflickr.com/7548/26820724620_1d221c3187_b.jpg" />
</entry>
<entry>
<author>
<name>Dunnock_D</name>
<uri>http://www.flickr.com/people/dunnock_d/</uri>
</author>
<link rel="license" type="text/html" href="https://creativecommons.org/licenses/by-nc/2.0/deed.en" />
<link rel="enclosure" type="image/jpeg" href="http://farm8.staticflickr.com/7548/26820724620_1d221c3187_b.jpg" />
</entry>
<entry>
<author>
<name>Dunnock_D</name>
<uri>http://www.flickr.com/people/dunnock_d/</uri>
</author>
<link rel="license" type="text/html" href="https://creativecommons.org/licenses/by-nc/2.0/deed.en" />
<link rel="enclosure" type="image/jpeg" href="http://farm8.staticflickr.com/7548/26820724620_1d221c3187_b.jpg" />
</entry>
</entries>
I know the entries are repeated, but it's only for demo purposes. The code to get only the enclosure links would be:
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
$doc->loadXML($result);
$xpath = new DOMXpath($doc);
$entries = $xpath->query('//entries/entry');
foreach ($entries as $entry) {
$link = $xpath->query('link[#rel="enclosure"]', $entry)->item(0);
$href = $link->getAttribute('href');
echo "{$href}\n";
}
You are using simplexml. Just use "attributes()" function: http://php.net/manual/pt_BR/simplexmlelement.attributes.php
Or you can access directly:
foreach ($xml->entry as $pixinfo) {
if($pixinfo->link[1]['rel'] == 'enclosure') {
echo $pixinfo->link[1]['href'];
}
}
The solution is Xpath.
With SimpleXML you can fetch the attribute node and cast the generated SimpleXMLElement into a string. You should make sure that you got an element before you cast it. SimpleXMLElement::xpath() will always return an array of SimpleXMLElement objects.
$entry = new SimpleXMLElement($xml);
$enclosures = $entry->xpath('link[#rel="enclosure"]/#href');
if (count($enclosures) > 0) {
var_dump((string)$enclosures[0]);
}
Output:
string(63) "http://farm8.staticflickr.com/7548/26820724620_1d221c3187_b.jpg"
With DOM the bootstrap is slightly larger, but you can fetch the href attribute directly as a string:
$document = new DOMDocument();
$document->loadXml($xml);
$xpath = new DOMXpath($document);
var_dump(
$xpath->evaluate('string(/entry/link[#rel="enclosure"]/#href)')
);
This will return an empty string if the expression does not match.
Using PHP, SimpleXML and XPATH; I want to find a specific serviceId and then find the DMA and Abbreviation values. I can find a specific serviceId using $xml->xpath(//d:ServiceId[.= '123']), but I am not sure how to modify the xpath query to also return the DMA and Abbreviation as well.
<?xml>
<feed xmlns:m="" xmlns:d="">
<entry>
<content>
<m:properties>
<d:ServiceId>123</d:ServiceId>
<d:ServiceName>Service 1</d:ServiceName>
<d:DMA>DMA 1</d:DMAName>
<d:Abbreviation>ABC</d:Abbreviation>
</m:properties>
</content>
<content>
<m:properties>
<d:ServiceId>456</d:ServiceId>
<d:ServiceName>Service 2</d:ServiceName>
<d:DMA>DMA 2</d:DMAName>
<d:Abbreviation>DEF</d:Abbreviation>
</m:properties>
</content>
<content>
<m:properties>
<d:ServiceId>789</d:ServiceId>
<d:ServiceName>Service 3</d:ServiceName>
<d:DMA>DMA 3</d:DMAName>
<d:Abbreviation>HIJ</d:Abbreviation>
</m:properties>
</content>
</entry>
</feed>
</xml>
You need to get m:properties node first. To get it use this XPath:
//m:properties[d:ServiceId = 123]
After that just query this node to retrieve d:DMA and d:Abbreviation elements. Sorry, I don't know PHP but it should be straightforward.
As alternative try this XPath with union operator:
//m:properties[d:ServiceId = 123]/d:DMA | //m:properties[d:ServiceId = 123]/d:Abbreviation
I have looked through several posts on how to parse the namespace of a Google Analytics api feed (XML file) in PHP. They all say I need to have this bit of code:
$properties = $item->children('http://schemas.google.com/analytics/2009');
(or something similar, all involving the URL "http://schemas.google.com/analytics/2009")
The problem is, however, that I then get an error:
Fatal error: Call to a member function children() on a non-object
It seems as though the schemas.google.com doesn't exist, but I can't find where I need to be pointing to... any ideas?
Here's a snippet of the XML file I'm working with:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:dxp="http://schemas.google.com/analytics/2009" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/">
<id>https://www.googleapis.com/analytics/v2.4/data?ids=ga:42418300&dimensions=ga:pagePath&metrics=ga:pageviews,ga:uniquePageviews&sort=-ga:pageviews&start-date=2013-12-01&end-date=2014-01-01&max-results=10</id>
<updated>2014-01-03T22:21:31.057Z</updated>
<title type="text">Google Analytics Data for View (Profile) xxxxxxx</title>
<link rel="self" type="application/atom+xml" href="https://www.googleapis.com/analytics/v2.4/data?ids=ga:42418300&dimensions=ga:pagePath&metrics=ga:pageviews,ga:uniquePageviews&sort=-ga:pageviews&start-date=2013-12-01&end-date=2014-01-01&max-results=10"/>
<link rel="next" type="application/atom+xml" href="https://www.googleapis.com/analytics/v2.4/data?ids=ga:42418300&dimensions=ga:pagePath&metrics=ga:pageviews,ga:uniquePageviews&sort=-ga:pageviews&start-date=2013-12-01&end-date=2014-01-01&start-index=11&max-results=10"/>
<author>
<name>Google Analytics</name>
</author>
<generator>Google Analytics</generator>
<openSearch:totalResults>4826</openSearch:totalResults>
<openSearch:startIndex>1</openSearch:startIndex>
<openSearch:itemsPerPage>10</openSearch:itemsPerPage>
<dxp:aggregates>
<dxp:metric name="ga:pageviews" type="integer" value="166656"/>
<dxp:metric name="ga:uniquePageviews" type="integer" value="132895"/>
</dxp:aggregates>
<dxp:containsSampledData>false</dxp:containsSampledData>
<dxp:dataSource>
<dxp:property name="ga:profileId" value="xxxxxxxx"/>
<dxp:property name="ga:webPropertyId" value="UA-xxxxxxxx-1"/>
<dxp:property name="ga:accountName" value="Provost"/>
<dxp:tableId>ga:42418300</dxp:tableId>
<dxp:tableName>WebSite</dxp:tableName>
</dxp:dataSource>
<dxp:endDate>2014-01-01</dxp:endDate>
<dxp:startDate>2013-12-01</dxp:startDate>
<entry>
<id>https://www.googleapis.com/analytics/v2.4/data?ids=ga:42418300&ga:pagePath=/&start-date=2013-12-01&end-date=2014-01-01</id>
<updated>2014-01-03T22:21:31.057Z</updated>
<title type="text">ga:pagePath=/</title>
<link rel="alternate" type="text/html" href="http://www.google.com/analytics"/>
<dxp:dimension name="ga:pagePath" value="/"/>
<dxp:metric name="ga:pageviews" type="integer" value="38197"/>
<dxp:metric name="ga:uniquePageviews" type="integer" value="29385"/>
</entry>
<entry>
<id>https://www.googleapis.com/analytics/v2.4/data?ids=ga:42418300&ga:pagePath=/page2/&start-date=2013-12-01&end-date=2014-01-01</id>
<updated>2014-01-03T22:21:31.057Z</updated>
<title type="text">ga:pagePath=/page2/</title>
<link rel="alternate" type="text/html" href="http://www.google.com/analytics"/>
<dxp:dimension name="ga:pagePath" value="/page2/"/>
<dxp:metric name="ga:pageviews" type="integer" value="13964"/>
<dxp:metric name="ga:uniquePageviews" type="integer" value="10974"/>
</entry>
Here's my PHP so far:
<?php
//ini_set('auto_detect_line_endings',TRUE);
$xml = simplexml_load_file("/ga-feed.xml");
$namespaces = $xml->getNamespaces(true);
foreach ($xml->entry as $key => $value) {
$value->registerXPathNamespace('dxp', 'http://schemas.google.com/analytics/2009');
echo $value->xpath('dxp:metric[pageviews]') . "<br />\n";
}
?>
Eventually, I need to be able run some calculations with pageviews and unique pageviews (show top 4 sites, a 5th "Other" would be a combination of all the other sites) against the overall pageviews/unique pageviews. Am I at least going in a semi-correct direction?
Update: In my foreach, I removed "feed" so it just says $xml->entry as $key, and now it will display a list of text:
Array
Array
Array
Array
Array
Array
Array
Array
Array
Array
Not quite what I'm looking for... but progress? lol
I would like to create an XML like this but I can not do it ..
<content type="application/xml">
<m:properties>
<d:Description>test</d:Description>
<d:IncidentId m:type="Edm.Guid">00000000-0000-0000-0000-000000000000</d:IncidentId>
<d:ResponsibleContactId m:type="Edm.Boolean" m:null="true" />
My code in PHP :
$sxe = new SimpleXMLElement('<content></content>');
$prop = $sxe->addChild('m:proprieties');
$prop->addChild('d:Description', 'test');
$prop->addChild('d:IncidentId', '0');
$prop->addChild('d:ResponsibleContactId', '0');
Return this XML without prefix m and d:
<content>
<proprieties>
<description>PHP2: More Parser Stories</description>
<incidentid>0</incidentid>
<responsiblecontactid>0</responsiblecontactid>
</proprieties>...
How do I put my prefix "m:" and "d:"? Thanks
I am trying to output a xml file to an array thats then outputted to screen. The xml file loads I know it loads because as I can output entry > Id but I can not access its child nodes. I need the data located in.
content > s:organisationSummay
content > s:organisationSummay > s:address
content > s:organisationSummay > s:geographicCoordinates
how would I access the the data located in s:organisationSummay ,s:address, s:geographicCoordinates so I can getElementsByTagName for each items in that child node.
$doc2 = new DOMDocument();
$url = 'http://v1.syndication.nhschoices.nhs.uk/organisations/'.$_POST['ServiceType'].'/postcode/'.$_POST['PostCode'].'.xml?apikey=??&range=50';
echo $url;
$doc2->load($url);
$arrFeeds = array();
foreach ($doc2->getElementsByTagName('entry') as $node)
{
echo $node->getElementsByTagName($content->'s:name');
$itemRSS = array (
'PracticeName' => $organisationSummary->getElementsByTagName('s:name')->item(0)->nodeValue
);
array_push($arrFeeds, $itemRSS);
}
<?xml version="1.0" encoding="utf-8"?>
<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 - ls1- Within 50km</title>
<id>http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/postcode/bd164jt?range=50</id>
<rights type="text">© Crown Copyright 2009</rights>
<updated>2012-07-06T10:24:46+01:00</updated>
<category term="Search"/>
<logo>http://www.nhs.uk/nhscwebservices/documents/logo1.jpg</logo>
<author>
<name>NHS Choices</name>
<uri>http://www.nhs.uk</uri>
<email>webservices#nhschoices.nhs.uk</email>
</author>
<link rel="self" type="application/xml" title="NHS Choices - GP Practices Near Postcode - ;ls1 - Within 50km" href="http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/postcode/ls1?apikey=??&range=50"/>
<link rel="first" type="application/xml" title="first" length="1000" href="http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/postcode/ls1?apikey=??&range=50&page=1"/>
<link rel="next" type="application/xml" title="next" length="1000" href="http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/postcode/Ls1?apikey=??&range=50&page=2"/>
<link rel="last" type="application/xml" title="last" length="1000" href="http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/postcode/LS1?apikey=??&range=50&page=10"/>
<link rel="alternate" title="NHS Choices - Find and choose services - GP Practices" href="http://www.nhs.uk/ServiceDirectories/pages/ServiceSearch.aspx?ServiceType=GP"/>
<s:SearchCoords>439300,411100</s:SearchCoords>
<entry>
<id>http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/1</id>
<title type="text">Medical Practice</title>
<updated>2012-07-06T09:24:46Z</updated>
<link rel="self" title="Medical Practice" href="http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/1?apikey=??"/>
<link rel="alternate" title="Medical Practice" href="http://www.nhs.uk/ServiceDirectories/Pages/GP.aspx?pid=1"/>
<content type="application/xml">
<s:organisationSummary>
<s:name>Medical Practice</s:name>
<s:address>
<s:addressLine>Health Care Centre</s:addressLine>
<s:addressLine>2</s:addressLine>
<s:addressLine>Town</s:addressLine>
<s:addressLine>Yorkshire</s:addressLine>
<s:postcode>?</s:postcode>
</s:address>
<s:contact type="General">
<s:telephone>5558383</s:telephone>
</s:contact>
<s:geographicCoordinates>
<s:northing>438880</s:northing>
<s:easting>411444</s:easting>
<s:longitude>-1.82821202227791</s:longitude>
<s:latitude>53.996218047559</s:latitude>
</s:geographicCoordinates>
<s:Distance>0.5</s:Distance>
</s:organisationSummary>
</content>
</entry>
<entry>
<id>http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/2</id>
<title type="text">Surgery</title>
<updated>2012-07-06T09:24:46Z</updated>
<link rel="self" title="Surgery" href="http://v1.syndication.nhschoices.nhs.uk/organisations/gppractices/1?apikey=??"/>
<link rel="alternate" title="Surgery" href="http://www.nhs.uk/ServiceDirectories/Pages/GP.aspx?pid=2"/>
<content type="application/xml">
<s:organisationSummary>
<s:name>Surgery</s:name>
<s:address>
<s:addressLine>Healthcare Centre</s:addressLine>
<s:addressLine>Kings</s:addressLine>
<s:addressLine>Town</s:addressLine>
<s:postcode>?</s:postcode>
</s:address>
<s:contact type="General">
<s:telephone>555555</s:telephone>
<s:email>Email</s:email>
</s:contact>
<s:geographicCoordinates>
<s:northing>78421</s:northing>
<s:easting>484100</s:easting>
<s:longitude>-1.828987402220691</s:longitude>
<s:latitude>53.987218047559</s:latitude>
</s:geographicCoordinates>
<s:Distance>0.5</s:Distance>
</s:organisationSummary>
</content>
</entry>
</feed>
This is a namespaced document, so you need to use the proper namespace methods, e.g. DOMDocument::getElementsByTagNameNS.
In addition, there is so much wrong with your loop that I suspect you're either not including all the code or you really misunderstand how DOMDocument works.
$NS = array(
's' => "http://syndication.nhschoices.nhs.uk/services",
'atom' => "http://www.w3.org/2005/Atom",
);
$entries = array();
foreach ($doc2->getElementsByTagNameNS($NS['s'], 'organisationSummary') as $node)
{
$entries[] = array(
'name' => trim($node->getElementsByTagNameNS($NS['s'], 'name')->item(0)->textContent),
'address' => keyByElementName($node->getElementsByTagNameNS($NS['s'], 'address')->item(0)),
'geographicCoordinates' => keyByElementName($node->getElementsByTagNameNS($NS['s'], 'geographicCoordinates')->item(0)),
);
}
function keyByElementName(DOMNode $node)
{
$elem = array();
foreach ($node->childNodes as $child) {
if ($child->nodeType===XML_ELEMENT_NODE) {
$elem[$child->localName] = trim($child->textContent);
}
}
return $elem;
}
However, consider using DOMXPath or SimpleXML, as these will be easier than dom traversal.