HerrimanCoder
HerrimanCoder

Reputation: 7218

Simplest way to get XML nodes with namespace?

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?

Upvotes: 4

Views: 2284

Answers (2)

J45
J45

Reputation: 396

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;

Upvotes: 1

Charles Mager
Charles Mager

Reputation: 26213

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.

Upvotes: 3

Related Questions