asp.netxmlxpathselectnodes

ASP.NET Select XML nodes based on attribute value in child element


I'm trying to loop through the XML below and find all entry elements where the underlying category element has the value collection for thr term attribute. There are 2 in the example below. And then for those get the value of the href attribute on the link element. However, I can't seem to find the right selectors:

<feed xmlns="http://www.w3.org/2005/Atom">
    <title>demo</title>
    <id>urn:uuid:071d9650-ae6c-11e7-8f1a-0800200c9a66</id>
    <link rel="self" href="https://test.com/atom/index.xml"/>
    <updated>2017-10-11T14:37:33+02:00</updated>
    <author>
        <name>Test</name>
        <uri>http://www.test.com</uri>
    </author>
    <generator version="1.8">Agent</generator>
    <entry>
        <title>YDEMO</title>
        <id>urn:uuid:15f44340-ae6c-11e7-8f1a-0800200c9a66</id>
        <category term="collection"/>
        <published>2017-10-11T13:41:53+02:00</published>
        <updated>2017-10-11T14:37:33+02:00</updated>
        <link rel="alternate" href="https://www.myurl.com" type="text/xml"/>
        <mcp:projectScenario xmlns:mcp="http://webservice.yes-co.nl/3mcp/1.5/atom-extension">NBvh</mcp:projectScenario>
    </entry>
    <entry>
        <title>DEMO 2</title>
        <id>urn:uuid:25f44340-ae6c-11e7-8f1a-0800200c9a00</id>
        <category term="collection"/>
        <published>2017-10-11T13:42:53+02:00</published>
        <updated>2017-10-11T14:38:33+02:00</updated>
        <link rel="alternate" href="https://www.myurl2.com" type="text/xml"/>
        <mcp:projectScenario xmlns:mcp="http://webservice.yes-co.nl/3mcp/1.5/atom-extension">BBvh</mcp:projectScenario>
    </entry>
    <entry>
        <title>photo</title>
        <id>12</id>
        <category term="metadata"/>
        <updated>2016-10-11T14:38:33+02:00</updated>
        <link rel="alternate" href="https://www.myurl2.com" type="text/xml"/>
    </entry>
    <entry
        xmlns:mcp="http://webservice.yes-co.nl/3mcp/1.5/atom-extension">
        <title>No title</title>
        <id>urn:uuid:6d65c57f-621f-4c15-8a1d-5dc967423d5d</id>
        <category term="media"/>
        <published>2017-10-11T13:39:43+02:00</published>
        <updated>2017-10-11T13:39:43+02:00</updated>
        <link
            xmlns:mcp="http://webservice.yes-co.nl/3mcp/1.5/atom-extension" rel="related" href="https://webservice.yes-co.com/3mcp/1.5/15f44340-ae6c-11e7-8f1a-0800200c9a66/media/6d65c57f-621f-4c15-8a1d-5dc967423d5d-large.jpg" type="image/jpg" mcp:mediaFormat="large"/>
    </entry>        
</feed>

Here's my code so far, but even though the data variable contains the above XML, the nodeList.Count line returns 0 results:

    Dim WC As New WebClient
    Dim data As String = WC.DownloadString("http://localhost/index.xml")

    Dim indexXML As New XmlDocument
    indexXML.LoadXml(data)

    Dim mgr As XmlNamespaceManager = New XmlNamespaceManager(indexXML.NameTable)
    mgr.AddNamespace("http://www.w3.org/2005/Atom", indexXML.DocumentElement.NamespaceURI)

    Dim node As XmlNode

    Dim root As XmlNode = indexXML.DocumentElement
    Dim nodeList As XmlNodeList = root.SelectNodes("/feed/entry")

    'now loop through all elements  with "category term=collection" in index.xml
    For i As Integer = 0 To nodeList.Count - 1
        If nodeList(i).SelectSingleNode("/category/@term=collection") IsNot Nothing Then
            LogMessage(nodeList(i).SelectSingleNode("/category/link/@href").Value)
        End If
    Next i  

UPDATE 1
I want to select all 'entry' elements where it has a category node with term=collection. That part works through this statement: indexXML.SelectNodes("/atom:feed/atom:entry[atom:category/@term=""collection""]", mgr)

I want to start from the entry node and then I want to select the href attribute of subelement link of entry (and in the future other child elements of entry. However, none of the examples I tried below, return the value of the href attribute. How can I fix that?

I now have this:

Dim mgr As XmlNamespaceManager = New XmlNamespaceManager(indexXML.NameTable)
mgr.AddNamespace("atom", "http://www.w3.org/2005/Atom")

Dim root As XmlNode = indexXML.DocumentElement
Dim nodeList As XmlNodeList = indexXML.SelectNodes("/atom:feed/atom:entry[atom:category/@term=""collection""]", mgr)

'now loop through all collections in index.xml

For i As Integer = 0 To nodeList.Count - 1 '1 result found

'NONE OF CALLS BELOW RETURN THE VALUE OF HREF ATTRIBUTE
    If nodeList(i).SelectSingleNode("atom:/link/@href", mgr) IsNot Nothing Then
        LogMessage(nodeList(i).SelectSingleNode("atom:/link/@href", mgr).Value)
'error: 'atom:/link/@href' has an invalid qualified name.
    End If
Next i

UPDATE 2 Thanks to @Pawel I was able to select all entry nodes that have project as value for the term attribute on category node like so:

objectsXML.SelectNodes("/atom:feed/atom:entry[atom:category/@term=""project""]", mgr)

However, how can I add an additional criterium to this selector to filter out entry nodes that have value NBvh OR BBvh for node mcp:projectScenario?

UPDATE 3 I added an additional namespace to the manager:

mgr.AddNamespace("atom", "http://www.w3.org/2005/Atom")
mgr.AddNamespace("mcp", "http://webservice.yes-co.nl/3mcp/1.5/atom-extension")

But when I try to select the href attribute of the media element by uuid, I get the error: Object reference not set to an instance of an object.

My code:

objectsXML.SelectSingleNode("/atom:feed/atom:entry[atom:id=""urn:uuid:" + "6d65c57f-621f-4c15-8a1d-5dc967423d5d" + """]/mcp:link/@href", mgr).InnerText

Solution

  • The document uses the http://www.w3.org/2005/Atom namespace. You need to bind this namespace to a uri prefix and use this prefix in your XPath. If you bind the namespace to the atom prefix like this:

    var nsmanager = new XmlNamespaceManager(indexXML.NameTable);
    nsmanager.AddNamespace("atom", "http://www.w3.org/2005/Atom");
    

    You will be able to use this prefix in your XPath expressions if you pass the namespace manager e.g.:

    indexXML.SelectNodes("/atom:feed/atom:entry[atom:category/@term="collection"]/atom:link/@href", nsmanager)