【问题标题】:C# Reading multiple elements with same name using LINQ to XMLC# 使用 LINQ to XML 读取具有相同名称的多个元素
【发布时间】:2011-06-27 06:14:01
【问题描述】:

有没有更好的方法来做到这一点? 我必须获得两个属性值。 XML 总是只有这两个属性。

我的 xml:

<Template name="filename.txt">
  <Property name="recordSeparator">\r\n</Property>
  <Property name="fieldCount">16</Property>
</Template>

林克:

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

【问题讨论】:

  • 请澄清您的问题以解释您要做什么。阅读tinyurl.com/so-hints
  • 您是否期望单个模板中有多个分隔符或 fieldCount 属性?因为,Select() 返回 IEnumerable,在您的情况下为 IEnumerable。这意味着 recordDelim 和 fieldCount 都将是 IEnumerable 类型。这是您在匿名对象中所需要的吗?
  • @kornelijepetak,xml 总是相同的,只有这两个属性。

标签: c# .net xml linq xpath


【解决方案1】:

“更好的方法”取决于您到底想达到什么目标 - 性能、简单性等?

我想我会创建一个类,其中包含您试图通过匿名类获得的内容。

public class Item {
    public String Separator { get; set; }
    public int FieldCount { get; set; }
}

然后我会将 LINQ 修改为:

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();

请注意,如果您的 Template 标签不包含两个 Property 标签,每个标签都有指定的属性,这将导致 NullReference 异常。

如果它不是数字,它也会在从 FieldCount 解析整数时抛出异常。

想法:

如果生成的 xml 是您自己的,并且您可以更改它的格式,为什么不这样做:

<Template>
  <Name>filename.txt</Name>
  <RecordSeparator>\r\n</RecordSeparator>
  <FieldCount>16</FieldCount>
</Template>

它更容易阅读和解析,而且更短一些。

最后,我认为我会这样做:

有这个课程:

public class Item 
{
   public String FileName { get; set; }
   public String Separator { get; set; }
   public int FieldCount { get; set; }
}

还有这个私有方法:

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

我可以在代码中做:

XDocument doc = XDocument.Load("myfile.txt");

List<Item> items = (from template in doc.Elements("Template")
                   select GetItemFromTemplate(template)).ToList();

【讨论】:

  • 感谢您的建议!我想我要改变 xml 的结构,因为它确实更容易阅读和解析。
  • 您可能需要考虑我所做的编辑。简化 LINQ 查询。
  • 好吧,你为答案付出了相当多的努力:)。虽然同意答案 +1。
  • @hs2d。我的回答从来都不是完美的。 :) 我总能找到改进我的解决方案的方法 :) 很高兴你觉得它有帮助。
【解决方案2】:

这个效率高一点:

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

如果你一直有一个Template 节点:

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

【讨论】:

  • 这当然有效,但我不会强制匿名对象,除非您仅在执行 LINQ 查询的方法中需要此信息(分隔符、计数)。否则,我认为使用自定义创建的类会很聪明(甚至可能是必要的)。
  • @kornelijepetak - 100% 同意。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多