Shadi Almosri
Shadi Almosri

Reputation: 11989

Parsing XML using PHP

I've consistently had an issue with parsing XML with PHP and not really found "the right way" or at least a standardised way of parsing XML files.

Firstly i'm trying to parse this:

  <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> 

I'm using this code:

$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);
}

Now I want to get the "media:content" and "media:thumbnail" url attributes, how would i do that? Now i think i should be using DOMElement::getAttribute but i haven't managed to get it to work :/ Can anyone shed some light on this, and also let me know if this is a good way to parse XML?

Regards, Shadi

Upvotes: 2

Views: 14339

Answers (8)

Tom Tom
Tom Tom

Reputation: 3698

Media:content attributes are actually pretty easy to get with 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'];
  }
}

Upvotes: 0

cwd
cwd

Reputation: 54846

You may get the error Call to a member function getAttribute() on a non-object if a feed is missing entries like thumbnail, so while I like @Helder Robalo's answer you should check to make sure a node exists before trying to use things like 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);

Upvotes: 0

Helder Robalo
Helder Robalo

Reputation: 31

Try this. It'll work fine.

$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);
}

Upvotes: 3

Shadi Almosri
Shadi Almosri

Reputation: 11989

This was how i have eventually done it using 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>";

?>

Upvotes: 2

Craig Martek
Craig Martek

Reputation: 284

You would want something like this:

'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');

I believe that will work, it's been a while since I've done anything like this.

Upvotes: 0

Sander Marechal
Sander Marechal

Reputation: 23216

You can use SimpleXML as suggested by the other posters, but you need to use the children() and attributes() functions so you can deal with the different namespaces

Example (untested):

$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);
    }
}

Alternatively, you can use XPath (again, untested):

$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);

Upvotes: 4

catsby
catsby

Reputation: 11352

Try using SimpleXML: https://www.php.net/simplexml

Upvotes: 0

ist_lion
ist_lion

Reputation: 3209

<?php

#Convert the String Into XML
$xml = new SimpleXMLElement($_POST['name']);

#Itterate through the XML for the data 

$values = "VALUES('' , ";
foreach($xml->item as $item)
{
 //you now have access to that aitem
}

?>

Upvotes: 0

Related Questions