views:

352

answers:

3

Hello.

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&lt;/url&gt;
         <image size="small">http://userserve-ak.last.fm/serve/34s/8696437.jpg&lt;/image&gt;
         <image size="medium">http://userserve-ak.last.fm/serve/64s/8696437.jpg&lt;/image&gt;
         <image size="large">http://userserve-ak.last.fm/serve/126/8696437.jpg&lt;/image&gt;
         <date uts="1236440600">7 Mar 2009, 15:43</date>
      </track>
      <track > 
         <artist mbid="f5b8ea5f-c269-45dd-9936-1fedf3c56851">The Presets</artist>
         <name>Get The Fuck 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+The+Fuck+Outta+Here&lt;/url&gt;
         <image size="small">http://userserve-ak.last.fm/serve/34s/20923179.png&lt;/image&gt;
         <image size="medium">http://userserve-ak.last.fm/serve/64s/20923179.png&lt;/image&gt;
         <image size="large">http://userserve-ak.last.fm/serve/126/20923179.png&lt;/image&gt;
         <date uts="1236440242">7 Mar 2009, 15:37</date>
      </track>
   </recenttracks>
</lfm>
A: 

Can you post the relevant XML fragment? We're looking at your code that parses it, but if we had the XML itself, it'd be easier to cons up an Xpath query. Most useful would be the bit that has elements like

<lfm>
    <recenttracks>
        <track>
            <album>

etc

Cheeso
done. the corresponding xml has been added to the question
xaddict
+2  A: 

Try this

 for (var i = 0; i < xmlDoc.getElementsByTagName('track').length; i++)
            {
                alert(xmlDoc.getElementsByTagName('track')[i].getElementsByTagName('name')[0].childNodes[0].nodeValue); 
            }


if you want to use xpath, you can also try the below solution.

var s = xmlDoc.evaluate( '//track' ,xmlDoc, null, XPathResult.ANY_TYPE, null );
var track = s.iterateNext();

while (track)
{
     alert(track.getElementsByTagName('name')[0].textContent );
     track = s.iterateNext();
}
gk
I want to use XPath, since it works much faster in Yahoo! Widgets. SO this is not really an option. Thanks anyway!
xaddict
Ok, try the seed value as 1 for the xpath index.
gk
I tried it just now and it seems both codes work in normal javascript but the first returns "TypeError: xmlDoc.getElementsByTagName("track")[0] has no properties" in Yahoo! Widgets. The second returns "function s.iterateNext does not exist"
xaddict
Can you pls post more details about Yahoo widget. And also are you sure you trying this on a Xml type object and not any custom yahoo type.
gk
A: 

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;
}
xaddict