Search code examples
.netxmlvb.netnamespacesprefix

Parse XML with namespace prefix in vb .net


I am pretty new to vb .net and it has been a very long time since I dealt with XML parsing.

I got the following XML file:

<?xml version="1.0" encoding="ISO-8859-15"?>
<tns:keyitem_list_test xmlns:tns="http://someurl.com/abc/def">
  <tns:name>test.keyitem</tns:name>
  <tns:type>test.IKeyItemListDataObject</tns:type>
  <tns:keyitem>
    <tns:cataloge>testCat</tns:cataloge>
    <tns:seq_nr>1</tns:seq_nr>
    <tns:keyvalue>01</tns:keyvalue>
    <tns:keyvalue_alt>test1</tns:keyvalue_alt>
    <tns:keytext>test text 1</tns:keytext>
    <tns:keyhelpertext />
    <tns:is_temp>false</tns:is_temp>
  </tns:keyitem>
  <tns:keyitem>
    <tns:cataloge>testCat</tns:cataloge>
    <tns:seq_nr>2</tns:seq_nr>
    <tns:keyvalue>02</tns:keyvalue>
    <tns:keyvalue_alt>test2</tns:keyvalue_alt>
    <tns:keytext>test text 2</tns:keytext>
    <tns:keyhelpertext />
    <tns:is_temp>false</tns:is_temp>
  </tns:keyitem>
...
</tns:keyitem_list_test>

The XML is returned from a POST request and saved in a variable. I want to extract all tns:keyvalue tags.

Dim doc = New Xml.XmlDocument()
doc.LoadXml(retVal.return)

Dim nsm = New Xml.XmlNamespaceManager(doc.NameTable)
nsm.AddNamespace("tns", "http://someurl.com/abc/def")
Dim value = doc.SelectSingleNode("/tns:keyvalue", nsm).InnerText

My problem is that value is always "Nothing". I tried different things but none work and I have no clue why. I think it has something to do with the namespace prefixes.


Solution

  • The immediate problem is in your XPath expression:

    Dim value = doc.SelectSingleNode("/tns:keyvalue", nsm).InnerText
    

    That's only looking for a root element called keyvalue. If you change it to look for descendants, you'll find the first keyvalue node:

    Dim value = doc.SelectSingleNode("//tns:keyvalue", nsm).InnerText
    

    Or to look for all nodes rather than just the first:

    Dim nodes = doc.SelectNodes("//tns:keyvalue", nsm)
    For Each node as Xml.XmlNode in nodes
        Console.WriteLine(node.InnerText)
    Next
    

    However, if you can, I'd recommend using LINQ to XML, which has much cleaner namespace support, and better support for querying without using XPath:

    Dim doc = XDocument.Parse(retVal.return)
    Dim ns As XNamespace = "http://someurl.com/abc/def"
    Dim elements = doc.Descendants(ns + "keyvalue")
    For Each element in elements
        Console.WriteLine(element.Value)
    Next