Reputation: 314
I need help with the following to return a set of nested lists from an xml tree:
The sample data:
<step>
<sequence>
<step>
<type></type>
<position>0</position>
</step>
<step>
<type></type>
<position>0</position>
</step>
<step>
<type></type>
<position>0</position>
</step>
<step>
<type></type>
<position>1</position>
</step>
<step>
<type></type>
<position>0</position>
</step>
<step>
<sequence>
<step>
<position>0</position>
</step>
<step>
<position>0</position>
</step>
<step>
<position>0</position>
</step>
<step>
<position>0</position>
</step>
<step>
<position>0</position>
</step>
</sequence>
</step>
<step>
<sequence>
<step>
<position>0</position>
</step>
<step>
<position>0</position>
</step>
<step>
<position>0</position>
</step>
<step>
<position>0</position>
</step>
</sequence>
</step>
</sequence>
</step>
My code:
public List<InstructionSequence> GetSequenceFromSource(XDocument UriSource)
{
List<InstructionSequence> StepCollection = new List<InstructionSequence>();
var u = from v in UriSource.Descendants("step")
select new InstructionSequence
{
step = Convert.ToInt16(v.Element("position").Value),
sequence = this.GetChildSequence(v)
};
return u.ToList<InstructionSequence>();
}
private List<InstructionSequence> GetChildSequence(XElement parent)
{
var u = (from v in parent.Descendants("step")
select new InstructionSequence
{
step = Convert.ToInt16(v.Element("position").Value),
sequence = null
});
return u.ToList<InstructionSequence>();
}
In one variation I can get the top level to be parsed correctly, but the child nodes are not returned - where is it going wrong?
Upvotes: 0
Views: 71
Reputation: 117124
Based on the document you presented (which is a little odd) this is what you need to convert it to a InstructionSequence
:
public InstructionSequence GetSequenceFromSource(XDocument UriSource)
{
return this.GetSequenceFromSource(UriSource.Root);
}
public InstructionSequence GetSequenceFromSource(XElement step)
{
return new InstructionSequence
{
step = step.Element("position") == null ? 0 : (int)step.Element("position"),
sequence = step.Element("sequence")?.Elements("step").Select(s => this.GetSequenceFromSource(s)).ToList(),
};
}
Please note that you asked for a list, but the root node of the XML is a step
so it appears you actually only need to return a single InstructionSequence
(which internally holds a list).
My code is recursive and will go down as far as the stack will allow.
With your source data from your question I get this result:
Upvotes: 1
Reputation: 69
var val = doc.Root
.Descendants("sequence")
.Descendants("step")
.Where(e => (e.FirstNode is XElement) && (((XElement)e.FirstNode).Name != "sequence"))
.Select(l => new InstructionSequence()
{
step = Convert.ToInt32(l.Element("position").Value)
});
This sounds like what you want, but I'm not sure. Can you provide some more details and we can work from the basis above? Maybe some sample output? You provided very little information to go off of.
Func<XElement, InstructionSequence> GetChildContents = child => new InstructionSequence { step = Convert.ToInt32(child.Element("position").Value), sequence = null };
var matchItems = new List<InstructionSequence>();
var splitGroups = doc.Root
.Descendants("step")
.GroupBy(v => (v.FirstNode is XElement) && (((XElement)v.FirstNode).Name != "sequence"));
var matchGroup = splitGroups.Single(e => e.Key == true);
var remaining = splitGroups.Single(e => e.Key == false);
matchItems.AddRange(matchGroup.Select(GetChildContents));
matchItems.AddRange(remaining.Descendants("sequence").Descendants("step").Select(GetChildContents));
Is this what you were looking for? Like I said before, not a lot to go off of. If your nodes are nested even further, I can add recursion to the above solution for you.
Upvotes: 0