4

How to get attribute "action" and "filename" values in a right way using C#?

XML:

<?xml version="1.0" encoding="utf-8" ?>
 <Config version="1.0.1.1" >
   <Items>
    <Item action="Create" filename="newtest.xml"/>
    <Item action="Update" filename="oldtest.xml"/>   
  </Items>
 </Config>

C#: i cannot get attribute values as well as how to get values in foreach loops? How to solve this?

        var doc = new XmlDocument();
        doc.Load(@newFile);
        var element = ((XmlElement)doc.GetElementsByTagName("Config/Items/Item")[0]); //null
        var xmlActions = element.GetAttribute("action"); //cannot get values
        var xmlFileNames= element.GetAttribute("filename"); //cannot get values

         foreach (var action in xmlActions)
         {
           //not working
         }

         foreach (var file in xmlFileNames)
         {
           //not working
         }

Your code example means alot to me. Thanks!

1
  • 1
    You might want to look into LINQ to XML. It makes working with XML a lot easier. Commented Aug 2, 2013 at 13:31

4 Answers 4

9

You can use LINQ to XML. Following query returns strongly typed collection of items with Action and FileName properties:

var xdoc = XDocument.Load(@newFile);

var items = from i in xdoc.Descendants("Item")
            select new {
               Action = (string)i.Attribute("action"),
               FileName = (string)i.Attribute("fileName")
            };

foreach (var item in items)
{
   // use item.Action or item.FileName
}
Sign up to request clarification or add additional context in comments.

2 Comments

var items = for i in xdoc.Descendants("Item") select new { Action = (string)i.Attribute("action"), FileName = (string)i.Attribute("fileName") }; is not correct code grammar
@user235973457 sorry, typo. It should be from instead of for
3

GetElementsByTagName will find you only direct descendants. The argument is supposed to be just a tag name, not a whole path of elements.

If you want to search across the document while supplying an XPath expression, use SelectNodes instead.

For your document, it should look like this:

var element = (XmlElement)doc.SelectNodes("/Config/Items/Item")[0];

3 Comments

i have tried SelectNode but not sure how to use it in code. can you please give me example code?
@user235973457: I have added the exemplary call; I cannot try it right now, but I hope there will be no problem with namespaces. If you encounter any errors, please include the exact error message, and I, or anyone else around here, will try later on.
@user235973457: Do you mean XmlActions contains only one element? That is expected, as GetAttribute will return only one attribute node. If you actually want to get "all nodes whose action attribute says ...", iterate over the result from SelectNodes (the collection of <Item> elements) and retrieve the action and file attributes from each one of those <Item> elements.
2

You can achieve what you're asking with LINQ to XML:

// For each element that is a child of your Items element that is named Item
foreach (var item in XElement.Load("file.xml").Descendants("Items").Elements("Item"))
{
    // If the element does not have any attributes
    if (!item.Attributes().Any())
    {
        // Lets skip it
        continue;
    }

    // Obtain the value of your action attribute - Possible null reference exception here that should be handled
    var action = item.Attribute("action").Value;
    // Obtain the value of your filename attribute - Possible null reference exception here that should be handled
    var filename = item.Attribute("filename").Value;

    // Do something with your data
    Console.WriteLine("action: {0}, filename {1}", action, filename);
}

Comments

2

There are a bunch of problems with the code in the question:
1. You are using an XPath in the GetElementsByTagName, just use the tag
2. You are only getting the first XmlNode in the XmlNodeCollection by using [0]
3. Since you only have one XmlNode, you are only getting a string result for getting the attribute, not a collection of strings, which you are then trying to enumerate through
4. Your foreach is broken, there is no type for the resulting object

Here is a snippet that would work:

var doc = new XmlDocument();
doc.Load("test.xml");
var items = doc.GetElementsByTagName("Item");

var xmlActions = new string[items.Count];
var xmlFileNames = new string[items.Count];
for (int i = 0; i < items.Count; i++) {
    var xmlAttributeCollection = items[i].Attributes;
    if (xmlAttributeCollection != null) {
        var action = xmlAttributeCollection["action"];
        xmlActions[i] = action.Value;

        var fileName = xmlAttributeCollection["filename"];
        xmlFileNames[i] = fileName.Value;
    }
}

foreach (var action in xmlActions) {
    //working
}

foreach (var file in xmlFileNames) {
    //working
}

Or, if you don't need all of the actions and filenames in a collection before you act on them, you could just act on each action/filename in the for loop.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.