0

I am trying to read xml nodes values from lastfm web service that look like this:

<lfm status="ok"> 
<results for="stinkfist" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"> 
<opensearch:Query role="request" searchTerms="stinkfist" startPage="1" /> 
<opensearch:totalResults>188</opensearch:totalResults> 
<opensearch:startIndex>0</opensearch:startIndex> 
<opensearch:itemsPerPage>1</opensearch:itemsPerPage> 
<trackmatches> 
<track> 
    <name>Stinkfist</name> 
    <artist>Tool</artist> 
    <url>http://www.last.fm/music/Tool/_/Stinkfist</url> 
    <streamable fulltrack="0">1</streamable> 
    <listeners>290583</listeners> 
         <image size="small">http://userserve-ak.last.fm/serve/34s/24508457.jpg</image> 
    <image size="medium">http://userserve-ak.last.fm/serve/64s/24508457.jpg</image> 
    <image size="large">http://userserve-ak.last.fm/serve/126/24508457.jpg</image> 
    <image size="extralarge">http://userserve-ak.last.fm/serve/300x300/24508457.jpg</image> 
 <mbid></mbid> 
</track> 
</trackmatches> 
</results>
</lfm>

After searching here and on the web for examples i found a way that should work:

 Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
    Dim doc As XmlDocument
    Dim ns As XmlNamespaceManager
    Dim nodes As XmlNodeList
    doc = New XmlDocument()
    doc.Load("http://ws.audioscrobbler.com/2.0/?method=track.search&limit=1&track=stinkfist&artist=tool&api_key=b25b959554ed76058ac220b7b2e0a026")
    ns = New XmlNamespaceManager(doc.NameTable)
    ns.AddNamespace("lastfm", "http://a9.com/-/spec/opensearch/1.1/")
    nodes = doc.SelectNodes("lastfm:results/lastfm:trackmatches/lastfm:track", ns)
    Dim str As String = String.Empty
    For Each node As XmlNode In nodes
        str += node.Attributes("name").InnerText
        str += node.Attributes("artist").InnerText
        str += node.Attributes("url").InnerText
        str += node.Attributes("listeners").InnerText
    Next

    Response.Write(str)

End Sub

But when i run the page i get no results the page is empty... what am i doing wrong?

tone
  • 1,535
  • 3
  • 15
  • 20

2 Answers2

1

According to the XML you showed us, <results>, <trackmatches> and <track> are in no namespace. But you're trying to find them in the opensearch namespace. Even though <results> has a namespace declaration, only elements (or attributes) that use the opensearch: namespace prefix are actually in that namespace.

So you need to remove the namespace prefixes from

nodes = doc.SelectNodes("lastfm:results/lastfm:trackmatches/lastfm:track", ns)

I.e. change it to (deleted; see below)

Update: Reflecting edits to the input XML: since the top-level element is not <results> but <lfm>, do

nodes = doc.SelectNodes("/*/results/trackmatches/track")

See also @Garett's good points about trying to select child elements as if they were attributes.

LarsH
  • 27,481
  • 8
  • 94
  • 152
  • did it but still no results...maybe other way to get these nodes values? – tone Oct 22 '10 at 12:16
  • 1
    and @tone: According to [this](http://www.lastfm.es/api/rest) response has not default namespace. So @LarsH answer is in the right direction. But it should be: `/lfm/results/trackmatches/track` –  Oct 22 '10 at 13:50
  • 1
    @tone, I've edited my answer now to reflect your changes in the input XML. – LarsH Oct 22 '10 at 21:41
1

There are a couple of issues that I see.

First, you don't need to add the namespace lastfm only opensearch (if you need to access those elements).

So this line:

ns.AddNamespace("lastfm", "http://a9.com/-/spec/opensearch/1.1/")

Would become:

ns.AddNamespace("opensearch", "http://a9.com/-/spec/opensearch/1.1/")

If you needed to access the opensearch elements you would then use it like:

doc.SelectSingleNode("lfm/results/opensearch:totalResults", ns).InnerText

To select the track nodes your XPath query should be:

nodes = doc.SelectNodes("/lfm/results/trackmatches/track")

The track nodes do not have attributes, so node.Attributes("name").InnerText will not work. Rather, they have child elements (nodes), so to get those values you can do:

node.SelectSingleNode("name").InnerText

or even shorter syntax

node("name").InnerText

Putting it all together, your program would resemble the following:

Dim doc As XmlDocument
Dim ns As XmlNamespaceManager
Dim nodes As XmlNodeList

doc = New XmlDocument()
doc.Load("http://ws.audioscrobbler.com/2.0/?method=track.search&track=Believe&api_key=b25b959554ed76058ac220b7b2e0a026")
ns = New XmlNamespaceManager(doc.NameTable)
ns.AddNamespace("opensearch", "http://a9.com/-/spec/opensearch/1.1/")
nodes = doc.SelectNodes("/lfm/results/trackmatches/track")
Dim str As String = String.Empty
For Each node As XmlNode In nodes
    str += node.SelectSingleNode("name").InnerText
    str += node.SelectSingleNode("artist").InnerText
    str += node.SelectSingleNode("url").InnerText
    str += node.SelectSingleNode("listeners").InnerText
Next

Lastly, MSDN has very good examples of using XPath and XmlDocument, which you may find useful.

Garett
  • 16,632
  • 5
  • 55
  • 63