【问题标题】:LINQ to XML - list of custom objects with attributes from parentLINQ to XML - 具有父属性的自定义对象列表
【发布时间】:2013-09-23 06:05:36
【问题描述】:

今晚的 LINQ 学习曲线太陡峭了,所以我再次来这里寻求帮助。提前多谢。

这是我当前的代码;

_myList = (
from listLv2 in
    _documentRoot.Descendants("Level1").Descendants("Level2")
where
    (string)listLv2.Attribute("id") == "12345"

let attrib_Colour = listLv2.Attribute("Colour")
let attrib_ID = listLv2.Attribute("id")

//select listLv2.Descendants("Level3") <---- not working
select new MyObj
{
let attrib_ChildID = ???..Attribute("id")

ParentColour = attrib_Colour.Value, 
ParentID = attrib_ID.Value, // in this case 12345
ChildID = attrib_ChildID
}).ToList<MyObj>();

这就是我想要实现的目标;

  1. 创建 MyObjs 列表。我在 MyObjs 中转换 Level3 元素。
  2. 我只想要 Level2 元素中 ID 为 12345 的 Level3 元素
  3. 我想在每个 Level3 子元素中使用 Level2(id=12345) 元素中的一些属性

XML结构如下;

<root>
  <Level1>
<Level2 id="12345" colour="Red">
  <Level3 id="0001" />
  <Level3 id="0002" />
  <Level3 id="0003" />
</Level2>
<Level2 id="45678" colour="Blue">
  <Level3 id="0004" />
  <Level3 id="0005" />
  <Level3 id="0006" />
</Level2>
</Level1>
</root>

列表中的对象应该是这样的;

MyObj.ParentID = 12345
MyObj.ParentColour = "Red"
MyObj.ID = 0001

MyObj.ParentID = 12345
MyObj.ParentColour = "Red"
MyObj.ID = 0002

MyObj.ParentID = 12345
MyObj.ParentColour = "Red"
MyObj.ID = 0003

from 和 where 有效。它选择 1 个元素,Level2[id=12345]。好的。 Level2 属性有效。

这是我无法解决的问题;

  • 如何访问每个 Level3 子元素,以便将其转换为 MyObj
  • 如何创建 Level3 属性(使用“let”)。我想使用 Let 来检查 null 等

再次感谢

【问题讨论】:

    标签: c# linq linq-to-xml


    【解决方案1】:

    您应该使用SelectMany 为您的 level2 元素获取 level3 项目。查询语法等效为from listLv3 in listLv2.Descendants("Level3"):

    from listLv2 in _documentRoot.Descendants("Level1").Descendants("Level2")
    let attrib_ID = (string)listLv2.Attribute("id")
    let attrib_Colour = (string)listLv2.Attribute("colour") // note: lowercase!
    where attrib_ID == "12345"
    from listLv3 in listLv2.Descendants("Level3")
    select new MyObj
    {
      ParentColour = attrib_Colour, 
      ParentID = attrib_ID, 
      ChildID = (string)listLv3.Attribute("id")
    }
    

    更新:为什么我在解决方案中提到了 SelectMany?因为上面的代码(如果我们忘记了用 let 关键字引入的新范围变量)将被编译成以下方法语法查询:

    _documentRoot
        .Descendants("Level1")
        .Descendants("Level2")
        .Where(listLv2 => (string)listLv2.Attribute("id") == "12345")
        .SelectMany(listLv2 => listLv2.Descendants("Level3")) // flattening query
        .Select(listLv3 => new MyObj {
            ParentColour = (string)listLv3.Parent.Attribute("colour"),
            ParentID = "12345", // equal to id you are searching for
            ChildID = (string)listLv3.Attribute("id")
        });
    

    这里的关键是通过从每个匹配的 level2 元素中选择所有 level3 后代到单个序列中来展平查询。

    顺便说一句,还要考虑 XPath 解决方案:

    from listLv3 in root.XPathSelectElements("Level1/Level2[@id='12345']/Level3")
    select new MyObj
    {
       ParentColour = (string)listLv3.Parent.Attribute("colour"), 
       ParentID = "12345", 
       ChildID = (string)listLv3.Attribute("id")
    }
    

    【讨论】:

    • 干杯。我看不到你提到的 SelectMany,但这段代码对我很有帮助。再次感谢。
    • @ausgeorge 这段代码编译成SelectMany方法调用:) 我给你加了一些解释
    • Descendants 可以有一个 performance hit 用于大型 xml。
    • @Anirudh 同意,最好使用Elements,即使在这种情况下是小文件
    【解决方案2】:

    你只在最后使用select,一旦你到达查询表达式完成的地步。基本上,您需要将您的//select &lt;-- not working 更改为另一个from,然后继续。它最终会是这样的:

    _myList = (
    from listLv2 in
        _documentRoot.Descendants("Level1").Descendants("Level2")
    where
        (string)listLv2.Attribute("id") == "12345"
    
    let attrib_Colour = listLv2.Attribute("Colour")
    let attrib_ID = listLv2.Attribute("id")
    
    from listLv3 in listLv2.Descendants("Level3") // <----  should work
    
    select new MyObj
    {
    let attrib_ChildID = listLv3.Attribute("id")
    
    ParentColour = attrib_Colour.Value, 
    ParentID = attrib_ID.Value, // in this case 12345
    ChildID = attrib_ChildID
    }).ToList<MyObj>();
    

    请注意,您的最后一个 ToList 不需要指定显式类型参数,因为 C# 可以根据您最后一个 select 是 MyObjs 的事实推断出正确的类型。

    【讨论】:

    • 谢谢!仅供参考,attrib_ChildID LET 必须在 from 和 select 语句之间。当它在 select new{} 内时我不工作。
    【解决方案3】:
    _documentRoot.Elements("Level1")
                 .Elements("Level2")
                 .Where(x=>x.Attribute("id").Value=="12345")
                 .Elements("Level3")
                 .Select(y=>
                      new MyObj
                      {
                          ParentColour = y.Parent.Attribute("colour").Value, 
                          ParentID = y.Parent.Attribute("id").Value,
                          ChildID = (string)y.Attribute("id")
                      }
                     );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多