I have an XML file as following:
<?xml version="1.0" encoding="utf-8"?>
<files>
<file name="1">
<file name="4">
</file>
</file>
<file name="2">
</file>
<file name="3">
<file name="5">
<file name="7">
</file>
</file>
</file>
</files>
Now I want to create a list of strings/numbers which save all the attribute name
in a list/array which has the nested nodes hierarchy in it. For example for the above XML file the expected list would be,
(1,4
2
3,5,7)
Because I could could know the desired node in which level is.
Would you please let me know what is your idea about having such a list?
Update: After Jon's answer, If the children nodes are in the same hierarchy, then would in the following way.
The XML file:
<files>
<file name="1">
<file name="4"/>
<file name="2">
<file name="3"/>
</file>
</file>
<file name="5"/>
and the desired output:
1,4
1,2
1,2,3
5
PS. After testing for some examples I noticed that I have to have first parent and then children in case when there are two or more children from the same level.
It seems that you possibly want:
file
elements which don't have a child file
elementfile
element ancestryname
attribute for each ancestor, and join it togetherSo I think this should work, creating an IEnumerable<List<int>>
:
var hierarchy = doc.Descendants("file")
.Where(x => x.Element("file") == null)
.Select(x => x.AncestorsAndSelf("file")
.Reverse()
.Select(f => (int) f.Attribute("name"))
.ToList());
Complete example:
using System;
using System.Linq;
using System.Xml.Linq;
class Test
{
static void Main()
{
var doc = XDocument.Load("test.xml");
var hierarchy = doc.Descendants("file")
.Where(x => x.Element("file") == null)
.Select(x => x.AncestorsAndSelf("file")
.Reverse()
.Select(f => (int) f.Attribute("name"))
.ToList());
foreach (var item in hierarchy)
{
Console.WriteLine(string.Join(", ", item));
}
}
}
Output:
1, 4
2
3, 5, 7
An alternative approach is to take all top-level file
elements, and for each one, find all the descendants:
using System;
using System.Linq;
using System.Xml.Linq;
class Test
{
static void Main()
{
var doc = XDocument.Load("test.xml");
var hierarchy = doc.Root.Elements("file")
.Select(x => x.DescendantsAndSelf("file")
.Select(f => (int) f.Attribute("name"))
.ToList());
foreach (var item in hierarchy)
{
Console.WriteLine(string.Join(", ", item));
}
}
}
Now both of those give the same result at the moment, because you've basically got a "line" from each top-level file
element. However, you should consider what you want the result to be if you had XML like this:
<files>
<file name="1">
<file name="4"/>
<file name="2">
<file name="3"/>
</file>
</file>
<file name="5"/>
</files>
Here the top-level element with name 1 has two children - what would you want the result to be?
See more on this question at Stackoverflow