Использование 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://img.ruphp.com/php/_51078953_226alanpotbury.jpg"/> 

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/'); ... } 

Как вы уже знаете, SimpleXML позволяет выбрать дочерний элемент узла, используя оператор свойства объекта -> или атрибут узла, используя доступ к массиву ['name'] . Это здорово, но операция работает только в том случае, если выбранное вами принадлежит к тому же пространству имен .

Если вы хотите «перескочить» из пространства имен в другое, вы можете использовать методы children() или attributes() . В вашем случае это немного сложнее, потому что у вас есть <item/> в глобальном пространстве имен, <item/> вам узел находится в пространстве имен «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», и ваш скрипт перестанет работать, если ваш скрипт ссылается на префикс «media». Однако, если вы используете имя пространства имен, оно будет продолжать работать независимо от префикса.