![]() |
XSLT to produce subtree of a tree
I am trying to write an XSLT template which creates a subtree of an input document, which is a simple tree. For example, the input might be <node name="1"/> <node name="2"> <node name="2.1"/> <node name="2.2"/> </node> <node name="3"/> I pass the template a parameter "2.2" and it creates the following result fragment: <node name="2"> <node name="2.2"/> </node> There is clearly one inefficient way of doing this: <xsl:template match="node[.//node[@name='2.2']]"> <xsl:copy><xsl:apply-templates/></xsl:copy> </xsl:template> But it seems a shame to evaluate that XPath expression on each node. There ought also to be a recursive way of doing it, like this: <xsl:template match="node"> <xsl:choose> <xsl:when test="@name='2.2'"><xsl:copy/></xsl:when> <xsl:otherwise> <xsl:variable name="children"><xsl:apply-templates/></xsl:variable> <xsl:if test="$children"> <xsl:copy><xsl:copy-of select="$children"/></xsl:copy> </xsl:if> </xsl:otherwise> </xsl:choose> </xsl:template> Unfortunately this doesn't work. The reason, AFAICT, is that the Boolean value of a result tree fragment is always true, because it always contains a hidden root node. Can anybody either solve this particular problem of how to tell when a result tree fragment is empty, or tell me a better way to approach this? Many thanks Martin Bright |
Re: XSLT to produce subtree of a tree
"Martin Bright" <martin@boojum.org.uk> wrote in message news:Xns948585CFAB16Amartinboojumorguk@138.253.100 .85... > > I am trying to write an XSLT template which creates a subtree of an input > document, which is a simple tree. For example, the input might be > > <node name="1"/> > <node name="2"> > <node name="2.1"/> > <node name="2.2"/> > </node> > <node name="3"/> > > I pass the template a parameter "2.2" and it creates the following result > fragment: > > <node name="2"> > <node name="2.2"/> > </node> First of all, do notice that the source xml document provided in your message is not well-formed. This transformation: <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:param name="pNodeID" select="2.2"/> <xsl:template match="/"> <xsl:apply-templates select="//node[@name = $pNodeID]"/> </xsl:template> <xsl:template match="node"> <xsl:apply-templates select="ancestor::*[last()]" mode="gen"> <xsl:with-param name="pPath" select=".|ancestor::node[position()< last()]" /> </xsl:apply-templates> </xsl:template> <xsl:template match="*" mode="gen"> <xsl:param name="pPath" select="/.."/> <xsl:copy> <xsl:copy-of select="@*"/> <xsl:apply-templates select="$pPath[1]" mode="gen"> <xsl:with-param name="pPath" select="$pPath[position() > 1]"/> </xsl:apply-templates> </xsl:copy> </xsl:template> </xsl:stylesheet> when applied on your source.xml (corrected in order to become well-formed): <node name="0"> <node name="1"/> <node name="2"> <node name="2.1"/> <node name="2.2"/> </node> <node name="3"/> </node> produces the desired result: <node name="0"> <node name="2"> <node name="2.2"/> </node> </node> Hope this helped. Cheers, Dimitre Novatchev [XML MVP], FXSL developer, XML Insider, http://fxsl.sourceforge.net/ -- the home of FXSL Resume: http://fxsl.sf.net/DNovatchev/Resume/Res.html |
| All times are GMT. The time now is 08:39 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.