Reputation: 1274
I need to apply several XSL stylesheets to an input document but the stylesheet to be imported have some templates named with identical names.
Here is what I need to do:
<xsl:import href="convert_from_a_to_b.xsl"/>
<xls:import href="convert_from_b_to_c.xsl"/>
<xsl:template match="//root">
<new_root_element>
<xsl:apply-templates select="./*"/> <!-- handle some transformations in this stylesheet -->
</new_root_element>
</xsl:template>
<xsl:template match="content_to_convert"/> <!-- the element and its content to be transformed -->
<content>
<xsl:variable name="convertedContent">
<xsl:next-match/>
<xsl:apply-templates select="./*"/> <!-- this should be from convert_a_to_b -->
</xsl:variable>
<xsl:next-match/>
<xsl:apply-templates select="$convertedContent"/> <!-- this should be from convert_b_to_c -->
</content>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
convert_a_to_b.xsl
<xsl:include href="ab_include.xsl"/>
<xsl:template match="/" name="baseContent">
<xsl:param name="in" select="//SubRoot/root/content_to_convert"/>
<!-- more processing -->
</xsl:template>
</xsl:template>
ab_include.xsl
<xsl:template name="template-1234">
<xsl:param name="in" select="."/>
<!-- more processing -->
</xsl:template>
<xsl:template match="subSet">
<xsl:for-each select="./something">
<xsl:call-template name="template-1234">
<xsl:with-param name="in" select="./detail"/>
<xsl:call-template>
</xsl:for-each>
</xsl:template>
convert_b_to_c.xsl
<xsl:include href="bc_include.xsl"/>
<xsl:template match="/" name="baseContent">
<xsl:param name="in" select="//converted_to_a"/>
<xsl:choose>
<xsl:when test="count($in) gt 1">
<batch xmlns="">
<xsl:for-each select="$in">
<xsl:call-template name="subTemplate">
<xsl:with-param name="param1" select="value1"/>
<xsl:with-param name="param2" select="value2"/>
</xsl:call-template>
</xsl:for-each>
</batch>
</xsl:when>
<xsl:otherwise>
xsl:call-template name="subTemplate">
<xsl:with-param name="param1" select="$in/value1"/>
<xsl:with-param name="param2" select="$in/value2"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template name="subTemplate">
<xsl:param name="param1"/>
<xsl:param name="param2"/>
<!-- more processing -->
</xsl:template>
bc_include.xsl
<xsl:template name="template-1234">
<xsl:param name="time" select="."/>
<!-- more processing -->
</xsl:template>
<xsl:template match="otherSubSet">
<xsl:for-each select="./somethingElse">
<xsl:call-template name="template-1234">
<xsl:with-param name="time" select="./detail"/>
<xsl:call-template>
</xsl:for-each>
</xsl:template>
Input_file.xml
<SomeRoot>
<SubRoot>
<root>
<content_to_be_copied_over/> <!-- this I can handle -->
<content_to_convert>
<!-- all kinds of data to be converted -->
</content_to_convert>
</root>
<root>
<content_to_be_copied_over/> <!-- this I can handle -->
<content_to_convert>
<!-- all kinds of data to be converted -->
</content_to_convert>
</root>
<root>
<content_to_be_copied_over/> <!-- this I can handle -->
<content_to_convert>
<!-- all kinds of data to be converted -->
</content_to_convert>
</root>
</SubRoot>
</SomeRoot>
Output should be:
<SomeRoot>
<SubRoot>
<new_root_element>
<content>
<!-- converted content -->
</content>
</new_root_element>
<new_root_element>
<content>
<!-- converted content -->
</content>
</new_root_element>
<new_root_element>
<content>
<!-- converted content -->
</content>
</new_root_element>
</SubRoot>
</SomeRoot>
However, both stylesheets a lot of includes and have several templates with the same name (e.g. 'template-1234') but different parameters. They have no dependency on each other, but deep down in the included stylesheet stacks they might include the same XSL stylesheet.
The above works if I only import the first stylesheet but after adding the second import I get errors about missing parameters.
E.g. I get an error parameter in is not declared in the called template
.
I cannot change the stylesheets, because they are produced and maintained by a different group. I can only use them.
Is there a way I can isolate the stylesheets so I can use both in 1 stylesheet and indicate which one I want to use?
NB. I use xslt 3.0 in OxygenXMLEditor with Saxon PE 11.4
Upvotes: 0
Views: 95
Reputation: 167716
To elaborate from my suggestion in the comment, as you are using XSLT 3 and as you seem to want to chain stylesheets without being able to edit them, it appears one way is to use fn:transform
with fold-left
e.g. fold-left(('convert_from_a_to_b.xsl', 'convert_from_b_to_c.xsl'), $some-node, function($a, $s) { transform(map{'source-node': $a, 'stylesheet-node': doc($s) })?output })
, perhaps, in the context of your example
<xsl:template match="content_to_convert"/> <!-- the element and its content to be transformed -->
<content>
<xsl:sequence
select="fold-left(('convert_from_a_to_b.xsl', 'convert_from_b_to_c.xsl'), ., function($a, $s) { transform(map{'source-node': $a, 'stylesheet-node': doc($s) })?output })"/>
</content>
</xsl:template>
I can't tell in detail what you are trying to achieve and whether the suggestion helps and works out, to provide a working example see the directory https://github.com/martin-honnen/martin-honnen.github.io/tree/master/xslt/2023/chain-stylesheets-using-fold-left which chains three stylesheets sheet1.xsl
, sheet2.xsl
, sheet3.xsl
by using the suggested fold-left
/transform
combination from the new main stylesheet fold-left-transform-sample1.xml
on the input sample-input1.xml
; the stylesheet doing nothing but the identity transformation plus adding a comment that they processed the input, so with the input being e.g.
<root>This is a test sample.</root>
the result of processing the input file with Saxon and the XSLT file fold-left-transform-sample1.xml
from https://raw.githubusercontent.com/martin-honnen/martin-honnen.github.io/master/xslt/2023/chain-stylesheets-using-fold-left/fold-left-transform-sample1.xsl is e.g.
<?xml version="1.0" encoding="UTF-8"?>
<root>This is a test sample.</root>
<!--Processed by https://raw.githubusercontent.com/martin-honnen/martin-honnen.github.io/master/xslt/2023/chain-stylesheets-using-fold-left/sheet1.xsl with SAXON HE 11.5 at 2023-02-28T17:23:57.3777158+01:00-->
<!--Processed by https://raw.githubusercontent.com/martin-honnen/martin-honnen.github.io/master/xslt/2023/chain-stylesheets-using-fold-left/sheet2.xsl with SAXON HE 11.5 at 2023-02-28T17:23:57.406232+01:00-->
<!--Processed by https://raw.githubusercontent.com/martin-honnen/martin-honnen.github.io/master/xslt/2023/chain-stylesheets-using-fold-left/sheet3.xsl with SAXON HE 11.5 at 2023-02-28T17:23:57.4349873+01:00-->
The stylesheet does e.g.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="3.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
expand-text="yes">
<xsl:param name="xslt-uris" as="xs:string*" select="'sheet1.xsl', 'sheet2.xsl', 'sheet3.xsl'"/>
<xsl:output indent="yes"/>
<xsl:template match="/" name="xsl:initial-template">
<xsl:sequence
select="fold-left($xslt-uris, /, function($a, $s) { transform(map{'source-node': $a, 'stylesheet-node': doc($s) })?output })"/>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1