Как получить атрибут узла с пространством имен с помощью SimpleXML?

youtube.xml

<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"> <entry> ... <yt:duration seconds="1870"/> ... </entry> </feed> 

update_videos.php

 $source = 'youtube.xml'; // load as file $youtube = new SimpleXMLElement($source, null, true); foreach($youtube->entry as $item){ //title works echo $item->title; //now how to get seconds? My attempt... $namespaces = $item->getNameSpaces(true); $yt = $item->children($namespaces['yt']); $seconds = $yt->duration->attributes(); echo $seconds['seconds']; //but doesn't work :( } 

Solutions Collecting From Web of "Как получить атрибут узла с пространством имен с помощью SimpleXML?"

Код, который у вас есть в вашем вопросе, действительно работает . Вы правильно указали, что можете получить доступ к атрибуту из пространства имен, который не находится в пространстве имен по умолчанию в качестве корневого элемента, используя метод SimpleXMLElement::children() с параметрами, связанными с пространством имен XML $ns и $is_prefix :

 $youtube->entry->children('yt', TRUE)->duration->attributes()->seconds; // is "1870" 

Поскольку это в основном то же, что и в вашем вопросе, можно сказать, что вы ответили на свой вопрос. Сравните с расширенной онлайн-демонстрацией №2 .


Длинный ответ: код, который у вас есть в вашем вопросе , работает . Вы можете найти свой пример XML и код в интерактивном примере онлайн: Online Demo # 1 – он показывает результат с разными версиями PHP и LIBXML.

Код:

 $buffer = '<feed xmlns="http://www.w3.org/2005/Atom" xmlns:yt="http://gdata.youtube.com/schemas/2007"> <entry> <yt:duration seconds="1870"/> </entry> </feed>'; $xml = new SimpleXMLElement($buffer); echo "ibxml version: ", LIBXML_DOTTED_VERSION, "\n"; foreach ($xml->entry as $item) { //original comment: how to get seconds? $namespaces = $item->getNameSpaces(true); $yt = $item->children($namespaces['yt']); $seconds = $yt->duration->attributes(); echo $seconds['seconds'], "\n"; // original comment: but doesn't work. } echo "done. should read 1870 one time.\n"; 

Результаты:

Выход для 5.3.26, 5.4.16 – 5.5.0

 ibxml version: 2.9.1 1870 done. should read 1870 one time. 

Выход для 5.3.15 – 5.3.24, 5.4.5 – 5.4.15

 ibxml version: 2.8.0 1870 done. should read 1870 one time. 

Выход для 5.1.2 – 5.3.14, 5.4.0 – 5.4.4

 ibxml version: 2.7.8 1870 done. should read 1870 one time. 

С этой точки зрения все выглядит хорошо. Поскольку вы не указали конкретного описания ошибки, трудно сказать, что пошло не так на ваш случай. Вероятно, вы использовали версию PHP, устаревшую после того, как вы задали свой вопрос, например, получить фатальную ошибку:

Неустранимая ошибка: вызов неопределенного метода SimpleXMLElement :: getNameSpaces ()

Возможно, также из-за устаревшей версии libxml. Согласно тесту, следующие версии libxml отлично работают с PHP 5.1.2-5.5.0:

  • Версия ibxml: 2.9.1
  • Версия ibxml: 2.8.0
  • Версия ibxml: 2.7.8

Итак, я нашел способ сделать это с помощью xpath, это лучший способ или есть способ, который согласуется с моим кодом в вопросе? Просто из любопытства.

 $source = 'youtube.xml'; // load as file $youtube = new SimpleXMLElement($source, null, true); $youtube->registerXPathNamespace('yt', 'http://gdata.youtube.com/schemas/2007'); $count = 0; foreach($youtube->entry as $item){ //title works echo $item->title; $attributes = $item->xpath('//yt:duration/@seconds'); echo $attributes[$count]['seconds']; $count++; } 

Я тоже боролся с этой ситуацией, тогда я нашел решение. Это так просто, как читать сложное пространство имен атрибутов XML.

 foreach($media->group->content as $content) { $attrs = $content->attributes(); $ytformat = $content->attributes("yt","format"); echo(" attr = " . $ytformat . "; "); if ($ytformat == 5) { $url = $attrs['url']; $type = $attrs['type']; echo ($url . " - " . $type); } } 

Надеюсь, поможет…:)

Следующее – это другое решение, использующее атрибуты () и children () только, проверенные и работающие ОК! 🙂

 $data=<<<XML <rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/"> <channel> <item> <title>Title: 0</title> <link test="test" test2="This is a test">Link:0</link> <media:thumbnail url="Thumbnail URL: 0"/> <media:content url="Content URL: 0" type="video/mp4" /> </item> <item> <title>Title: 1</title> <link>Link:1</link> <media:thumbnail url="1"/> <media:content url="1" type="video/mp4" /> </item> </channel> </rss> XML; $xml=simplexml_load_string($data); //reading simple node echo $xml->channel[0]->item[0]->title; echo "<br>----------------------------------<br>"; //reading/updating simple node's attribute echo $xml->channel[0]->item[0]->link->attributes()->test2="This is a NEW test!."; echo "<br>----------------------------------<br>"; //reading/updating namespaced node's attribute echo $xml->channel[0]->item[0]->children('media',TRUE)->content->attributes()->type="VIDEO/MP6"; //saving... $xml->asXml('updated.xml');