Simplest way to get XML nodes with namespace?

2.1k views Asked by At

I have the following XML:

<?xml version="1.0" encoding="UTF-8"?>
<createTransactionResponse xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd" 
                          xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <messages>
      <resultCode>Ok</resultCode>
      <message>
         <code>I00001</code>
         <text>Successful.</text>
      </message>
   </messages>
   <transactionResponse>
      <responseCode>1</responseCode>
      <authCode>25C10X</authCode>
      <messages>
         <message>
            <code>1</code>
            <description>This transaction has been approved.</description>
         </message>
      </messages>
  </transactionResponse>
</createTransactionResponse>

What is the easiest way to get the value "Successful." from createTransactionResponse->messages->message->text?

Here is my code:

XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
var nsmgr = new XmlNamespaceManager(doc.NameTable);
nsmgr.AddNamespace("anet", "AnetApi/xml/v1/schema/AnetApiSchema.xsd");
var myNodes = doc.SelectNodes("//anet:messages", nsmgr);

myNodes returns 2 nodes. The innerxml of node[0] is:

<resultCode xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">Ok</resultCode><message xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
   <code>I00001</code>
   <text>Successful.</text>
</message>

The innerxml of node[1] is:

<message xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd">
   <code>1</code>
   <description>This transaction has been approved.</description>
</message>

My problem is I can't go any deeper than that.

//anet:messages/message yields nothing. //anet:createTransactionResponse/messages yields nothing.

I'm just trying to get specific element values such as "I00001" and "25C10X".

What am I doing wrong?

2

There are 2 answers

0
Charles Mager On BEST ANSWER

Namespace bindings are inherited, so the child elements are in the same namespace as their parents here.

You need to add the missing namespace prefixes to your query:

//anet:messages/anet:message/anet:text

That said, I'd usually prefer LINQ to XML over XPath:

XNamespace ns = "AnetApi/xml/v1/schema/AnetApiSchema.xsd";

var root = XElement.Parse(xml);

var text = (string) root.Elements(ns + "messages")
    .Descendants(ns + "text")
    .Single();

See this fiddle for a working demo.

0
J45 On

You can also use the LocalName property to avoid using the namespace:

XDocument root = XDocument.Parse(xml);

string text = root.Descendants()
    .First(node => node.Name.LocalName == "messages").Elements()
    .First(node => node.Name.LocalName == "message").Elements()
    .First(node => node.Name.LocalName == "text").Value;