Search code examples
vb.netxpathxmldocument

VB.Net XmlDocument.SelectNodes(xPath): unable to query WSDL


I'm trying to read the SOAP addresses from an Alfresco WSDL in VB.Net.

The XML looks like this:

<?xml version="1.0" encoding="utf-8"?>
<definitions xmlns:cmis="http://docs.oasis-open.org/ns/cmis core/200908/" xmlns:cmism="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:cmisw="http://docs.oasis-open.org/ns/cmis/ws/200908/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:ns="http://schemas.xmlsoap.org/soap/encoding/" targetNamespace="http://docs.oasis-open.org/ns/cmis/ws/200908/" xmlns:jaxws="http://java.sun.com/xml/ns/jaxws" name="CMISWebServices">
   ...
   <message name="cmisException">
       <part name="fault" element="cmism:cmisFault" />
   </message>
   ...
   <service name="ACLService">
       <port name="ACLServicePort" binding="cmisw:ACLServicePortBinding">
           <soap:address location="https://myserver:8443/alfresco/cmisws/ACLService" />
       </port>
   </service>
   ...

This is my VB.Net code. I'm trying to use XmlDocument.SelectNodes() with an XPath query ... and I'm having no joy.

    Dim xmlReader As System.Xml.XmlTextReader = New XmlTextReader(urlWsdl)
    Dim xmlWsdl As System.Xml.XmlDocument = New XmlDocument
    xmlWsdl.Load(xmlReader)
    ...
    Dim xPath As String = "/definitions/service[@name='" & sService & "']"
    Dim serviceNodes As XmlNodeList
    While True
        Try
            serviceNodes = xmlWsdl.SelectNodes(xPath)
            PrintMsg("Count=" & serviceNodes.Count)
        Catch ex As Exception
            Logger.LogMsg("ERROR: " & ex.Message)
        End Try
    End While
    ...

I need to get the address location for several different services from the WSDL: "ACLService", "DiscoveryService", "MultiFilingService", "NavigationService", etc.

I've tried many different XPath expressions, but I'm always getting "serviceNodes.Count" of "0":

Dim serviceNodes As XmlNodeList = xmlWsdl.SelectNodes(xPath):

XPath:                                    Count:   ServicesNodes(0).OuterXml:
-----                                     -----    -------------------------
//service[@name='ACLService']             0
//service[@name=ACLService]               0
//service                                 0
*                                         1        OuterXml: "<definitions ...>...  // Entire XML document
/definitions//service[@name=ACLService]   0
/definitions/service[@name='ACLService']  0
/definitions/service                      0

Q: What am I doing wrong?

Q: What can I do to fix it?

===================================================

Many thanks to har07, who correctly pointed out that I need to use an XmlNamespaceManager.

Here is the updated code:

Dim nsManager As New XmlNamespaceManager(New NameTable())
nsManager.AddNamespace("afws", xmlWsdl.DocumentElement.NamespaceURI)
Dim xPath As String = "/afws:definitions/afws:service[@name='" & sService & "']"
Dim serviceNodes As XmlNodeList = xmlWsdl.SelectNodes(xPath, nsManager) ' Now works perfectly!

Solution

  • "What am I doing wrong?"

    Your XPath didn't take the default namespace into account, the one declared without prefix here: xmlns="http://schemas.xmlsoap.org/wsdl/". (See Default Namespaces section in this MSDN article for more details).

    "What can I do to fix it?"

    Register mapping of prefix to the default namespace URI using XmlNamespaceManager, and then use the registered prefix properly in your XPath, for example :

    ....
    Dim nsManager As New XmlNamespaceManager(New NameTable())
    nsManager.AddNamespace("d", xmlWsdl.DocumentElement.NamespaceURI)
    Dim xPath As String = "/d:definitions/d:service[@name='" & sService & "']"
    ....
    serviceNodes = xmlWsdl.SelectNodes(xPath, nsManager)