if i have an xml-doc in memory and
all nodes have a name-Attribute.
Now i want all nodes whose name is "Bill".
Easy.
But i want not the nodes named bill as a flat list/array
but rather as a partial tree.
Is there a tool (e.g XPath or Linq-To-XML#1)
that supports queries that return "partial" trees?
I need something that kind of filters the tree or
hiding the dat that doesn't match, leaving the original
structure, namely teh branching levels intact.
Example:
*Org-tree*:
Root
|--John
| |--Hilary
| |--Sue
|
|--Monica
| |--Bill
|
|--Ginger
|--Fred
*Result Tree of query for Name "Bill"*:
Root
|--Monica
|--Bill
#1Btw I do this in a .NET-Project so if Linq-To-Xml did the trick it'd
be nice.
MfG,
Alex
Better Example:
A Node now consists of two attributes: ID and Name
which are separated by a backslash in the demo
*Org-tree*:
0/Root
|--22/John
| |--16/Hilary
| |--19/Sue
|
|--98/Bill
|
|--23/Monica
| |--13/Bill
|
|--78/Ginger
| |--99/Fred
|
|--55/Harry
|--80/Sue
|--45/Bill
The desired result should look like:
*QueriedTree*:
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
It there a library, query-language, API or whatever
that has *built*-*in* support for returning matches of
queries on XML-data in tree-like structure?
All help & hints very much appreciated,
Alex
XPath does not change the tree at all, it can only select nodes in an
existing tree. If you want to transform the tree then you need XSLT or
XQuery or DOM or LINQ to XML.
With XSLT you would transform the input tree into a result tree;
assuming the input tree is
<node id="0" name="Root">
<node id="22" name="John">
<node id="16" name="Hilary"/>
<node id="19" name="Sue"/>
</node>
<node id="98" name="Bill"/>
<node id="23" name="Monica">
<node id="13" name="Bill"/>
</node>
<node id="78" name="Ginger">
<node id="99" name="Fred"/>
</node>
<node id="55" name="Harry">
<node id="80" name="Sue">
<node id="45" name="Bill"/>
</node>
</node>
</node>
then this stylesheet
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output indent="yes"/>
<xsl:template match="node[descendant-or-self::node[@name = 'Bill']]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:apply-templates select="node"/>
</xsl:copy>
</xsl:template>
<xsl:template match="node"/>
</xsl:stylesheet>
would create the output
<node id="0" name="Root">
<node id="98" name="Bill"/>
<node id="23" name="Monica">
<node id="13" name="Bill"/>
</node>
<node id="55" name="Harry">
<node id="80" name="Sue">
<node id="45" name="Bill"/>
</node>
</node>
</node>
With LINQ to XML you would have the possibility to change the input tree
or to create a new. Here is an example that creates a new one, input is
as above:
static void Main(string[] args)
{
XDocument doc = XDocument.Load(@"..\..\XMLFile1.xml");
XDocument doc2 = Filter(doc, "Bill");
doc2.Save(Console.Out);
}
static XDocument Filter(XDocument input, string name)
{
return new XDocument(Filter(input.Root, name));
}
static XElement Filter(XElement node, string name)
{
return
node
.DescendantsAndSelf("node")
.Any(n => (string)n.Attribute("name") == name) ?
new XElement(
node.Name,
node.Attributes(),
from child in node.Elements("node") select
Filter(child, name)) : null;
}
Result is also as above.
--
Martin Honnen --- MVP XML
http://msmvps.com/blogs/martin_honnen/
Is there a way to dynamically create such an XSLT-transformation by
code?
I want my queries on the tree to be flexible and user-defined
so i can't code a xslt-file for each of them.
Can I build a xsl-stylesheet in memory with the .NET-XML-Api?
> With LINQ to XML you would have the possibility to change the input tree
> or to create a new. Here is an example that creates a new one, input is
> as above:
>
> static void Main(string[] args)
> {
> XDocument doc = XDocument.Load(@"..\..\XMLFile1.xml");
> XDocument doc2 = Filter(doc, "Bill");
> doc2.Save(Console.Out);
> }
>
> static XDocument Filter(XDocument input, string name)
> {
> return new XDocument(Filter(input.Root, name));
> }
>
> static XElement Filter(XElement node, string name)
> {
> return
> node
> .DescendantsAndSelf("node")
> .Any(n => (string)n.Attribute("name") == name) ?
> new XElement(
> node.Name,
> node.Attributes(),
> from child in node.Elements("node") select
> Filter(child, name)) : null;
>
> }
>
> Result is also as above.
Thanks the linq-to xml solution also looks good to me.
MfG,
Alex
> Is there a way to dynamically create such an XSLT-transformation by
> code?
> I want my queries on the tree to be flexible and user-defined
> so i can't code a xslt-file for each of them.
> Can I build a xsl-stylesheet in memory with the .NET-XML-Api?
First of all XSLT stylesheet can have global parameters that you can set
with your .NET code before your .NET code runs a transformation with an
XSLT stylesheet, see
http://msdn.microsoft.com/en-us/library/system.xml.xsl.xsltargumentlist.addparam.aspx
And then XSLT stylesheets are XML documents which you can create with
.NET XML APIs like System.Xml.XmlDocument or System.Xml.Linq.XDocument
in memory if you want, and then use
http://msdn.microsoft.com/en-us/library/ms163422.aspx for instance to
load from an XmlDocument.