Hello everyone,
The DITA Open Toolkit<https://www.dita-ot.org/> allows plugin stylesheets to
be incorporated into processing via <xsl:import>. To keep my plugin code
robust against future DITA-OT processing changes and other plugins, I call
<xsl:next-match> and postprocess the results where possible. And XSLT 3.0 with
shallow-copy moded templates make postprocessing pretty easy!
I'm hitting a case where the existing code passes non-tunneling parameters
from template A to B, with parameter defaults computed in template B. And when
I try to wedge my processing between A and B using <xsl:next-match>, I can't
get template B to properly receive parameters from A only when they're
passed.
For example, given the following XML input:
<?xml version="1.0" encoding="utf-8" ?>
<body>
<note type="note">This is note 1.</note>
<note type="caution">This is an important note 2.</note>
<note type="unknown">This is some other note 3.</note>
</body>
and the original processing code:
<?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" exclude-result-prefixes="#all"
version="3.0">
<xsl:mode on-no-match="shallow-copy"/>
<!-- A1 - default note -->
<xsl:template match="note">
<xsl:apply-templates select="." mode="B"/>
</xsl:template>
<!-- A2 - Caution note -->
<xsl:template match="note[@type = 'caution']">
<xsl:apply-templates select="." mode="B">
<xsl:with-param name="title" select="'Caution'"/>
</xsl:apply-templates>
</xsl:template>
<!-- A3 - fallback for unknown note types -->
<xsl:template match="note[@type = 'unknown']">
<xsl:apply-templates select="." mode="B">
<xsl:with-param name="type" select="'note'"/>
</xsl:apply-templates>
</xsl:template>
<!-- B -->
<xsl:template match="*" mode="B">
<xsl:param name="type" select="@type"/>
<xsl:param name="title" select="'Note'"/> <!-- this is actually
complicated string lookup code I don't want to replicate -->
<span class="{$type}"><xsl:value-of select="$title"/>: <xsl:sequence
select="node()"/></span>
</xsl:template>
</xsl:stylesheet>
then the result is as follows:
<?xml version="1.0" encoding="UTF-8"?><body>
<span class="note">Note: This is note 1.</span>
<span class="caution">Caution: This is an important note 2.</span>
<span class="note">Note: This is some other note 3.</span>
</body>
The second element shows the "Caution" title computed in B, and the third
element shows the "note" type passed from A3.
But when I try to insert my own processing between A and B:
<!-- B-prime -->
<xsl:template match="*" mode="B" priority="10"> <!-- (priority emulates
<xsl:next-match>) -->
<xsl:param name="type"/>
<xsl:param name="title"/>
<!-- ...post-processing... -->
<xsl:next-match>
<xsl:with-param name="type" select="$type"/>
<xsl:with-param name="title" select="$title"/>
</xsl:next-match>
</xsl:template>
then note 1 and 2's type is empty because B-prime passes an empty sequence for
the "type" parameter that bypasses B's default value. And if I remove the
parameter stuff from B-prime, then the title for note 3 never gets through
B-prime.
How can I get sometimes-defined parameters passed through B-prime? Tunnelling
is the correct solution, but the A and B templates (which I can't modify) do
not define them as tunnelling parameters. I tried using <xsl:if> inside
<xsl:next-match/> to selectively pass defined parameters, but it isn't
allowed.
I want B-prime to be as ignorant as possible about the outside world, but
maybe that's not possible here.
Thanks!
-----
Chris Papademetrious
Tech Writer, Implementation Group
(610) 628-9718 home office
(570) 460-6078 cell
|