Подтвердить что ты не робот

Использование 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"/>  
4b9b3361

Ответ 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". Однако, если вы используете имя пространства имен, оно будет продолжать работать независимо от префикса.