The xsl:include/@mode patchset I have developed to ease XML Pipeline in XSLT is not good. The major problem is it won't work on closed-source XSLT processors (Saxon PE/EE for example).
As suggested by Michael Kay, there is a standard compliant way to implement above:
<xsl:include href="link1.xsl?mode=link1"/>
It would work by means of custom URIResolver performing XSLT preprocessing.
Using this approach chain.xsl would look like
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exsl="http://exslt.org/common">
<xsl:output method="xml" omit-xml-declaration="no" indent="no" encoding="UTF-8"/>
<xsl:include href="link1.xsl?mode=link1"/>
<xsl:include href="link2.xsl?mode=link2"/>
<xsl:include href="link3.xsl?mode=link3"/>
<xsl:template match="/">
<xsl:variable name="link1">
<xsl:apply-templates mode="link1" select="node()"/>
</xsl:variable>
<xsl:variable name="link2">
<xsl:apply-templates mode="link2" select="exsl:node-set($link1)/node()"/>
</xsl:variable>
<xsl:variable name="link3">
<xsl:apply-templates mode="link3" select="exsl:node-set($link2)/node()"/>
</xsl:variable>
<xsl:copy-of select="exsl:node-set($link3)/node()"/>
</xsl:template>
</xsl:stylesheet>
, link1.xsl, link2.xsl, link3.xsl and identity.xsl will be the same as in previous variant.
I have implemented ?mode in xsl:include/@href, and it works great.
The implementation works by using custom URIResolver and SAX ContentHandler transformation. The ContentHandler transformation is implemented in Java and is on-the-fly transforming XSLT source code adding mode attribute where necessary.
The reason I choose SAX ContentHandler approach over simpler XSLT like
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="no" indent="no" encoding="UTF-8"/>
<xsl:param name="mode"/>
<xsl:template priority="-9" match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xsl:template[@match and not(@mode)] | xsl:apply-templates[not(@mode)]">
<xsl:copy>
<xsl:attribute name="mode">
<xsl:value-of select="$mode"/>
</xsl:attribute>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="xsl:include/@href | xsl:import/@href">
<xsl:attribute name="{name()}">
<xsl:choose>
<xsl:when test="contains(., '?')">
<xsl:value-of select="concat(., '&mode=', $mode)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(., '?mode=', $mode)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:template>
</xsl:stylesheet>
is because ContentHandler approach preserves line number information: if you'll make an error in the source, processor will report exact line/col position of error; w/ above XSLT that is not possible.
You can find ZIP w/ full source code attached below.
| Attachment | Size |
|---|---|
| xml-pipeline3.zip | 8.88 KB |
Comments
Post new comment