Использование SimpleXML для чтения RSS-ленты
Я использую PHP и simpleXML для чтения следующего файла rss:
http://feeds.bbci.co.uk/news/england/rss.xml
Я могу получить большую часть информации, которую я хочу так:
$rss = simplexml_load_file('http://feeds.bbci.co.uk/news/england/rss.xml');
echo '<h1>'. $rss->channel->title . '</h1>';
foreach ($rss->channel->item as $item) {
echo '<h2><a href="'. $item->link .'">' . $item->title . "</a></h2>";
echo "<p>" . $item->pubDate . "</p>";
echo "<p>" . $item->description . "</p>";
}
Но как я могу вывести изображение миниатюр, которое находится в следующем теге:
<media:thumbnail width="66" height="49" url="http://news.bbcimg.co.uk/media/images/51078000/jpg/_51078953_226alanpotbury.jpg"/>
Ответы
Ответ 1
SimpleXML довольно плохо справляется с обработкой пространств имен. У вас есть два варианта: самый простой взлом - просто прочитать содержимое фида в строке и заменить пространства имен;
$feed = file_get_contents('http://feeds.bbci.co.uk/news/england/rss.xml');
$feed = str_replace('<media:', '<', $feed);
$rss = simplexml_load_string($feed);
...
Теперь вы можете напрямую получить доступ к элементу thumbnail
.
Более элегантный (не реально) метод - это выяснить, какой URI использует пространство имен. Если вы посмотрите на исходный код http://feeds.bbci.co.uk/news/england/rss.xml, вы увидите, что он указывает на http://search.yahoo.com/mrss/
.
Теперь вы можете использовать этот URI в методе children()
элемента SimpleXMLElement для получения содержимого медиа: элемент эскиза;
$rss = simplexml_load_file('http://feeds.bbci.co.uk/news/england/rss.xml');
foreach ($rss->channel->item as $item) {
$media = $item->children('http://search.yahoo.com/mrss/');
...
}
Ответ 2
Как вы уже знаете, SimpleXML позволяет выбрать дочернего элемента node, используя оператор свойства объекта ->
или атрибут node, используя доступ к массиву ['name']
. Это здорово, но операция работает только в том случае, если выбранное вами значение относится к тому же пространству имен.
Если вы хотите "перескочить" из пространства имен в другое, вы можете использовать children()
или attributes()
. В вашем случае это немного сложнее, потому что у вас есть <item/>
в глобальном пространстве имен, node, который вы ищете, находится в пространстве имен "media" *, и затем атрибуты снова попадают в глобальное пространство имен (они не имеют префикса.) Поэтому, используя стандартную нотацию объекта/массива, вам придется "прыгать" дважды:
foreach ($rss->channel->item as $item)
{
// we load the attributes into $thumbAttr
// you can either use the namespace prefix
$thumbAttr = $item->children('media', true)->thumbnail->attributes();
// or preferably the namespace name, read note below for an explanation
$thumbAttr = $item->children('http://search.yahoo.com/mrss/')->thumbnail->attributes();
echo $thumbAttr['url'];
}
* Примечание
Я называю пространство имен как пространство имен "media", но это не совсем правильно. Имя пространства имен http://search.yahoo.com/mrss/
, а "media" - только префикс, какой-то псевдоним, если хотите. Важно помнить, что http://search.yahoo.com/mrss/
- это реальное имя пространства имен. В какой-то момент ваш провайдер RSS может решить изменить префикс, скажем, "yahoo", и ваш script перестанет работать, если ваш script относится к префиксу "media". Однако, если вы используете имя пространства имен, оно будет продолжать работать независимо от префикса.