LINQ to XML - 具有父级属性的自定义对象的列表
本文关键字:属性 自定义 对象 列表 XML to LINQ | 更新日期: 2023-09-27 18:31:51
今
晚的 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>();
这就是我想要实现的目标;
- 创建一个 MyObjs 列表。我在MyObjs中转换Level3元素。
- 我只想要 ID 为 12345 的 Level2 元素中的 Level3 元素
- 我想在每个子级 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
从哪里工作。它选择 1 个元素,即 Level2[id=12345]。好。级别 2 属性正常工作。
这是我无法解决的;
- 如何访问每个子 Level3 元素,以便我可以将其转换为 MyObj
- 如何创建 Level3 属性(使用"let")。我想使用 Let 以便我可以检查空等
再次,谢谢
您应该使用 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")
}
只有在查询表达式完成之后,您只能在最后使用select
。基本上,您需要将//select <-- 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
的最后一件事是 MyObj
s 的事实推断出正确的类型。
_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")
}
);