xmlxpathchildrenyahoo-widgets

How to use Xpath in Yahoo! Widgets to traverse a tree?


I'm creating a Yahoo! Widget and have done this before without any problems (creating a widget). I'm getting a xml document via a weblink and want to get all the nodes intro a tree. I'm doing this:

var request = new XMLHttpRequest();
        request.open( "GET", url, false );
        request.send();
        if ( request.status == 200 )
        {
            doc = request.responseXML;
            tree = doc.evaluate("/lfm");
            status = tree.item(0).getAttribute("status")
            if(status == "ok")
            {
                print ("status is ok!");
                tracks = doc.evaluate("/lfm/recenttracks[1]/track");
                for(i=0;i<tracks.length;i++)
                {
                    artist = tracks.item(i).firstChild.firstChild.data;
                }
            }
        }
    }

This way you can get the node artist out of the tree. there's a problem though if you want to have the next sibling. You have to call

tracks.item(i).firstChild.nextSibling.firstChild.data;
tracks.item(i).firstChild.nextSibling.nextSibling.firstChild.data;
tracks.item(i).firstChild.nextSibling.nextSibling.nextSibling.firstChild.data;

to get this done. The node next to that adds a 'nextsibling' to it and so on. I do not want to keep on adding these nodes and thought it would be possible to use childNodes[i] like this:

artist = tracks.item(i).childNodes[0].firstChild.data;
nextitem = tracks.item(i).childNodes[1].firstChild.data;

this doesn't work though. it returns "childNodes[0] has no properties" in whatever way I use it. Now I think there's also a way in Xpath to do this in a for-loop:

name = doc.evaluate("string(/lfm/recenttracks[1]/track["+i+"]/name)");
                    print(name);
othernode = doc.evaluate("string(/lfm/recenttracks[1]/track["+i+"]/album)");
                    print(othernode);

and then increasing i for the next track. but somehow this returns only one item. it doesn't retrieve more items in a for-loop. i-1 doesn't work either.

Anyone knows how to use a Xpath expression with my i value to choose a node and then get the subnodes per supernode? Per track I want to get artist, name, streamable, mbid, album, url, image(small), image(medium), image(large) and date.

my xml file looks like this:

<lfm status="ok">
   <recenttracks user="xaddict">
      <track nowplaying="true"> 
         <artist mbid="f5b8ea5f-c269-45dd-9936-1fedf3c56851">The Presets</artist>
         <name>Girl (You Chew My Mind Up)</name>
         <streamable>1</streamable>
         <mbid></mbid>
         <album mbid="b150d099-b0f3-4feb-9a05-34e693c6dd24">Beams</album>
         <url>http://www.last.fm/music/The+Presets/_/Girl+%28You+Chew+My+Mind+Up%29</url>
         <image size="small">http://userserve-ak.last.fm/serve/34s/8696437.jpg</image>
         <image size="medium">http://userserve-ak.last.fm/serve/64s/8696437.jpg</image>
         <image size="large">http://userserve-ak.last.fm/serve/126/8696437.jpg</image>
         <date uts="1236440600">7 Mar 2009, 15:43</date>
      </track>
      <track > 
         <artist mbid="f5b8ea5f-c269-45dd-9936-1fedf3c56851">The Presets</artist>
         <name>Get Outta Here</name>
         <streamable>1</streamable>
         <mbid></mbid>
         <album mbid="0469956f-d895-4120-8ec5-29ad41b9e2fd">Blow Up</album>
         <url>http://www.last.fm/music/The+Presets/_/Get+Outta+Here</url>
         <image size="small">http://userserve-ak.last.fm/serve/34s/20923179.png</image>
         <image size="medium">http://userserve-ak.last.fm/serve/64s/20923179.png</image>
         <image size="large">http://userserve-ak.last.fm/serve/126/20923179.png</image>
         <date uts="1236440242">7 Mar 2009, 15:37</date>
      </track>
   </recenttracks>
</lfm>

Solution

  • the fully Xpath-enabled way of doing this is using the string conversion in Xpath. Ive already posted this code as an answer to another question and will do this again. I'm very glad I found out about this way of doing things.

    var entries = xmlDoc.evaluate("lfm/recenttracks/track");
    var length = entries.length;
    for(var i = 0; i &lt; length; i++) {
       var entry = entries.item(i);
       var obj = {
          artist: entry.evaluate("string(artist)"),
          name: entry.evaluate("string(name)"),
          url: entry.evaluate("string(url)"),
          image: entry.evaluate("string(image[@size='medium'])")
       };
    posts[i] = obj;
    }