问题
I'm using simpleXML to parse this xml file. It's a feed I'm using to access the YouTube API. I want to embed the most recent video in an object and display the next four thumbnails.
So I'm using simplexml_load_file
on this, going using a foreach
loop to access the values in each feed.
I can access the values no problem, but I run into the problem that it stores each video in a separate SimpleXMLElement Object
. I don't have any control over which object I'm accessing as they are not stored in an array. So I can't get, say, $thumb[4]
or $entry[4]->thumb
.
I tried to use SimpleXMLIterator
, but for whatever reason, any values that have the same beginning render as blank. For example, the video could have eleven variations of:
And these would each render as [1]=""
, [2]=""
, [3]=""
, etc.
I'll happily provide some more information to anyone who can help!
Edit
Here is the print_r of my results. This is done on a single variable to give you an idea of the structure issue I'm facing. The entire print_r($entry) would give variables for each node in the XML file.
SimpleXMLElement Object
(
[0] => 159
)
SimpleXMLElement Object
(
[0] => 44
)
Also, the print_r is simply inside the PHP block for testing. I'm actually looking to access the variables within echoes in the HTML.
回答1:
You ran into the problem of namespaces and SimpleXML. The feed starts with
<feed xmlns='http://www.w3.org/2005/Atom' xmlns:media='http://search.yahoo.com/mrss/' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gd='http://schemas.google.com/g/2005' xmlns:yt='http://gdata.youtube.com/schemas/2007'>
The xmlns='http://www.w3.org/2005/Atom'
sets the default namespace to http://www.w3.org/2005/Atom
. I.e. its child elements are not really id
, updated
, category
but http://www.w3.org/2005/Atom:id
, http://www.w3.org/2005/Atom:updated
and so on...
So you can't access the the id element via $feed->id
, you need the method SimpleXMLELement::children(). It lets you specify the namespace of the child elements you want to retrieve.
For example,
$feed = simplexml_load_file('http://gdata.youtube.com/feeds/api/videos?author=ofcoursegolf&max-results=5&prettyprint=true');
$children = $feed->children('http://www.w3.org/2005/Atom');
echo $children->updated;
Currently prints 2010-02-06T05:23:33.858Z
.
To get the id of the first entry element you can use echo $children->entry[0]->id;
.
But then you'll hit the <media:group>
element and its children <media:category
, <media:player>
and so on..., which are in the xmlns:media='http://search.yahoo.com/mrss/'
namespace.
$feed = simplexml_load_file('http://gdata.youtube.com/feeds/api/videos?author=ofcoursegolf&max-results=5&prettyprint=true');
$group = $feed->children('http://www.w3.org/2005/Atom')
->entry[0]
->children('http://search.yahoo.com/mrss/')
->group
->children('http://search.yahoo.com/mrss/')
;
echo $group->player->attributes()->url, "\n";
foreach( $group->thumbnail as $thumb) {
echo 'thumb: ', $thumb->attributes()->url, "\n";
}
(Currently) prints
http://www.youtube.com/watch?v=ikACkCpJ-js&feature=youtube_gdata
thumb: http://i.ytimg.com/vi/ikACkCpJ-js/2.jpg
thumb: http://i.ytimg.com/vi/ikACkCpJ-js/1.jpg
thumb: http://i.ytimg.com/vi/ikACkCpJ-js/3.jpg
thumb: http://i.ytimg.com/vi/ikACkCpJ-js/0.jpg
Edit: I'd probably do that within the browser with a lot more JavaScript, but here's a (simple, ugly) example app.
<?php
//define('TESTENV' , true);
function getFeed($author) {
// <-- add caching here if needed -->
if ( !defined('TESTENV') ) {
$url = sprintf('http://gdata.youtube.com/feeds/api/videos?author=%s&max-results=5',
urlencode($author)
);
}
else {
$url = 'feed.xml';
}
return simplexml_load_file($url);
}
$feed = getFeed('jonlajoie');
if ( !isset($_GET['id']) ) {
$selected = '';
}
else {
$selected = $_GET['id'];
printf ('
<object width="425" height="344">
<param name="movie" value="http://www.youtube.com/v/%s"></param>
<param name="allowFullScreen" value="true"></param>
<param name="allowscriptaccess" value="always">
</param>
<embed src="http://www.youtube.com/v/%s" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="344"></embed>
</object>',
htmlspcialchars($selected), htmlspcialchars($selected)
);
}
$item = 0;
foreach( $feed->children('http://www.w3.org/2005/Atom')->entry as $entry ) {
$entryElements = $entry->children('http://www.w3.org/2005/Atom');
$groupElements = $entry
->children('http://search.yahoo.com/mrss/')
->group
->children('http://search.yahoo.com/mrss/')
;
if ( !preg_match('!^http://gdata.youtube.com/feeds/api/videos/([^/]+)!', $entryElements->id, $m) ) {
// google can choose whatever id they want. But this is only a simple example....
die('unexpected id: '.htmlspecialchars($entryElements->id));
}
$id = $m[1];
if ( $selected!==$id ) {
printf('<a href="?id=%s"><img src="%s" /></a>',
urlencode($id),
$groupElements->thumbnail[0]->attributes()->url
);
}
}
Edit 2: "And when I click the thumbnails, I'll use jQuery to load the video in the main space. Seems like I'll need precise access to node[#], right?"
If you're already using JavaScript/jQuery your PHP script (if needed at all) could simply return a (JSON encoded) array of all the data for all the video and your jQuery script could figure out what to do with the data.
回答2:
$doc = new DOMDocument();
$doc->loadXML(file_get_contents('http://gdata.youtube.com/feeds/api/videos?author=ofcoursegolf&max-results=5&prettyprint=true'));
$xpd = new DOMXPath($doc);
$xpd->registerNamespace('atom', "http://www.w3.org/2005/Atom");
false&&$node = new DOMElement();//this is for my IDE to have intellysense
$result = $xpd->query('//atom:feed/atom:entry[1]/media:group/media:thumbnail');
foreach($result as $node){
echo $node->getAttribute('url').'<br />';
}
echo "more results <br />";
$result = $xpd->query('//atom:feed/atom:entry[1]/media:group/media:thumbnail[1]');
foreach($result as $node){
echo $node->getAttribute('url').'<br />';
}
回答3:
Try $sxml->entry[4]->thumb
or something to that regard.
AKA, to access the first entries ID, you would go $sxml->entry[4]->id
Basically $sxml->entry
is an array of SimpleXMLElement Object
s. When you foreach them, you are going through each object and assigning it to $entry
, so that $entry = $sxml->entry[0]
and upwards.
You can go like this:
print_r($sxml);
to see the ENTIRE structure. And that will tell you what you need to use to access it.
回答4:
In the end, I did two foreach loops, one running through an XML feed showing the most recent one entry. Then, I echoed out the object around this to play the vide.
In the other, I ran through the most recent four entries, returning list elements for a list of thumbnails.
Now, when I click on a thumbnail video, javascript handles passing the parameters to the main entry. Now, how to reload that main object upon receiving the parameters, I'm open to ideas.
来源:https://stackoverflow.com/questions/2212009/simplexml-returning-multiple-objects-how-can-i-get-the-data