Extending XSLT by Patching Saxon and Xalan

The XML Pipeline in XSLT technique requires every xsl:template and xsl:apply-templates in the chained stylesheet to have mode attribute.

This could be simplified if XSLT would allow specifying mode in xsl:include. So <xsl:include href="link1.xsl" mode="link1"/> would mean "use link1 as default mode in link1.xsl":

  1. if xsl:template or xsl:apply-templates in the contained stylesheet do not have mode attribute, they receive it from xsl:include the stylesheet was included with
  2. if you still want to reference default mode from link1.xsl, you should use mode="#default"
  3. if link1.xsl includes identity.xsl, link1 mode is tunneled to identity.xsl.

If xsl:include/@mode would be available in XSLT processors, XML Pipeline code would look much simpler:

  • chain.xsl
    <?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
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    	<xsl:import href="identity.xsl" />
    
        <xsl:template match="a">
            <aa>
                <xsl:apply-templates select="@*|node()"/>
                <b/>
            </aa>
        </xsl:template>
    
    </xsl:stylesheet>
    
  • link2.xsl
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    	<xsl:import href="identity.xsl" />
    
        <xsl:template match="b">
            <bb>
                <xsl:apply-templates select="@*|node()"/>
                <c/>
            </bb>
        </xsl:template>
    
    </xsl:stylesheet>
    
  • link3.xsl
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    	<xsl:import href="identity.xsl" />
    
        <xsl:template match="c">
            <cc>
                <xsl:apply-templates select="@*|node()"/>
            </cc>
        </xsl:template>
    
    </xsl:stylesheet>
    
  • identity.xsl
    <?xml version="1.0" encoding="UTF-8"?>
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
        <xsl:template priority="-9" match="@*|node()">
            <xsl:copy>
                <xsl:apply-templates select="@*|node()"/>
            </xsl:copy>
        </xsl:template>
    
    </xsl:stylesheet>
    

Attached you can find my patches to Saxon 9.1 and Xalan-J 2.7.1 enabling @mode in xsl:include.

AttachmentSize
xml-pipeline2.zip6.48 KB

Comments

Michael Kay from Saxon kindly

Michael Kay from Saxon kindly suggested standard-compliant way of handling xsl:include/@mode:

Post new comment

The content of this field is kept private and will not be shown publicly.