Reputation: 331
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!
Upvotes: 4
Views: 32258
Reputation: 236208
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
}
Upvotes: 9
Reputation: 51
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.
Upvotes: 2
Reputation:
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);
}
Upvotes: 2
Reputation: 20722
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];
Upvotes: 3