1

I've been searching for a while on this and haven't had much luck. I've found plenty of resources showing how to echo data from dynamic XML, but I'm a PHP novice, and nothing I've written seems to grab and print exactly what I want, though from everything I've heard, it should be relatively easy. The source XML (located at 192.168.0.15:8080/requests/status.xml) is as follows:

<root>
  <fullscreen>0</fullscreen>
  <volume>97</volume>
  <repeat>false</repeat>
  <version>2.0.5 Twoflower</version>
  <random>true</random>
  <audiodelay>0</audiodelay>
  <apiversion>3</apiversion>
  <videoeffects>
  <hue>0</hue>
  <saturation>1</saturation>
  <contrast>1</contrast>
  <brightness>1</brightness>
  <gamma>1</gamma>
  </videoeffects>
  <state>playing</state>
  <loop>true</loop>
  <time>37</time>
  <position>0.22050105035305</position>
  <rate>1</rate>
  <length>168</length>
  <subtitledelay>0</subtitledelay>
  <equalizer/>
  <information>
  <category name="meta">
  <info name="description">
  000003EC 00000253 00000D98 000007C0 00009C57 00004E37 000068EB 00003DC5 00015F90 00011187
  </info>
  <info name="date">2003</info>
  <info name="artwork_url"> file://brentonshp04/music%24/Music/Hackett%2C%20Steve/Guitar%20Noir%20%26%20There%20Are%20Many%20Sides%20to%20the%20Night%20Disc%202/Folder.jpg
  </info>
  <info name="artist">Steve Hackett</info>
  <info name="publisher">Recall</info>
  <info name="album">Guitar Noir &amp; There Are Many Sides to the Night Disc 2
  </info>
  <info name="track_number">5</info>
  <info name="title">Beja Flor [Live]</info>
  <info name="genre">Rock</info>
  <info name="filename">Beja Flor [Live]</info>
  </category>
  <category name="Stream 0">
  <info name="Bitrate">128 kb/s</info>
  <info name="Type">Audio</info>
  <info name="Channels">Stereo</info>
  <info name="Sample rate">44100 Hz</info>
  <info name="Codec">MPEG Audio layer 1/2/3 (mpga)</info>
  </category>
  </information>
  <stats>
  <lostabuffers>0</lostabuffers>
  <readpackets>568</readpackets>
  <lostpictures>0</lostpictures>
  <demuxreadbytes>580544</demuxreadbytes>
  <demuxbitrate>0.015997290611267</demuxbitrate>
  <playedabuffers>0</playedabuffers>
  <demuxcorrupted>0</demuxcorrupted>
  <sendbitrate>0</sendbitrate>
  <sentbytes>0</sentbytes>
  <displayedpictures>0</displayedpictures>
  <demuxreadpackets>0</demuxreadpackets>
  <sentpackets>0</sentpackets>
  <inputbitrate>0.016695899888873</inputbitrate>
  <demuxdiscontinuity>0</demuxdiscontinuity>
  <averagedemuxbitrate>0</averagedemuxbitrate>
  <decodedvideo>0</decodedvideo>
  <averageinputbitrate>0</averageinputbitrate>
  <readbytes>581844</readbytes>
  <decodedaudio>0</decodedaudio>
  </stats>
  </root> 

What I'm trying to write is a simple PHP script that echoes the artist's name (In this example Steve Hackett). Actually I'd like it to echo the artist, song and album, but I'm confident that if I'm shown how to retrieve one, I can figure out the rest on my own.

What little of my script which actually seems to work goes as follows. I've tried more than what's below, but I left out the bits that I know for a fact aren't working.

<?PHP
$file = file_get_contents('http://192.168.0.15:8080/requests/status.xml');
$sxe = new SimpleXMLElement($file);

foreach($sxe->...

echo "Artist: "...

?>

I think I need to use foreach and echo, but I can't figure out how to do it in a way that will print what's between those info brackets.

I'm sorry if I've left anything out. I'm not only new to PHP, but I'm new to StackOverflow too. I've referenced this site in other projects, and it's always been incredibly helpful, so thanks in advance for your patience and help!

////////Finished Working Script - Thanks to Stefano and all who helped!

<?PHP
$file = file_get_contents('http://192.168.0.15:8080/requests/status.xml');
$sxe = new SimpleXMLElement($file);

$artist_xpath = $sxe->xpath('//info[@name="artist"]');
$album_xpath = $sxe->xpath('//info[@name="album"]');
$title_xpath = $sxe->xpath('//info[@name="title"]');


$artist = (string) $artist_xpath[0];
$album = (string) $album_xpath[0];
$title = (string) $title_xpath[0];


echo "<B>Artist: </B>".$artist."</br>";
echo "<B>Title: </B>".$title."</br>";
echo "<B>Album: </B>".$album."</br>";
?>

2 Answers2

2

Instead of using a for loop, you can obtain the same result with XPath:

// Extraction splitted across two lines for clarity
$artist_xpath = $sxe->xpath('//info[@name="artist"]');
$artist = (string) $artist_xpath[0];
echo $artist;

You will have to adjust the xpath expression (i.e. change @name=... appropriately), but you get the idea. Also notice that [0] is necessary because xpath will return an array of matches (and you only need the first) and the cast (string) is used to extract text contained in the node.

Besides, your XML is invalid and will be rejected by the parser because of the literal & appearing in the <info name="album"> tag.

Stefano Sanfilippo
  • 32,265
  • 7
  • 79
  • 80
  • +1 to picked up the mistake of `&` and greatly explained use of `[0]` as `xpath`'s returned value. – Smile May 11 '13 at 15:46
  • Thanks so much for the quick response!! Oh man, yeah I guess VLC will use the literal & character there when it auto generates. I can probably resolve that by going through my playlists and changing it manually wherever it occurs (hopefully not too often!) I'll resolve and test it as soon as I get home! – Brent Smith May 11 '13 at 16:38
  • 1
    VLC does use `&` inside the XML for `&` in filenames and titles just correctly. I assume this is a problem copying data into the question. Nice XML interface BTW. – hakre May 11 '13 at 21:16
  • Yep! You're right, I copy/pasted this from a browser window out of sheer laziness! Thanks for saving me more work! – Brent Smith May 11 '13 at 23:00
  • Thanks Stefano, I absolutely will! Testing now! I may be hindered by my own ignorance though... The script ended up like the above (See at the end of my original post), can you save me again by showing me where I went wrong? Once again thank you so much for your help! – Brent Smith May 11 '13 at 23:32
  • I added another example for you two here that shows how to move the suggested code *into* your own SimpleXMLElement which then makes the code more easy: http://stackoverflow.com/a/16512153/367456 – hakre May 12 '13 at 21:24
1

If you look at your code again, you are missing a function that turns the first result of the xpath expression into a string of a SimpleXMLElement (casting).

One way to write this once is to extend from SimpleXMLElement:

class BetterXMLElement extends SimpleXMLElement
{
    public function xpathString($expression) {
        list($result) = $this->xpath($expression);
        return (string) $result;
    }
}

You then create the more specific SimpleXMLElement like you did use the less specific before:

$file = file_get_contents('http://192.168.0.15:8080/requests/status.xml');
$sxe  = new BetterXMLElement($file);

And then you benefit in your following code:

$artist = $sxe->xpathString('//info[@name="artist"]');
$album  = $sxe->xpathString('//info[@name="album"]');
$title  = $sxe->xpathString('//info[@name="title"]');

echo "<B>Artist: </B>".$artist."</br>";
echo "<B>Title: </B>".$title."</br>";
echo "<B>Album: </B>".$album."</br>";

This spares you some repeated code. This means as well less places you can make an error in :)

Sure you can further on optimize this by allowing to pass an array of multiple xpath queries and returning all values named then. But that is something you need to write your own according to your specific needs. So use what you learn in programming to make programming more easy :)

If you want some more suggestions, here is another, very detailed example using DOMDocument, the sister-library of SimpleXML. It is quite advanced but might give you some good inspiration, I think something similar is possible with SimpleXML as well and this is probably what you're looking for in the end:

Community
  • 1
  • 1
hakre
  • 193,403
  • 52
  • 435
  • 836
  • Thx & Yes, it is very little known that you can easily extend the *SimpleXMLElement* (or the *SimpleXMLIterator*) and add needed functionality at a central place. Works also with `simplexml_load_string()` or [`simplexml_load_file()`](http://php.net/simplexml_load_file) using the second parameter. – hakre May 12 '13 at 21:39