Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   XML (http://www.velocityreviews.com/forums/f32-xml.html)
-   -   XSLT to produce subtree of a tree (http://www.velocityreviews.com/forums/t166553-xslt-to-produce-subtree-of-a-tree.html)

Martin Bright 02-04-2004 01:09 PM

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

Dimitre Novatchev [MVP] 02-04-2004 07:36 PM

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()&lt; 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.