Reputation:
I need to specify the output order from a html file to a text file. Therefore I use the xsl:apply-templates select approach. It works ok but in order to fine tune the output of the different nodes I need a corresponding template, not just a general one. This also works ok but I need to repeat the select pattern in the match pattern for the template.
I like to define a variable that holds the pattern so it only needs to be defined once. Below is my simplified style sheet and simplified html which does not work but gives an idea of what I want to accomplish. Is it possible to use variables like this? I can use both xslt 1.0 and 2.0 if needed.
<xsl:stylesheet ...>
...
<xsl:variable name="first">div[@class='one']</xsl:variable>
<xsl:variable name="second">div[@class='two']</xsl:variable>
<xsl:template match="/*">
<xsl:apply-templates select="//$first"/>
<xsl:apply-templates select="//$second"/>
...
</xsl:template>
<xsl:template match="//$first">
<xsl:text>Custom text for class one:</xsl:text><xsl:value-of select="text()"/>
</xsl:template>
<xsl:template match="//$second">
<xsl:text>Custom text for class two:</xsl:text><xsl:value-of select="text()"/>
</xsl:template>
</xsl:stylesheet>
The html:
...
<div class="two">text from two</div>
<div class="one">text from one </div>
...
Desired output:
Custom text for class one: text from one
Custom text for class two: text from two
Upvotes: 1
Views: 2363
Reputation: 163322
Variables in XSLT hold values, not fragments of expressions. (In other words, XSLT is not a macro language).
As an alternative to Martin's solution, which requires XSLT 3.0, you could consider using what are sometimes called "meta-stylesheets" - do a transformation as a pre-processing step on the stylesheet itself. You could even write the generic stylesheet to use the XSLT 3.0 syntax with shadow attributes like _match, and do an XSLT preprocessing phase to convert this to regular XSLT 1.0 or 2.0 syntax for execution.
Upvotes: 1
Reputation: 167571
There is no way to use variables like that in XSLT 1 or 2. The only way would be to write a stylesheet producing a second stylesheet and execute that separately.
In XSLT 3 there are new features called static variables/parameters and shadow attributes that could help or there you could use the transform
function to execute a newly generated stylesheet directly with XSLT instead of in a separate step with a host language.
But using XSLT 2 you can shorten the
<xsl:apply-templates select="//div[@class='one']"/>
<xsl:apply-templates select="//div[@class='two']"/>
to
<xsl:apply-templates select="//div[@class='one'], //div[@class='two']"/>
For completeness here is the XSLT 3 approach with two static parameters used in shadow attributes:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
exclude-result-prefixes="xs math"
version="3.0">
<xsl:param name="first" static="yes" as="xs:string" select=""div[@class='one']""/>
<xsl:param name="second" static="yes" as="xs:string" select=""div[@class='two']""/>
<xsl:template match="/*">
<xsl:apply-templates _select="//{$first}, //{$second}"/>
</xsl:template>
<xsl:template _match="{$first}">
<xsl:text>Custom text for class one:</xsl:text><xsl:value-of select="text()"/>
</xsl:template>
<xsl:template _match="{$second}">
<xsl:text>Custom text for class two:</xsl:text><xsl:value-of select="text()"/>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2