Return a tree from a quey (filtered trree)

A

Alexander Mueller

Hi

i have an xml-doc in memory.
All nodes have a name-Attribute.
Some nodes have a name-attribute whose value is "Bill".
Bill-named nodes can be located at any
branching depth and index. Bills can contain other Bills.
Now i want to select all nodes named Bill.
Easy, SelectNodes.

The special thing is, that i don't want a flat list
of nodes to be returned.
I rather want the "partial tree".
That is: the parts of the original tree, that contain
a node named Bill down their branches shall be included.
All nodes below a Bill that don't contain another Bill indirectly
shall be stripped.
All nodes below root that don't contain any Bill directly or
indirectly shall be stripped, as well.

So I need something like a filter or a view on a tree.

It there a library, query-language, API or whatever
that has *built*-*in* support for returning tree-structures
a result of a query? (Doesn't need to be XML-orientated)

All help & hints very much appreciated,
Alex


Example:

*OriginalTree*:

0/Root
|--22/John
| |--16/Hilary
| |--19/Sue
|
|--98/Bill
|
|--23/Monica
| |--13/Bill
| |--199/Mabel
|
|
|--78/Ginger
| |--99/Fred
|
|--55/Harry
|--80/Sue
|--45/Bill

The desired result should look like:

*FilteredTree*:

0/Root
|
|--98/Bill
|
|--23/Monica
| |--13/Bill
|
|--55/Harry
|--80/Sue
|--45/Bill


All APIs I know (e.g. SelectNodes(xpathExpression),
return *flat* list/collections/arrays, like:

|--98/Bill
|--13/Bill
|--45/Bill
 
M

Mr. Arnold

It there a library, query-language, API or whatever
that has *built*-*in* support for returning tree-structures
a result of a query? (Doesn't need to be XML-orientated)

VS 2008, .Net Framework 3.5 and Linq-2-XML will give you the ability.

http://www.hookedonlinq.com/LINQtoXML5MinuteOverview.ashx


__________ Information from ESET NOD32 Antivirus, version of virus signature database 4098 (20090522) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com
 
M

Mr. Arnold

It there a library, query-language, API or whatever
that has *built*-*in* support for returning tree-structures
a result of a query? (Doesn't need to be XML-orientated)

VS 2008, .Net Framework 3.5 and Linq-2-XML will give you the ability.

http://www.hookedonlinq.com/LINQtoXML5MinuteOverview.ashx


__________ Information from ESET NOD32 Antivirus, version of virus signature database 4098 (20090522) __________

The message was checked by ESET NOD32 Antivirus.

http://www.eset.com
 
M

Morten Wennevik [C# MVP]

Hi Alexander,

In addition to the other answers, if you are unwilling or unable to go the
Linq-To-Xml way, the xml nodes you get from SelectedNodes know who their
parents are so you can recreate the full tree. Below is a code sample
creating a List<Person> containing Bills and his parents.

protected override void OnLoad(EventArgs e)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);

XmlNodeList list = doc.SelectNodes("//Person[@Name='Bill']");

List<Person> people = CreateList(list);
}

private List<Person> CreateList(XmlNodeList list)
{
List<Person> people = new List<Person>();
foreach (XmlNode node in list)
{
Person p = new Person
{
ID = int.Parse(node.Attributes["ID"].Value),
Name = node.Attributes["Name"].Value
};

XmlNode parent = node.ParentNode;
while (parent != null && parent.ParentNode != null
&& parent.ParentNode.NodeType != XmlNodeType.Document)
{
int parentId = int.Parse(parent.Attributes["ID"].Value);
Person p2 = people.Find(x => x.ID == parentId);
if (p2 == null)
{
p2 = new Person
{
ID = parentId,
Name = parent.Attributes["Name"].Value
};
}

p2.Children.Add(p);
p = p2;
parent = parent.ParentNode;
}
people.Add(p);
}
return people;
}

[DebuggerDisplay("{ID} {Name} Children: {Children.Count}")]
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public List<Person> Children { get; set; }
public Person() { Children = new List<Person>(); }
}


string xml =
@"<Root>
<Person ID=""22"" Name=""John"">
<Person ID=""16"" Name=""Hilary""/>
<Person ID=""19"" Name=""Sue""/>
</Person>
<Person ID=""98"" Name=""Bill""/>
<Person ID=""23"" Name=""Monica"">
<Person ID=""13"" Name=""Bill"">
<Person ID=""199"" Name=""Mabel""/>
</Person>
</Person>
<Person ID=""78"" Name=""Ginger"">
<Person ID=""99"" Name=""Fred""/>
</Person>
<Person ID=""55"" Name=""Harry"">
<Person ID=""80"" Name=""Sue"">
<Person ID=""45"" Name=""Bill""/>
</Person>
</Person>
</Root>";
 
M

Morten Wennevik [C# MVP]

Hi Alexander,

In addition to the other answers, if you are unwilling or unable to go the
Linq-To-Xml way, the xml nodes you get from SelectedNodes know who their
parents are so you can recreate the full tree. Below is a code sample
creating a List<Person> containing Bills and his parents.

protected override void OnLoad(EventArgs e)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);

XmlNodeList list = doc.SelectNodes("//Person[@Name='Bill']");

List<Person> people = CreateList(list);
}

private List<Person> CreateList(XmlNodeList list)
{
List<Person> people = new List<Person>();
foreach (XmlNode node in list)
{
Person p = new Person
{
ID = int.Parse(node.Attributes["ID"].Value),
Name = node.Attributes["Name"].Value
};

XmlNode parent = node.ParentNode;
while (parent != null && parent.ParentNode != null
&& parent.ParentNode.NodeType != XmlNodeType.Document)
{
int parentId = int.Parse(parent.Attributes["ID"].Value);
Person p2 = people.Find(x => x.ID == parentId);
if (p2 == null)
{
p2 = new Person
{
ID = parentId,
Name = parent.Attributes["Name"].Value
};
}

p2.Children.Add(p);
p = p2;
parent = parent.ParentNode;
}
people.Add(p);
}
return people;
}

[DebuggerDisplay("{ID} {Name} Children: {Children.Count}")]
public class Person
{
public int ID { get; set; }
public string Name { get; set; }
public List<Person> Children { get; set; }
public Person() { Children = new List<Person>(); }
}


string xml =
@"<Root>
<Person ID=""22"" Name=""John"">
<Person ID=""16"" Name=""Hilary""/>
<Person ID=""19"" Name=""Sue""/>
</Person>
<Person ID=""98"" Name=""Bill""/>
<Person ID=""23"" Name=""Monica"">
<Person ID=""13"" Name=""Bill"">
<Person ID=""199"" Name=""Mabel""/>
</Person>
</Person>
<Person ID=""78"" Name=""Ginger"">
<Person ID=""99"" Name=""Fred""/>
</Person>
<Person ID=""55"" Name=""Harry"">
<Person ID=""80"" Name=""Sue"">
<Person ID=""45"" Name=""Bill""/>
</Person>
</Person>
</Root>";
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top