2017-01-29 3 views
1

Я пытаюсь разобрать 15 лучших видеороликов YouTube. Отрывок корма я пытаюсь разобрать выглядит следующим образом:Как легко анализировать XML-документы с пространствами имен в PHP с помощью SimpleXML?

<entry> 
    <title>The Title</title> 
    <link href="http://example.com" /> 
    <media:thumbnail url="http://example.com/image.png" /> 
    <media:description>The Description</media:description> 
    <media:statistics views="123456" /> 
    <pubDate>29/01/2017</pubDate> 
</entry> 

Я не может захватить любой из значений, которые используют тег, начинающиеся с <media:. Я использую следующий код для анализа данных; прокомментированные строки - это те, которые не работают.

foreach ($xml->entry as $val) { 
    echo "<item>".PHP_EOL; 
    echo "<title>".$val->title."</title>".PHP_EOL; 
    echo "<link>".$val->link["href"]."</link>".PHP_EOL; 
    //echo "<image>".$val->media:thumbnail["url"]."</image>".PHP_EOL; 
    //echo "<description>".$val->media:description."</description>".PHP_EOL; 
    //echo "<views>".$val->media:statistics["views"]."</views>".PHP_EOL; 
    echo "<pubDate>".$val->published."</pubDate>".PHP_EOL; 
    echo "</item>".PHP_EOL; 
} 

Как получить значения этих тегов без установки пространств имен. при выполнении var_dump на $xml->entry даже не отображаются элементы с именами. Есть ли лучшая встроенная функция для преобразования XML в массивы?

+0

Ваш XML не является корректным (т. Е. Недействительным). Согласно [W3C Namespaces в XML 1.0] (https://www.w3.org/TR/REC-xml-names/#ns-using): * префикс пространства имен, если он не является xml или xmlns, ДОЛЖЕН быть объявлен в атрибуте объявления пространства имен *. Поэтому должен быть объявлен префикс 'media'. – Parfait

+0

Намного сложнее, чем с DOM + Xpath. Зарегистрируйте собственные префиксы в экземпляре DOMXpath и используйте DOMXpath :: evaluation() для извлечения списков узлов и значений. – ThW

+0

У меня нет времени, чтобы написать полный ответ прямо сейчас, но метод, который вы ищете, - это '' -> children() '] (http://php.net/manual/en/simplexmlelement.children. PHP). В вашем случае '$ val-> children ('media', true) -> description' будет работать, хотя я бы рекомендовал жестко кодировать фактический URI пространства имен (из атрибута' xmlns: media'), а не префикс, в случае, если исходный документ регенерируется с разными префиксами. – IMSoP

ответ

0

Получил ответ от code provided by IMSoP. PHP фрагмент кода я закончил с использованием было заимствован из вышеуказанной ссылки, используя XML, аналогичный ОП:

foreach ($xml->children(NS_ATOM)->entry as $entry) { 
    echo "<item>".PHP_EOL; 
    echo "<title>".$entry->title."</title>".PHP_EOL; 
    echo "<link>".$entry->link->attributes(null)->href."</link>".PHP_EOL; 
    echo "<image>".$entry->children(NS_MEDIA)->group->children(NS_MEDIA)->thumbnail->attributes(null)->url."</image>".PHP_EOL; 
    echo "<description>".$entry->children(NS_MEDIA)->group->children(NS_MEDIA)->description."</description>".PHP_EOL; 
    echo "<guid>".$entry->children(NS_YT)->videoId."</guid>".PHP_EOL; 
    echo "<views>".$entry->children(NS_MEDIA)->group->children(NS_MEDIA)->community->children(NS_MEDIA)->statistics->attributes(null)->views."</views>".PHP_EOL; 
    echo "<pubDate>".$entry->published."</pubDate>".PHP_EOL; 
    echo "</item>".PHP_EOL; 
} 

Надеется, что это может помочь кому-то в будущем. Это был самый простой пример синтаксического анализа пространства имен XML, с которым я столкнулся до сих пор.

0

Рассмотрите XSLT, родственный к XPath, поскольку вы по существу преобразуете оригинальный XML, а не синтаксический анализ выбранных значений. С XSLT вам не понадобится цикл foreach и может адекватно обрабатывать пространства имен.

В самом деле, как показано ниже XSLT является самым быстрым из вышеупомянутых методов (SimpleXML запросов и XPath оценки), используя размещенную XML, обернутый в <feed ...> корня:

Простой XML-(от @IMSoP)

$time_start = microtime(true); 

$xml = file_get_contents('YoutubeFeed.xml'); 
$document = new SimpleXMLElement($xml); 
define('NS_ATOM', 'http://www.w3.org/2005/Atom'); 
define('NS_MEDIA', 'http://search.yahoo.com/mrss/'); 

foreach ($document->children(NS_ATOM)->entry as $entry) { 
    echo "<item>".PHP_EOL; 
    echo "<title>".$entry->title."</title>".PHP_EOL; 
    echo "<link>".$entry->link->attributes(null)->href."</link>".PHP_EOL; 
    echo "<image>".$entry->children(NS_MEDIA)->thumbnail->attributes()->url."</image>".PHP_EOL; 
    echo "<description>".$entry->children(NS_MEDIA)->description."</description>".PHP_EOL; 
    echo "<guid>".$entry->children(NS_MEDIA)->guid."</guid>".PHP_EOL; 
    echo "<views>".$entry->children(NS_MEDIA)->statistics->attributes()->views."</views>".PHP_EOL; 
    echo "<pubDate>".$entry->published."</pubDate>".PHP_EOL; 
    echo "</item>".PHP_EOL; 
} 

Timing

echo "SimpleXML: " . (microtime(true) - $time_start) ."\n"; 
# SimpleXML: 0.0014688968658447 

XPATH(от @ThW)

$time_start = microtime(true); 

$xml = file_get_contents('YoutubeFeed.xml'); 
$document = new DOMDocument(); 
$document->loadXml($xml); 

$xpath = new DOMXpath($document); 
$xpath->registerNamespace('atom', 'http://www.w3.org/2005/Atom'); 
$xpath->registerNamespace('media', 'http://search.yahoo.com/mrss/'); 

foreach ($xpath->evaluate('//atom:entry') as $entry) { 
    echo "<item>".PHP_EOL; 
    echo "<title>". $xpath->evaluate('string(atom:title)', $entry)."</title>".PHP_EOL; 
    echo "<link>". $xpath->evaluate('string(atom:link/@href)', $entry)."</link>".PHP_EOL; 
    echo "<image>". $xpath->evaluate('string(media:thumbnail/@url)', $entry)."</image>".PHP_EOL; 
    echo "<description>". $xpath->evaluate('string(media:description)', $entry)."</description>".PHP_EOL; 
    echo "<guid>". $xpath->evaluate('string(media:guid)', $entry)."</description>".PHP_EOL; 
    echo "<views>".$xpath->evaluate('string(media:statistics/@views)', $entry)."</guid>".PHP_EOL; 
    echo "<pubDate>". $xpath->evaluate('string(atom:pubdate)', $entry)."</views>".PHP_EOL; 
    echo "</item>".PHP_EOL; 
} 

Хронометраж

echo "XPATH: " . (microtime(true) - $time_start) ."\n"; 
# XPATH: 0.0012829303741455 

XSLT

$time_start = microtime(true); 

$xml = file_get_contents('YoutubeFeed.xml'); 
$document = new DOMDocument(); 
$document->loadXml($xml); 

$xslstr = '<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" 
       xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" 
       exclude-result-prefixes="atom media"> 
<xsl:output version="1.0" encoding="UTF-8" indent="yes" /> 
<xsl:strip-space elements="*"/> 

    <xsl:template match="feed"> 
    <xsl:apply-templates select="atom:entry"/> 
    </xsl:template> 

    <xsl:template match="atom:entry"> 
     <item> 
     <title><xsl:value-of select="atom:title"/></title> 
     <link><xsl:value-of select="atom:link/@href"/></link> 
     <image><xsl:value-of select="atom:thumbnail/@url"/></image> 
     <description><xsl:value-of select="media:description"/></description> 
     <guid><xsl:value-of select="media:guid"/></guid> 
     <views><xsl:value-of select="media:statistics/@views"/></views> 
     <pubDate><xsl:value-of select="atom:pubdate"/></pubDate> 
     </item> 
    </xsl:template> 
</xsl:stylesheet>'; 

$xsl = new DOMDocument; 
$xsl->loadXML($xslstr); 

// Configure the transformer 
$proc = new XSLTProcessor; 
$proc->importStyleSheet($xsl); 

// Transform XML source 
$newXML = $proc->transformToXML($document); 

// Echo string output 
echo $newXML; 

Сроки

echo "XSLT: " . (microtime(true) - $time_start) ."\n"; 
# XSLT: 0.00098896026611328 

Даже с большим количеством узлов, <entry> копирование тега и детей до 500 строк, XSLT лучше масштабируется. Ниже приведены единицы измерения в секундах:

# SimpleXML: 0.62154388427734 

# XPATH: 0.68382000923157 

# XSLT: 0.011976957321167 
Смежные вопросы