开发者

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
    };
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜