Разбор на XML с помощта на PHP

Постоянно имах проблем с анализирането на XML с PHP и наистина не намерих "правилния начин" или поне стандартизиран начин за анализиране на XML файлове.

Първо се опитвам да анализирам това:

  <item> 
     <title>2884400</title> 
     <description><![CDATA[ ><img width="126" alt="" src="http://userserve-ak.last.fm/serve/126/27319921.jpg" /> ]]></description> 
     <link>http://www.last.fm/music/+noredirect/Beatles/+images/27319921</link> 
     <author>anne710</author> 
     <pubDate>Tue, 21 Apr 2009 16:12:31 +0000</pubDate> 
     <guid>http://www.last.fm/music/+noredirect/Beatles/+images/27319921</guid> 
     <media:content url="http://userserve-ak.last.fm/serve/_/27319921/Beatles+2884400.jpg" fileSize="13065" type="image/jpeg" expression="full"  width="126" height="126" /> 
     <media:thumbnail url="http://userserve-ak.last.fm/serve/126/27319921.jpg" type="image/jpeg" width="126" height="126" /> 
  </item> 

Използвам този код:

$doc = new DOMDocument();
$doc->load('http://ws.audioscrobbler.com/2.0/artist/beatles/images.rss');
$arrFeeds = array();
foreach ($doc->getElementsByTagName('item') as $node) {
    $itemRSS = array ( 
        'title' => $node->getElementsByTagName('title')->item(0)->nodeValue,
        'desc' => $node->getElementsByTagName('description')->item(0)->nodeValue,
        'link' => $node->getElementsByTagName('link')->item(0)->nodeValue,
        'date' => $node->getElementsByTagName('pubDate')->item(0)->nodeValue
        );
    array_push($arrFeeds, $itemRSS);
}

Сега искам да получа url атрибутите "media:content" и "media:thumbnail", как да направя това? Сега мисля, че трябва да използвам DOMElement::getAttribute, но не успях да го накарам да работи :/ Може ли някой да хвърли малко светлина върху това и също така да ме уведоми дали това е добър начин за анализиране на XML?

Поздрави, Шади


person Shadi Almosri    schedule 13.07.2009    source източник
comment
Целият този въпрос/тема е доста лош. Проблемът е липсата на разбиране на пространствата от имена. Предлагам на всеки, който чете това, да научи за пространствата от имена на XML. Хората са споменали това по-долу. Проблемът е, че media:content означава тагът „content“, който принадлежи към пространството от имена „media“, а не към пространството от имена по подразбиране (което е това, срещу което правите заявки).   -  person Jotham    schedule 11.02.2010


Отговори (8)


Можете да използвате SimpleXML, както е предложено от другите автори, но трябва да използвате children() и атрибутите () функции, така че можете да работите с различните пространства от имена

Пример (непроверен):

$feed = file_get_contents('http://ws.audioscrobbler.com/2.0/artist/beatles/images.rss');
$xml = new SimpleXMLElement($feed);
foreach ($xml->channel->item as $item) {
    foreach ($item->children('http://search.yahoo.com/mrss' as $media_element) {
        var_dump($media_element);
    }
}

Като алтернатива можете да използвате XPath (отново нетествано):

$feed = file_get_contents('http://ws.audioscrobbler.com/2.0/artist/beatles/images.rss');
$xml = new SimpleXMLElement($feed);
$xml->registerXPathNamespace('media', 'http://ws.audioscrobbler.com/2.0/artist/beatles/images.rss');
$images = $xml->xpath('/rss/channel/item/media:content@url');
var_dump($images);
person Sander Marechal    schedule 13.07.2009

Опитайте тази. Ще работи добре.

$doc = new DOMDocument();
$doc->load('http://ws.audioscrobbler.com/2.0/artist/beatles/images.rss');
$arrFeeds = array();
foreach ($doc->getElementsByTagName('item') as $node) {
    $itemRSS = array ( 
        'title' => $node->getElementsByTagName('title')->item(0)->nodeValue,
        'desc' => $node->getElementsByTagName('description')->item(0)->nodeValue,
        'link' => $node->getElementsByTagName('link')->item(0)->nodeValue,
        'date' => $node->getElementsByTagName('pubDate')->item(0)->nodeValue,
        'thumbnail' => $node->getElementsByTagName('thumbnail')->item(0)->getAttribute('url')
    );
    array_push($arrFeeds, $itemRSS);
}
person Helder Robalo    schedule 21.01.2010

Ето как в крайна сметка го направих с помощта на XMLReader:

<?php

define ('XMLFILE', 'http://ws.audioscrobbler.com/2.0/artist/vasco%20rossi/images.rss');
echo "<pre>";

$items = array ();
$i = 0;

$xmlReader = new XMLReader();
$xmlReader->open(XMLFILE, null, LIBXML_NOBLANKS);

$isParserActive = false;
$simpleNodeTypes = array ("title", "description", "media:title", "link", "author", "pubDate", "guid");

while ($xmlReader->read ())
{
    $nodeType = $xmlReader->nodeType;

    // Only deal with Beginning/Ending Tags
    if ($nodeType != XMLReader::ELEMENT && $nodeType != XMLReader::END_ELEMENT) { continue; }
    else if ($xmlReader->name == "item") {
        if (($nodeType == XMLReader::END_ELEMENT) && $isParserActive) { $i++; }
        $isParserActive = ($nodeType != XMLReader::END_ELEMENT);
    }

    if (!$isParserActive || $nodeType == XMLReader::END_ELEMENT) { continue; }

    $name = $xmlReader->name;

    if (in_array ($name, $simpleNodeTypes)) {
        // Skip to the text node
        $xmlReader->read ();
        $items[$i][$name] = $xmlReader->value;
    } else if ($name == "media:thumbnail") {
        $items[$i]['media:thumbnail'] = array (
                "url" => $xmlReader->getAttribute("url"),
                "width" => $xmlReader->getAttribute("width"),
                "height" => $xmlReader->getAttribute("height"),
                "type" => $xmlReader->getAttribute("type")
        );
    } else if ($name == "media:content") {
        $items[$i]['media:content'] = array (
                "url" => $xmlReader->getAttribute("url"),
                "width" => $xmlReader->getAttribute("width"),
                "height" => $xmlReader->getAttribute("height"),
                "filesize" => $xmlReader->getAttribute("fileSize"),
                "expression" => $xmlReader->getAttribute("expression")
        );
    }
}

print_r($items);
echo "</pre>";

?>
person Shadi Almosri    schedule 14.07.2009

Опитайте да използвате SimpleXML: http://us2.php.net/simplexml

person catsby    schedule 13.07.2009
comment
пускането на данните през simplexml изглежда не помага, не улавя нищо от ‹media:content и ‹media:thumbnail съдържание, само останалото - person Shadi Almosri; 14.07.2009
comment
Предложих и SimpleXML - person ist_lion; 14.07.2009

Бихте искали нещо подобно:

'content' => $node->getElementsByTagNameNS('http://search.yahoo.com/mrss/', 'content')->item(0)->getAttribute('url');
'thumbnail' => $node->getElementsByTagNameNS('http://search.yahoo.com/mrss/', 'thumbnail')->item(0)->getAttribute('url');

Вярвам, че ще проработи, мина известно време, откакто съм правил нещо подобно.

person Craig Martek    schedule 13.07.2009
comment
‹rss версия=2.0 xmlns:creativeCommons=backend.userland.com/creativeCommonsRssModule xmlns:media=search.yahoo.com/mrss› така че как да приложим това?! - person Shadi Almosri; 14.07.2009
comment
[Mon Jul 13 23:13:04 2009] [грешка] [клиент xxx.xxx.xxx.xxx] PHP Фатална грешка: Извикване на членска функция getAttribute() на не-обект в /v2.php на ред 73 - person Shadi Almosri; 14.07.2009
comment
Това е добро решение, има само едно объркващо нещо; getElementsByTagNameNS обикновено не е свързан с $node (което е част от итерация), но е свързан с XML Document Root, с основния DOM обект. Ако променлива $xml = new DOMDocument(); тогава ще работи така: $content = $xml->getElementsByTagNameNS('http://search.yahoo.com/mrss/', 'content')->item($i); - person Tamas Kalman; 10.08.2010

Може да получите грешката Call to a member function getAttribute() on a non-object, ако във фийд липсват записи като thumbnail, така че макар да харесвам отговора на @Helder Robalo, трябва да проверите дали съществува възел, преди да опитате да използвате неща като getAttribute():

<?php

header('Content-type: text/plain; charset=utf-8');

$doc = new DOMDocument();
$doc->load('http://ws.audioscrobbler.com/2.0/artist/beatles/images.rss');
$arrFeeds = array();
foreach ($doc->getElementsByTagName('item') as $node) {
    $itemRSS = array (
        'title' => $node->getElementsByTagName('title')->item(0)->nodeValue,
        'desc' => $node->getElementsByTagName('description')->item(0)->nodeValue,
        'link' => $node->getElementsByTagName('link')->item(0)->nodeValue,
        'date' => $node->getElementsByTagName('pubDate')->item(0)->nodeValue
    );

    if( sizeof($node->getElementsByTagName('thumbnail')->item(0)) > 0 )
    {
        $itemRSS['thumbnail'] = $node->getElementsByTagName('thumbnail')->item(0)->getAttribute('url');
    }
    else
    {
        $itemRSS['thumbnail'] = '';
    }

    array_push($arrFeeds, $itemRSS);
}


print_r($arrFeeds);
person cwd    schedule 13.07.2013

Media:content атрибутите всъщност са доста лесни за получаване с SIMPLE XML

if(!@$x=simplexml_load_file($feed_url)){

}
else
{
  foreach($x->channel->item as $entry)
  {
    $media = $entry->children('http://search.yahoo.com/mrss/')->attributes();
    $url = (string) $media['url'];
  }
}
person Tom Tom    schedule 08.11.2013

person    schedule
comment
хммм, това наистина не работи, опитах се да поставя url вместо $_POST, но не получава файла, поставих файла в променлива и го предадох на simplexmlelement, но все още нямаше нищо вътре $ елемент. - person Shadi Almosri; 14.07.2009
comment
Това всъщност беше част от кодов фрагмент от моя код. Трябва да спомена, че трябва да промените $xml-›item, тъй като се отнася до xml емисията, която получавате. Бих погледнал документацията на SimpleXMLElement - но това е, което използвам за работа с XML, който изпращам от Adobe Flex - person ist_lion; 14.07.2009