Reputation: 253
I am working with XSLT 2.0 and trying to apply the same transformation process to both elements from the input XML and elements dynamically created within the XSLT.
<?xml version="1.0" encoding="UTF-8"?>
<document>
<h2>General Introduction</h2>
<h3>Project Overview</h3>
<h3>Goals and Challenges</h3>
<h2>Installation</h2>
<h3>Initial Configuration</h3>
<h4>Configuration File</h4>
<h3>Deployment</h3>
<h4>On a Local Server</h4>
<h4>On a Remote Server</h4>
<h2>Usage</h2>
<h3>Basic Commands</h3>
<h3>Advanced Options</h3>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/document">
<html>
<body>
<xsl:apply-templates/>
<h3>Dynamic title (was not in the XML)</h3>
</body>
</html>
</xsl:template>
<xsl:template match="h2 | h3 | h4">
<xsl:element name="{name()}">
¶<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
The transformation correctly applies to <h2>, <h3>, and <h4>
elements from the original XML.
However, the dynamically created element:
<h3>Dynamic title (was not in the XML)</h3>
is not processed by the template that matches h2 | h3 | h4
.
How can I ensure that both XML elements and dynamically created elements undergo the same transformation process? Is there a way to reapply templates to generated elements within XSLT?
Upvotes: 0
Views: 21
Reputation: 163587
As an alternative to Martin's solution, which does two processing passes over the entire document, you could locally process the dynamic element like this:
<xsl:template match="/document">
<html>
<body>
<xsl:apply-templates/>
<xsl:variable name="temp">
<h3>Dynamic title (was not in the XML)</h3>
</xsl:variable>
<xsl:apply-templates select="$temp"/>
</body>
</html>
</xsl:template>
Upvotes: 2
Reputation: 167716
Use a variable as a temporary result and probably better different modes to separate the processing steps:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:mode name="step1" on-no-match="shallow-copy"/>
<xsl:mode name="step2" on-no-match="shallow-copy"/>
<xsl:variable name="result1">
<xsl:apply-templates mode="step1"/>
</xsl:variable>
<xsl:template match="/">
<xsl:apply-templates select="$result1" mode="step2"/>
</xsl:template>
<xsl:template mode="step1" match="/document">
<html>
<body>
<xsl:apply-templates mode="#current"/>
<h3>Dynamic title (was not in the XML)</h3>
</body>
</html>
</xsl:template>
<xsl:template mode="step2" match="h2 | h3 | h4">
<xsl:element name="{name()}">
¶<xsl:value-of select="."/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
I have used XSLT 3's xsl:mode
declaration to set up the default identity transformation for the used modes as all supported versions of Saxon are XSLT 3 processors; if you still work with a version of Saxon that only supports XSLT 2 you could use
<xsl:template match="@* | node()" mode="step1 step2">
<xsl:copy>
<xsl:apply-templates select="@* | node()" mode="#current"/>
</xsl:copy>
</xsl:template>
instead.
Upvotes: 1