On Feb 13, 9:32 pm, Joseph Kesselman <keshlam-nos...@comcast. net>
wrote:
johanneskrue... @gmx.net wrote:
>I'm trying to write a stylesheet which removes nodes which are empty
as a result of other template processing.
XSLT 1.0 doesn't have any built-in ability to do two-pass processing.
The usual solution is to run two stylesheets in succession, or the same
one twice.
If you MUST do it in a single stylesheet, the usual workaround is to use
the EXSLT node-set function. Do a first pass outputting into a variable
to obtain a Result Tree Fragment, then use exslt:node-set() to make that
available to XSLT in a form that it can walk over again, generating the
final output. Modes may be useful in keeping the two passes separate, if
the behavior is different in one than in the other.
(XSLT 2.0 -- still not widely supported, unfortunately, since it adds a
lot of complexity along with the simplifications -- eliminates the
distinction between node-sets and RTFs, and can do what I've just
described without needing a "standard nonstandard" helper.)
--
Joe Kesselman / Beware the fury of a patient man. -- John Dryden
Thanks for the help! As I would like to apply the templates in one
pass I've successfully used the approach of using included
stylesheets and modes described above. Here are the stylesheets:
first-pass.xsl:
<xsl:styleshe et version="1.0"
xmlns:xsl="http ://www.w3.org/1999/XSL/Transform"
xmlns:exslt="ht tp://exslt.org/common">
<xsl:output omit-xml-declaration="ye s" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- matches all nodes and attributes -->
<xsl:template match="node()|@ *" name="identity" mode="first-pass">
<xsl:copy>
<xsl:apply-templates select="node()| @*" mode="first-pass"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates mode="first-pass"/>
</xsl:template>
<!-- remove all b nodes -->
<xsl:template match="//b" priority="3" name="b-removal" mode="first-
pass"/>
</xsl:stylesheet>
second-pass.xsl:
<xsl:styleshe et version="1.0"
xmlns:xsl="http ://www.w3.org/1999/XSL/Transform"
xmlns:exslt="ht tp://exslt.org/common">
<xsl:output omit-xml-declaration="ye s" indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- matches all nodes and attributes -->
<xsl:template match="node()|@ *" name="identity" mode="second-pass">
<xsl:copy>
<xsl:apply-templates select="node()| @*" mode="second-pass"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates mode="second-pass"/>
</xsl:template>
<!-- rule for element "a", ought to reproduce a only if it has
children -->
<xsl:template match="//a" mode="second-pass">
<xsl:if test="count(./*) > 0">
<xsl:call-template name="identity"/>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
main.xsl:
<xsl:styleshe et version="1.0"
xmlns:xsl="http ://www.w3.org/1999/XSL/Transform"
xmlns:exslt="ht tp://exslt.org/common">
<xsl:output omit-xml-declaration="ye s" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:include href="first-pass.xsl"/>
<xsl:include href="second-pass.xsl"/>
<xsl:template match="/">
<xsl:variable name="first">
<xsl:apply-templates mode="first-pass" />
</xsl:variable>
<xsl:apply-templates select="exslt:n ode-set($first)" mode="second-
pass" />
</xsl:template>
</xsl:stylesheet>
Then with execution of main.xsl against the source xml, I get the
desired output:
<doc>
<a>
<c/>
</a>
</doc>
Thanks again.