0

I have this XML SOAP response from a server that I don't control:

            <s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
                <s:Body>
                    <GetResponse xmlns="http://Door.Application.DataService/">
                        <GetResult>C5465781005937173259</GetResult>
                    </GetResponse>
                </s:Body>
            </s:Envelope>

I am using this C# code to try to extract the text from the GetResult element:

    // xdoc is an XmlDocument with the above XML contained within
    XmlDocument xdoc = ...

    // Add namespace manager
    var nsmgr = new XmlNamespaceManager(xdoc.NameTable);
    nsmgr.AddNamespace("", "http://Door.Application.DataService/"); 
    nsmgr.AddNamespace("s", "http://schemas.xmlsoap.org/soap/envelope/");

    XmlNode titleNode = xdoc.SelectSingleNode("/s:Envelope/s:Body/GetResult/GetResponse", nsmgr);

If I query just the "s" namespace prefixed element, then I do get the result in titleNode. But if I try to get specific about it and include the GetResult and/or GetResponse elements, I always get null in the titleNode variable.

I can find many articles about C# XPath with namespaces and with just the default namespace but I can't find anything where part of the XML has an explicit namespace and part of it has the default namespace.

Yitzhak Khabinsky
  • 18,471
  • 2
  • 15
  • 21
jwh20
  • 646
  • 1
  • 5
  • 15
  • 1
    Just making sure you do understand that namespace prefixes in the XML and in XPath are *absolutely unrelated* to each other (your attempt to have them matching in the code looks quite suspicios). – Alexei Levenkov Jul 24 '23 at 17:27
  • Could you explain that a bit? If I leave out the namespace, i.e. the "s", then I also get null. – jwh20 Jul 24 '23 at 17:29
  • 1
    With your XPath 1.0 API, you anyway, in your C# code, need to use a prefix for any elements in a namespace so use e.g. `nsmgr.AddNamespace("ds", "http://Door.Application.DataService/");` and then just use that prefix `xdoc.SelectSingleNode("/s:Envelope/s:Body/ds:GetResult/ds:GetResponse", nsmgr);` – Martin Honnen Jul 24 '23 at 17:33
  • jwh20 - no sorry - I don't know how to *explain* that... Maybe try https://learn.microsoft.com/en-us/dotnet/standard/data/xml/xpath-queries-and-namespaces (even if it may not help with explanation in general at least tells you not to use empty prefix). Note that `` is valid XML - maybe that could be enlightening. – Alexei Levenkov Jul 24 '23 at 17:35
  • @MartinHonnen Yes, that worked. If you could please post this as an answer and include a bit of an explanation as to why this works, I'll accept it. Thanks! – jwh20 Jul 24 '23 at 17:39
  • The prefix defined for a namespace in the XML and the prefix defined for a namespace in the namespace manager used with the XPath don't need to match and are unrelated. – Jonathan Dodds Jul 24 '23 at 17:39
  • 1
    The prefixes you use for `nsmgr.AddNamespace(prefix, url)` don't need to be the same as the prefixes in the actual XML document, they can be whatever you want. Only the actual namespace URLs must match. But to query on the default namespace you need to specify some specific prefix for that namespace , which can be whatever, e.g. `"default:"`. See [How do I select nodes that use a default namespace?](https://stackoverflow.com/a/14371073) and [Using Xpath With Default Namespace in C#](https://stackoverflow.com/a/585822). Do those answer your question? – dbc Jul 24 '23 at 17:39

1 Answers1

2

It is better to use LINQ to XML API.

It is available in the .Net Framework since 2007.

c#

void Main()
{
    XDocument xdoc = XDocument.Parse(@"<s:Envelope xmlns:s='http://schemas.xmlsoap.org/soap/envelope/'>
            <s:Body>
                <GetResponse xmlns='http://Door.Application.DataService/'>
                    <GetResult>C5465781005937173259</GetResult>
                </GetResponse>
            </s:Body>
        </s:Envelope>");
    
    XNamespace ns1 = "http://Door.Application.DataService/";
    string GetResult = xdoc.Descendants(ns1 + "GetResult").FirstOrDefault()?.Value;
    Console.WriteLine(GetResult);
}

Output

C5465781005937173259
Yitzhak Khabinsky
  • 18,471
  • 2
  • 15
  • 21