Using xpath select how do I get the value of this element in example?

with this 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">
   <refId>999999999</refId>
   <messages>
      <resultCode>Ok</resultCode>
      <message>
         <code>I00001</code>
         <text>Successful.</text>
      </message>
   </messages>
   <transactionResponse>
      <responseCode>1</responseCode>
      <authCode>HH1D69</authCode>
      <avsResultCode>Y</avsResultCode>
      <cvvResultCode>P</cvvResultCode>
      <cavvResultCode>2</cavvResultCode>
      <transId>2228993425</transId>
      <refTransID />
      <transHash>916EE7527B17B62F62AA72B4C71F8322</transHash>
      <testRequest>0</testRequest>
      <accountNumber>XXXX0015</accountNumber>
      <accountType>MasterCard</accountType>
      <messages>
         <message>
            <code>1</code>
            <description>This transaction has been approved.</description>
         </message>
      </messages>
      <userFields>
         <userField>
            <name>MerchantDefinedFieldName1</name>
            <value>MerchantDefinedFieldValue1</value>
         </userField>
         <userField>
            <name>favorite_color</name>
            <value>blue</value>
         </userField>
      </userFields>
   </transactionResponse>
</createTransactionResponse>

I would like to get "resultCode", from here

<messages><resultCode>Ok</resultCode><message>

But the xpath I'm using does not give me the value of resultCode Ok.

What am I doing wrong?

--

static void Main(string[] args)
    {

                    string myXML = @"<?xml version=""1.0"" encoding=""utf-8""?><createTransactionResponse xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns=""AnetApi/xml/v1/schema/AnetApiSchema.xsd""><refId>999999999</refId><messages><resultCode>Ok</resultCode><message><code>I00001</code><text>Successful.</text></message></messages><transactionResponse><responseCode>1</responseCode><authCode>HH1D69</authCode><avsResultCode>Y</avsResultCode><cvvResultCode>P</cvvResultCode><cavvResultCode>2</cavvResultCode><transId>2228993425</transId><refTransID /><transHash>916EE7527B17B62F62AA72B4C71F8322</transHash><testRequest>0</testRequest><accountNumber>XXXX0015</accountNumber><accountType>MasterCard</accountType><messages><message><code>1</code><description>This transaction has been approved.</description></message></messages><userFields><userField><name>MerchantDefinedFieldName1</name><value>MerchantDefinedFieldValue1</value></userField><userField><name>favorite_color</name><value>blue</value></userField></userFields></transactionResponse></createTransactionResponse>";




 string myValue = XMLSelect(myXML, "createTransactionResponse/messages/message/resultCode");
        //myValue should = "Ok" but it does not :(

    }

    public static string XMLSelect(string _xmldoc, string _xpath)
    {
        string returnedValue = string.Empty;
        XmlDocument doc = new XmlDocument();

        try
        {
            doc.LoadXml(_xmldoc);

            XmlElement root = doc.DocumentElement;
            returnedValue = (string)doc.SelectNodes(_xpath)[0].InnerText; 
        }
        catch (Exception ex)
        {
            return "";
        }
        return returnedValue;
    }
Jon Skeet
people
quotationmark

Your first problem is that the XML you originally gave isn't valid. You're masking that by returning "" whenever you encounter an exception, so you don't have any information any more.

So the first thing to do IMO is remove the spurious exception handling:

public static string XMLSelect(string _xmldoc, string _xpath)
{
    string returnedValue = string.Empty;
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(_xmldoc);        
    XmlElement root = doc.DocumentElement;
    return (string)doc.SelectNodes(_xpath)[0].InnerText; 
}

Now, the problem with the XPath is that all the elements in your XML are in a namespace of AnetApi/xml/v1/schema/AnetApiSchema.xsd - so you'll probably want an XmlNamespaceManager. It's slightly tricky to separate that properly given the way that you've split the load from the XPath, but for the moment you could just introduce an alias of ns for the right namespace.

Next, your XPath is incorrect in that it looks for message/resultCode, when those two elements are peers. You don't want the message part.

Here's a short but complete program which fixes all those problems:

using System;
using System.Xml;

public class Program
{
    static void Main(string[] args)
    {
        // As per the question
        string myXML = "...";
        string myValue = XMLSelect(myXML, "ns:createTransactionResponse/ns:messages/ns:resultCode");
        Console.WriteLine(myValue);
    }

    public static string XMLSelect(string _xmldoc, string _xpath)
    {
        string returnedValue = string.Empty;
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(_xmldoc);        
        var nsm = new XmlNamespaceManager(doc.NameTable);
        nsm.AddNamespace("ns", "AnetApi/xml/v1/schema/AnetApiSchema.xsd");
        XmlElement root = doc.DocumentElement;
        return (string)doc.SelectNodes(_xpath, nsm)[0].InnerText;
    }
}

If you could use LINQ to XML instead, and simply work on the document instead of passing in the XML text and an XPath selector, it would be simpler:

XDocument doc = XDocument.Parse(xml);
XNamespace ns = "AnetApi/xml/v1/schema/AnetApiSchema.xsd";
string code = (string) doc.Root
                          .Element(ns + "messages")
                          .Element(ns + "resultCode");
Console.WriteLine(code);

people

See more on this question at Stackoverflow