Accessing namespace colon nodes in XML with Simple

2019-01-29 12:26发布

问题:

This is similar to a question I've posted, but I've broadened out as this has got to be solvable.

I am trying to access rating and viewCount from this rss feed. Now, these are namespaced with yt: and gd: - however the namespace references are 404's from youtube's feed so it seems to be failing. Any help please, please?

I am trying to use:-

$ytFeed->children('http://gdata.youtube.com/schemas/2007')->statistics->attributes('viewCount'));

But it fails... It does work like that normally, for instance I CAN access media: with

$ytFeed->children('http://search.yahoo.com/mrss/')->group->category);

This is the original RSS, look at the bottom for these nodes:-

<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns='http://www.w3.org/2005/Atom' xmlns:media='http://search.yahoo.com/mrss/' xmlns:gd='http://schemas.google.com/g/2005' xmlns:yt='http://gdata.youtube.com/schemas/2007'>
    <id>http://gdata.youtube.com/feeds/api/videos/tDJFDsZFw2E</id>
    <published>2009-03-02T07:02:49.000Z</published>
    <updated>2011-07-19T06:57:29.000Z</updated>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://gdata.youtube.com/schemas/2007#video' />
    <category scheme='http://gdata.youtube.com/schemas/2007/categories.cat' term='Music' label='Music' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Other Lives' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Jesse Tabish' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Jenny Hsu' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Jupiter Hotel' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='Portland' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='music' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='band' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='interview' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='mf magazine' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='fashion' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='hotel room' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='doug fir lounge' />
    <category scheme='http://gdata.youtube.com/schemas/2007/keywords.cat' term='erik schultz' />
    <title type='text'>Other Lives</title>
    <content type='text'>We sat down with Jesse Tabish and Jenny Hsu from Other Lives at the Jupiter Hotel in Portland, OR. We love these guys. Check them out at myspace.com/otherlivesVisit mf magazine at musicfashionmagazine.com or myspace.com/musicfashion</content>
    <link rel='alternate' type='text/html' href='http://www.youtube.com/watch?v=tDJFDsZFw2E&amp;feature=youtube_gdata' />
    <link rel='http://gdata.youtube.com/schemas/2007#video.responses' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/videos/tDJFDsZFw2E/responses' />
    <link rel='http://gdata.youtube.com/schemas/2007#video.related' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/videos/tDJFDsZFw2E/related' />
    <link rel='self' type='application/atom+xml' href='http://gdata.youtube.com/feeds/api/videos/tDJFDsZFw2E' />
    <author>
        <name>mfmagazine</name>
        <uri>http://gdata.youtube.com/feeds/api/users/mfmagazine</uri>
        </author>
    <gd:comments>
        <gd:feedLink href='http://gdata.youtube.com/feeds/api/videos/tDJFDsZFw2E/comments' countHint='16' />
        </gd:comments>
    <media:group>
        <media:category label='Music' scheme='http://gdata.youtube.com/schemas/2007/categories.cat'>Music</media:category>
        <media:content url='http://www.youtube.com/v/tDJFDsZFw2E?f=videos&amp;app=youtube_gdata' type='application/x-shockwave-flash' medium='video' isDefault='true' expression='full' duration='600' yt:format='5' />
        <media:content url='rtsp://v3.cache3.c.youtube.com/CiILENy73wIaGQlhw0XGDkUytBMYDSANFEgGUgZ2aWRlb3MM/0/0/0/video.3gp' type='video/3gpp' medium='video' expression='full' duration='600' yt:format='1' />
        <media:content url='rtsp://v6.cache3.c.youtube.com/CiILENy73wIaGQlhw0XGDkUytBMYESARFEgGUgZ2aWRlb3MM/0/0/0/video.3gp' type='video/3gpp' medium='video' expression='full' duration='600' yt:format='6' />
        <media:description type='plain'>We sat down with Jesse Tabish and Jenny Hsu from Other Lives at the Jupiter Hotel in Portland, OR. We love these guys. Check them out at myspace.com/otherlivesVisit mf magazine at musicfashionmagazine.com or myspace.com/musicfashion</media:description>
        <media:keywords>Other Lives, Jesse Tabish, Jenny Hsu, Jupiter Hotel, Portland, music, band, interview, mf magazine, fashion, hotel room, doug fir lounge, erik schultz</media:keywords>
        <media:player url='http://www.youtube.com/watch?v=tDJFDsZFw2E&amp;feature=youtube_gdata_player' />
        <media:thumbnail url='http://i.ytimg.com/vi/tDJFDsZFw2E/0.jpg' height='240' width='320' time='00:05:00' />
        <media:thumbnail url='http://i.ytimg.com/vi/tDJFDsZFw2E/1.jpg' height='90' width='120' time='00:02:30' />
        <media:thumbnail url='http://i.ytimg.com/vi/tDJFDsZFw2E/2.jpg' height='90' width='120' time='00:05:00' />
        <media:thumbnail url='http://i.ytimg.com/vi/tDJFDsZFw2E/3.jpg' height='90' width='120' time='00:07:30' />
        <media:title type='plain'>Other Lives</media:title>
        <yt:duration seconds='600' />
        </media:group>
    <gd:rating average='5.0' max='5' min='1' numRaters='17' rel='http://schemas.google.com/g/2005#overall' />
    <yt:statistics favoriteCount='10' viewCount='3572' />
    </entry>

回答1:

Using DomDocument and DomXpath:

error_reporting(E_ALL ^ E_STRICT);
ini_set('display_errors', 'on');

$dom = new DomDocument;
$dom->load('data.xml');

$xpath = new DomXpath($dom);
$xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom');
$xpath->registerNamespace('media', 'http://search.yahoo.com/mrss/');
$xpath->registerNamespace('gd', 'http://schemas.google.com/g/2005');
$xpath->registerNamespace('yt', 'http://gdata.youtube.com/schemas/2007');

$favoriteCountAttr = $xpath->query('/atom:entry/yt:statistics/@favoriteCount')->item(0);
if ($favoriteCountAttr instanceof DomAttr) {
    echo $favoriteCountAttr->nodeValue; // output: 10
}


回答2:

Simple pass the namespace argument when calling children function

$nodes = $xml->children('gd', true);

See the manual: http://www.php.net/manual/en/simplexmlelement.children.php



回答3:

Okay, first problem is that you are misusing the attributes method:

$simpleXML->statistics->attributes('viewCount'));

in the above (paraphrased from your example) you pass in the name of the attribute you want, which is not the parameter that attributes accepts. The above, instead, would return all attributes of the statistics element where the attribute itself had a namespace of viewCount, because the method expects the first parameter, if one is set, to be the attribute's namespace.

Your code would work if you instead accessed the attributes as an array of the element, like so:

$ytFeed->children('http://gdata.youtube.com/schemas/2007')->statistics['viewCount'];

If you want to avoid using the full namespace uri and the children method every time, you could simplify by using the getNamespaces method to map all namespaces to one array and then mapping the children with that namespace to one object via the children method, like:

$namespaces = $ytFeed->getNameSpaces(true);
$yt = $ytFeed->children($namespaces['yt']);
$yt->statistics['viewCount'];

// Access all media: namespaced group elements like in your "working" example:
$media = $ytFeed->children($namespaces['media']);
$media->group->category;

I realize this is over 2 years old and an answer was accepted, but the accepted answer is really just an alternative that is better documented and more intuitive, but does not tell others who find this question the actual way to achieve this with SimpleXML, which in the end requires only an extra two lines of code to the DOMDocument's 6-8 extra lines and a different extension, which may mislead future readers into thinking it can't be done with SimpleXML. It can, and it's easy, just not very obvious.