22

Suppose I have the following XML Document.

<reply success="true">More nodes go here</reply>

How to get the value of the attribute success, which in this case would be the string "true".

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Shamim Hafiz - MSFT
  • 21,454
  • 43
  • 116
  • 176
  • Must the soluton use `XmlDocument` or any other specifc XML processing API? – Daniel Renshaw Sep 20 '10 at 10:57
  • @Daniel: before you even go there: http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 ;-) – Isak Savo Sep 22 '10 at 19:44
  • @Isak: I had no intention of going the RegEx route! The question talks of an "XML Document" which suggests using a DOM API (i.e. `XmlDocument`) but I was asking whether that was required or whether a stream/SAX based API such as `XmlReader` was acceptable instead. – Daniel Renshaw Sep 23 '10 at 06:32

7 Answers7

41

I would try something like this:

XmlDocument doc = new XmlDocument();
doc.LoadXml("<reply success=\"true\">More nodes go here</reply>");

XmlElement root = doc.DocumentElement;

string s = root.Attributes["success"].Value;
Christian Davén
  • 16,713
  • 12
  • 64
  • 77
Edwin de Koning
  • 14,209
  • 7
  • 56
  • 74
  • You could also try to get the attribute by name: root.Attributes["succes"].Value – Edwin de Koning Sep 20 '10 at 11:09
  • 1
    It's generally very bad practice to access attributes by position, because by definition the ordering of attributes on XML elements is not significant. In this trivial case it works because there's only one attribute, but that's just being lucky. – Robert Rossney Sep 22 '10 at 17:24
  • You're right, I already suggested the alternative in my first comment. I now have edited my original post to show it. – Edwin de Koning Sep 23 '10 at 05:49
  • In my case, I was not able to index attributes like an array, so I did something like the following to get the value of a specific attribute: `string s = root.Attributes.GetNamedItem("success").InnerText; ` – Jonathan Maim May 12 '16 at 12:39
11

If you load the XML into an XmlDocument, there are any number of ways to get the attribute's value. You could use XPath to find the attribute:

XmlAttribute a = doc.SelectSingleNode("/reply/@success");
Console.Write(a.Value);

If you already have the XmlElement that the attribute appears on (which in this case is the document element), then you can just use GetAttribute:

Console.Write(doc.DocumentElement.GetAttribute("success"));

There are similar approaches if you're using XPathDocument or XmlReader or XDocument.

In all cases, though, you want to be getting the attribute by its name, not its position. In your test case there's only one attribute; in any real-world application multiple attributes are likely, and attribute ordering in XML is not significant. These two elements are semantically equivalent:

<a foo='true' bar='false'/>

<a bar='false' foo='true'/>

You don't even know that the XML parser will present attributes to you in the same order they appear in the document; depending on the implementation, the parser may give them to you in alphabetical order, or in random order. (I've seen both.)

Robert Rossney
  • 94,622
  • 24
  • 146
  • 218
  • But we are talking C#/.NET specifically here and there's no mention in the MS documentation that either `XmlReader` or `XmlDocument` indexes attributes in anything other than document/input order so if the requirement was to "get the first attribute that appears in the input XML", this can be achieved by looking for the attribute with index zero. Of course, the question isn't asking for the "first" attribute so it is correct in this case to use attribute name instead of index. – Daniel Renshaw Sep 23 '10 at 06:44
  • 1
    There's no guarantee in the MS documentation that `XmlDocument` (actually, `XmlNamedNodeMap`) indexes attributes in any deterministic order. There are examples showing that nodes are indexed in the order they're added to the map. But those examples are on this page - http://msdn.microsoft.com/en-us/library/7sf9z378.aspx - and what, pray, is the very first word in the title? – Robert Rossney Sep 23 '10 at 09:10
2

The following code works for me.

String strXML = "<reply success=\"true\">More nodes go here</reply>";

    using (XmlReader reader = XmlReader.Create(new StringReader(strXML)))
    {
            reader.ReadToFollowing("reply");
            reader.MoveToContent();
            string strValue = reader.GetAttribute("success");
            Console.WriteLine(strValue);
    }
2
    using System;
    using System.Linq;
    using System.Xml.Linq;

    class MyClass
    {
        static void Main(string[] args)
        {
            XElement xmlcode =
            XElement.Parse("<reply success=\"true\">More nodes go  </reply>");

            var successAttributes =
                from attribute in xmlcode.Attributes()
                where attribute.Name.LocalName=="success" 
                select attribute ;

            if(successAttributes.Count()>0)
            foreach (var sa in successAttributes)
            {
                Console.WriteLine(sa.Value);           
            }
            Console.ReadLine();
        }
    }
Edwin de Koning
  • 14,209
  • 7
  • 56
  • 74
explorer
  • 11,710
  • 5
  • 32
  • 39
  • See my comment on Rewinder's answer; this answer has exactly the same problem. It will work in this trivial case, but is a very bad practice in general. – Robert Rossney Sep 22 '10 at 17:25
  • Yeah, you are right. I edited the code to make it look for and print the value of all the 'success' attribute values in the XML snippet regardless of their order or location. Now give my Zero back :) – explorer Sep 22 '10 at 19:43
1
var at = 
XElement.Parse("<reply success=\"true\">More nodes go  </reply>").Attribute("success");
if (at != null) Console.Write(at.Value);
ASergan
  • 171
  • 8
0

If attribute value returns null or empty, try this.

     string x="<node1 id='12345'><node2 Name='John'></node2><node3 name='abc'></node3></node1>";
        XmlDocument xml = new XmlDocument();
        xml.LoadXml(x);
        var node = xml.GetElementsByTagName("node3");
        xml = new XmlDocument();
        xml.LoadXml(nodes[0].OuterXml);
        XmlElement root = xml.DocumentElement;
        String requiredValue = root.GetAttribute("name");  
    returns "abc";      
-1

Here's an alternative solution using XmlReader which may be a little more efficient than using XmlDoument although that's proably negligible on such a small XML document

string input = "<reply success=\"true\">More nodes go here</reply>";

using (XmlReader xmlReader = XmlReader.Create(new StringReader(input)))
{
    xmlReader.MoveToContent();
    string success = xmlReader.GetAttribute("success");
    Console.WriteLine(success);
}
Daniel Renshaw
  • 33,729
  • 8
  • 75
  • 94