LINQ to XML 选择子元素

5
我正在尝试使用LINQ to XML将XML文件中的信息提取到对象中。虽然我可以返回文档和部分Id属性,但我无法访问每个部分元素中的项目,它返回文档中所有项目的IEnumerable。我知道这是正确的,因为我正在调用Descendants,但是无法使其仅返回每个部分元素的子项。有人能帮忙吗?
XML文档
<root>
<document id="1">
  <section id="1.1">
    <item id="1.1.1"></item>
    <item id="1.1.2"></item>
    <item id="1.1.3"></item>
  </section>
  <section id="1.2">
    <item id="1.2.1"></item>
    <item id="1.2.2"></item>
  </section>
</document>
</root>

LINQ查询

XElement documentRoot = XElement.Load("document.xml");
var documents = (from docs in documentRoot.Descendants("document")
                 select new
                    {
                        Id = (string) docs.Attribute("id"),
                        Sections = docs.Elements("section"),
                        Items = docs.Elements("section").Elements("item")
                    }).ToList();

foreach(var doc in documents)
{
    foreach(var section in doc.Sections)
    {
        Console.WriteLine("SectionId: " + section.Attribute("Id"));  
        foreach(var item in doc.Items)
        {
            Console.WriteLine("ItemId: " + section.Attribute("Id"));
        }
    }
}

1
我有点不清楚目标。您的匿名对象由文档ID、文档中所有部分以及文档中所有部分的所有项组成。如果您想将XML层次结构重建为匿名对象,则需要多个查询。那么为什么不直接使用XML呢? - womp
2个回答

7
你有一些小的拼写错误,属性应该是Id而不是ID,在循环项上也有错误。但如果你想将所有部分项目放入该项目集合中,那么你在设计层面上是错误的,因为Items应该是Section属性,而不是Document(所以你需要查询你的XML两次)。
或者,你可以像这样做:
var documents =
    (from docs in documentRoot.Descendants("document")
     select new
     {
         Id = (string) docs.Attribute("id"),
         Sections = docs.Elements("section")
     }).ToList();

foreach (var doc in documents)
{
    foreach (var section in doc.Sections)
    {
        Console.WriteLine("SectionId: " + section.Attribute("id"));
        foreach (var item in section.Elements("item"))
        {
            Console.WriteLine("ItemId: " + item.Attribute("id"));
        }
    }
}

输出:

章节编号:id="1.1"
条目编号:id="1.1.1"
条目编号:id="1.1.2"
条目编号:id="1.1.3"
章节编号:id="1.2"
条目编号:id="1.2.1"
条目编号:id="1.2.2"

抱歉有错别字,但仍未解决问题。我想要实现的是只返回每个部分的子项。 - Cragly
@Cragly,我刚刚重写了我的答案,请看一下。 - Rubens Farias
太好了!像魔法一样好用。如此简单的修复。可能是因为看了这个问题很长时间,所以没能看到树木。干得好。 - Cragly

2
你是否希望有一个扁平的结构?(来自LinqPad)
XElement documentRoot  = XElement.Parse (
@"<root> 
<document id='1'> 
  <section id='1.1'> 
    <item id='1.1.1'></item> 
    <item id='1.1.2'></item> 
    <item id='1.1.3'></item> 
  </section> 
  <section id='1.2'> 
    <item id='1.2.1'></item> 
    <item id='1.2.2'></item> 
  </section> 
</document> 
</root> 
");




var documents = (from docs in documentRoot.Descendants("section") 
                 select new 
                    { 
                        SectionId = (string) docs.Attribute("id"), 
                        Items = docs.Elements("item") 
                    }); 
 documents.Dump();

这提供了2个SectionId项,其中包含与相关项目相关的XElements。


谢谢您的帖子,但我理想中的是能够访问那些包含的项目XElements并将它们分配给对象的Items属性,以便我获得与其特定部分相关联的项目的IEnumerable<XElement>。 - Cragly
你能提供一个数据结构的例子吗?为什么要用 XElement 而非类型?!? - salgo60

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接