C# Reading multiple elements with same name using LINQ to XML
Is there any better way doing this? I have to get both property values. XML always has only these 2 properties.
My xml:
<Template name="filename.txt">
<Property name="recordSeparator">\r\n</Property>
<Property name="fieldCount">16</Property>
</Template>
Linq:
var property = from template in xml.Descendants("Template")
select new
开发者_如何转开发 {
recordDelim = template.Elements("Property").Where(prop => prop.Attribute("name").Value == "recordSeparator")
.Select(f => new { f.Value }),
fieldCount = template.Elements("Property").Where(prop => prop.Attribute("name").Value == "fieldCount")
.Select(f => new { f.Value })
};
"Better way" depends on what exactly are you trying to achieve - performance, simplicity, etc.?
I guess I would create a class that contains what you are trying to get with anonymous classes.
public class Item {
public String Separator { get; set; }
public int FieldCount { get; set; }
}
and then I would modify the LINQ to:
var templates = from template in xml.Descendants("Template")
let children = template.Elements("Property")
select new Item() {
Separator = children.First(tag=>tag.Attribute("name").Value == "recordSeparator").Value,
FieldCount = Int32.Parse(children.First(tag=>tag.Attribute("name").Value == "fieldCount").Value)
};
List<Item> items = templates.ToList();
Note that this will cause NullReference
exception in case your Template tag does not contain two Property tags, each with specified attributes.
Also it will throw an exception in parsing the integer from a FieldCount if it's not a number.
Idea:
If the xml generated is your own, and you can change it's format, why not do something like:
<Template>
<Name>filename.txt</Name>
<RecordSeparator>\r\n</RecordSeparator>
<FieldCount>16</FieldCount>
</Template>
It's easier to read and to parse, and it's a little bit shorter.
In the end, I think this is how I would do it:
Having this class:
public class Item
{
public String FileName { get; set; }
public String Separator { get; set; }
public int FieldCount { get; set; }
}
and this private method:
private Item GetItemFromTemplate(XElement node)
{
return new Item() {
FileName = node.Element("Name").Value,
Separator = node.Element("RecordSeparator").Value,
FieldCount = Int32.Parse(node.Element("FieldCount").Value)
};
}
I could do in code:
XDocument doc = XDocument.Load("myfile.txt");
List<Item> items = (from template in doc.Elements("Template")
select GetItemFromTemplate(template)).ToList();
This one is a little more efficient:
var properties =
from template in xml.Descendants("Template")
let propertyNodes = template.Elements("Property")
.Select(arg => new { Name = arg.Attribute("name").Value, Value = arg.Value })
select
new
{
recordDelim = propertyNodes.Single(arg => arg.Name == "recordSeparator").Value,
fieldCount = propertyNodes.Single(arg => arg.Name == "fieldCount").Value
};
If you have always one Template
node:
var propertyNodes = xml.XPathSelectElements("/Template/Property")
.Select(arg => new { Name = arg.Attribute("name").Value, arg.Value })
.ToList();
var properties =
new
{
recordDelim = propertyNodes.Single(arg => arg.Name == "recordSeparator").Value,
fieldCount = propertyNodes.Single(arg => arg.Name == "fieldCount").Value
};
精彩评论