Google Analytics and XML namespace issue - php

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

Related

Get video Id from XML youtube video using PHP

I'm using PHP to process XML information. How can I get from the XML youtube the video id?
Question I have:
> $vid['title'] = $video->title; $vid['date'] = $video->updated;
that works. Only I also want to be getting the video id
$vid['id'] = ?
I use this XML as example , off course I use the real feed.
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns:yt="http://www.youtube.com/xml/schemas/2015" xmlns:media="http://search.yahoo.com/mrss/" xmlns="http://www.w3.org/2005/Atom">
<link rel="self" href="http://www.youtube.com/feeds/videos.xml?channel_id=UCCXoCcu9Rp7NPbTzIvogpZg&orderby=published"/>
<id>yt:channel:UCCXoCcu9Rp7NPbTzIvogpZg</id>
<yt:channelId>UCCXoCcu9Rp7NPbTzIvogpZg</yt:channelId>
<title>Fox Business</title>
<link rel="alternate" href="https://www.youtube.com/channel/UCCXoCcu9Rp7NPbTzIvogpZg"/>
<author>
<name>Fox Business</name>
<uri>https://www.youtube.com/channel/UCCXoCcu9Rp7NPbTzIvogpZg</uri>
</author>
<published>2008-02-04T12:35:54+00:00</published>
<entry>
<id>yt:video:yt9cwC3bySI</id>
<yt:videoId>yt9cwC3bySI</yt:videoId>
(1) For <yt:videoId> You can try:
$vid['id'] = $video->{'yt:videoId'}
(2) For <id> You can try:
$vid['title'] = $video->id;
Or else finally try...
Read not as XML but as a string of text. Use the PHP String functions to extract the text that exists between the <yt:videoId> and </yt:videoId>.

Unable to parse atom feed

I am implementing Youtube push notification and implemented webhook. Youtube gives updates in the form of atom feed. My problem is i can't parse that feed.
This is the XML:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:yt="http://www.youtube.com/xml/schemas/2015">
<link rel="hub" href="https://pubsubhubbub.appspot.com" />
<link rel="self" href="https://www.youtube.com/xml/feeds/videos.xml?channel_id=UCaNoTnXcQQt3ody_cLZSihw" />
<title>YouTube video feed</title>
<updated>2018-03-01T07:21:59.144766801+00:00</updated>
<entry>
<id>yt:video:vNQyYJqFopE</id>
<yt:videoId>vNQyYJqFopE</yt:videoId>
<yt:channelId>UCaNoTnXcQQt3ody_cLZSihw</yt:channelId>
<title>Test Video 4</title>
<link rel="alternate" href="https://www.youtube.com/watch?v=vNQyYJqFopE" />
<author>
<name>Testing</name>
<uri>https://www.youtube.com/channel/UCaNoTnXcQQt3ody_cLZSihw</uri>
</author>
<published>2018-03-01T07:21:48+00:00</published>
<updated>2018-03-01T07:21:59.144766801+00:00</updated>
</entry>
<?php
$xml = '<?xml versio......';
$obj = simplexml_load_string($xml);
echo '<pre>';print_r($obj);echo '</pre>';
Screenshot
How to get the value of yt:videoId element. I am new to PHP, if I did anything wrong please correct me.
It seems the XML elements containing the yt namespace (e.g. <yt:videoId>) are not being parsed by simplexml_load_string. I don't know why but in your case the video id is also present in the <id> element you just need to extract the last value or simply cut of yt:video: in front of it. That is at least an easy workaround.
Also it works if you use a direct XPath to the <yt:videoId> element like this:
echo $obj->xpath('//yt:videoId')[0];
// output: vNQyYJqFopE
XPath always returns an array so you need to get the first element with [0].
Try this (updated)
$str = $obj->entry->id;
echo substr($str, strpos($str, "video:")+ 6);
Get the channel
$chan = $obj->entry->author->uri;
echo substr($chan , strpos($chan , "channel/")+ 8);

PHP: How to extract “content type=”application/xml" nodes from a XML file?

I have a valid XML file (generated from SharePoint) which looks like this (in browser):
Sample XML File
<?xml version="1.0" encoding="utf-8"?>
<feed xml:base="https://www.example.com/_api/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml">
<id>9913f043-xxxx-xxxx-xxxx-xxxx-xxxx</id>
<title />
<updated>2017-05-23T06:08:01Z</updated>
<entry m:etag=""23"">
<id>Web/Lists(guid'13306095-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx')/Items(1)</id>
<category term="SP.Data.XXXXXXXXXXXXXXXXXXXXX" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
<link rel="edit" href="Web/Lists(guid'13306095-xxxx-xxxx-xxxx-xxxx-xxxx')/Items(1)" />
<title />
<updated>2017-05-23T06:08:01Z</updated>
<author>
<name />
</author>
<content type="application/xml">
<m:properties>
<d:FileSystemObjectType m:type="Edm.Int32">0</d:FileSystemObjectType>
<d:Id m:type="Edm.Int32">1</d:Id>
<d:ContentTypeId>0x0100B6A3B67BE96F724682CCDC8FBE9D70C2</d:ContentTypeId>
<d:Title m:null="true" />
<d:Topic>How to google?</d:Topic>
<d:Cats m:type="Collection(Edm.Int32)">
<d:element>1</d:element>
<d:element>2</d:element>
<d:element>3</d:element>
<d:element>4</d:element>
<d:element>5</d:element>
<d:element>6</d:element>
<d:element>7</d:element>
</d:Cats>
</m:properties>
</content>
</entry>
<entry>
.
.
</entry>
<entry>
.
.
</entry>
</feed>
(Note: I cut off some repeated nodes here, because it is so long.)
Clearly, we have inner nodes <content type="application/xml"> which also contain data inside.
The Problem (When parsing with PHP)
In PHP, i used this codes to parse (trying to extract it):
$xml = simplexml_load_file("data.xml");
foreach ($xml->entry as $item) {
echo $item->updated . PHP_EOL; // <--- This works!
print_r($item->content); // <--- This doesn't work as expected.
}
.. and then, it is giving me these:
2017-05-23T06:08:01Z
SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => application/xml
)
)
2017-05-23T06:08:01Z
SimpleXMLElement Object
(
[#attributes] => Array
(
[type] => application/xml
)
)
.
.
Question (Help!)
How do i extract (get) the actual data inside those <content type="application/xml"> nodes, please?
Please help. Thank you in advance.
The elements below "content" have a namespace (d:...). I had the same problem a while ago. This should help:
$xml = simplexml_load_file("data.xml");
foreach ($xml->entry as $item) {
echo $item->updated . PHP_EOL;
$ns = $item->content->children('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata');
print_r($ns->properties);
}
I updated the code. I'm shure print_r($ns->properties) doesn't show the complete sub-elements ... because they are from another namspace. I guess you can then do this:
$nsd = $ns->properties->children("http://schemas.microsoft.com/ado/2007/08/dataservices");
and proccced with the result.
In your example namespaces can be found in the document element:
xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"
(use the URL between the quotation marks)
d: and m: are used in the document to reference these namespaces.
EDIT: There is another namespace involved. Didn't recognize that. The solution can be atapted. I changed the code a bit.
I had a very similar issue. I was finally able to get my example working with this.
function pre($array){
echo "<pre>";
print_r($array);
echo "</pre>";
}
$record[$count]['id'] = $id->id;
$xmlData = utf8_encode(file_get_contents("https://ucf.uscourts.gov/odata.svc/Creditors(guid'81044f71-fb3c-11e5-ac5b-0050569d488e')"));
$xml = new SimpleXMLElement($xmlData);
$properties = $xml->content->children('http://schemas.microsoft.com/ado/2007/08/dataservices/metadata');
$fields = $properties->properties->children("http://schemas.microsoft.com/ado/2007/08/dataservices");
pre($fields);
$key = (string)$fields->Key;
$lastName = (string)$fields->LastName;
echo $key. "<br />";
echo $lastName. "<br />";
You would need to replace the Url in file_get_contents, the Key variable and LastName variable with you namespace values that you are looking for and I like to use a pre function to have things show easier. You can remove this part. Hopes this helps someone.

PHP outputing nested childnodes

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.

Traversing XML in PHP

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

Categories