Reputation: 1015
The LINQ learning curve is proving too steep tonight, so I again come here for help. Lots of gratitude in advance.
Here's my current code;
_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>();
Here's what I'm trying to achieve;
The XML structure is as follows;
<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>
The objects in the list should be like this;
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
The from and where are working. It selects 1 element, the Level2[id=12345]. Nice. The Level2 attributes are working.
Here's what I can't work out;
again, thanks
Upvotes: 2
Views: 886
Reputation: 236228
You should use SelectMany
to get level3 items for your level2 element. Query syntax equivalent will be 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")
}
UPDATE: Why I mentioned SelectMany in solution? Because code above (if we'll forget about new range variables introduces with let
keyword) will be compiled into following method-syntax query:
_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")
});
And key point here is flattening query by selecting all level3 descendants from each matched level2 element into single sequence.
BTW Consider also XPath solution:
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")
}
Upvotes: 2
Reputation: 32797
_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")
}
);
Upvotes: 0
Reputation: 63338
You only use select
right at the end, once you've got to the point that the query expression is finished. Basically, you need to change your //select <-- not working
to another from
, and carry on. It will end up something like this:
_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>();
And note that your last ToList
doesn't need an explicit type parameter specified, since C# can infer the correct type from the fact that the last thing you select
are MyObj
s.
Upvotes: 1