Skip to content

Instantly share code, notes, and snippets.

@philippn
Last active September 6, 2019 16:47
Show Gist options
  • Save philippn/1a792ed79374f2c7fd51df696db931a4 to your computer and use it in GitHub Desktop.
Save philippn/1a792ed79374f2c7fd51df696db931a4 to your computer and use it in GitHub Desktop.
A XSL transformation that constructs a single bootstrap.xsl from a bunch of XSL files comprising a pipeline. Useful for getting a XSL pipeline to work in Saxon-JS. In order to do so, first run this XSL, then compile the resulting bootstrap.xsl into SEF format, i.e. by using Oxygen.
<xsl:stylesheet
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:variable name="steps" select="collection('./xsl?select=*.xsl')" as="node()*"/>
<xsl:template match="/">
<xsl:for-each select="$steps">
<xsl:sort select="tokenize(base-uri(.), '/')[last()]"/>
<xsl:variable name="filename" select="tokenize(base-uri(.), '/')[last()]" as="xs:string"/>
<xsl:variable name="fullname" select="substring-before($filename, '.xsl')"/>
<xsl:variable name="shortname" select="concat('step', position())"/>
<xsl:variable name="package-decl" as="element(xsl:package)">
<xsl:element name="package" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name" select="$fullname"/>
<xsl:attribute name="package-version" select="'1.0'"/>
<xsl:attribute name="declared-modes" select="'no'"/>
<xsl:attribute name="exclude-result-prefixes" select="'#all'"/>
<xsl:attribute name="version" select="'3.0'"/>
<xsl:namespace name="{$shortname}" select="concat('urn:pipeline:', $shortname)"/>
<xsl:element name="import" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="href" select="concat('./xsl/', $filename)"/>
</xsl:element>
<xsl:element name="function" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name" select="concat($shortname, ':main')"/>
<xsl:attribute name="as" select="'document-node()'"/>
<xsl:attribute name="visibility" select="'public'"/>
<xsl:element name="param" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name" select="'input'"/>
<xsl:attribute name="as" select="'document-node()'"/>
</xsl:element>
<xsl:element name="document" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:element name="apply-templates" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="select" select="'$input'"/>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:variable>
<xsl:result-document href="{concat('./package_', $fullname, '.xsl')}" indent="yes">
<xsl:sequence select="$package-decl"/>
</xsl:result-document>
</xsl:for-each>
<xsl:result-document href="./saxon-config.xml" indent="yes">
<configuration xmlns="http://saxon.sf.net/ns/configuration" edition="EE" label="Import packages">
<xsltPackages>
<xsl:for-each select="$steps">
<xsl:variable name="filename" select="tokenize(base-uri(.), '/')[last()]" as="xs:string"/>
<xsl:variable name="fullname" select="substring-before($filename, '.xsl')"/>
<package name="{$fullname}" version="1.0" sourceLocation="{concat('./package_', $fullname, '.xsl')}"/>
</xsl:for-each>
</xsltPackages>
</configuration>
</xsl:result-document>
<xsl:variable name="bootstrap-decl" as="element(xsl:stylesheet)">
<xsl:element name="stylesheet" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="exclude-result-prefixes" select="'#all'"/>
<xsl:attribute name="version" select="'3.0'"/>
<xsl:for-each select="$steps">
<xsl:variable name="shortname" select="concat('step', position())"/>
<xsl:namespace name="{$shortname}" select="concat('urn:pipeline:', $shortname)"/>
</xsl:for-each>
<xsl:for-each select="$steps">
<xsl:variable name="filename" select="tokenize(base-uri(.), '/')[last()]" as="xs:string"/>
<xsl:variable name="fullname" select="substring-before($filename, '.xsl')"/>
<xsl:element name="use-package" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name" select="$fullname"/>
<xsl:attribute name="version" select="'1.0'"/>
</xsl:element>
</xsl:for-each>
<xsl:element name="template" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="match" select="'/'"/>
<xsl:for-each select="$steps">
<xsl:variable name="input-pointer">
<xsl:choose>
<xsl:when test="position() eq 1">
<xsl:value-of select="'.'"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat('$result', position()-1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:element name="variable" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="name" select="concat('result', position())"/>
<xsl:attribute name="select" select="concat('step', position(), ':main(', $input-pointer, ')')"/>
<xsl:attribute name="as" select="'document-node()'"/>
</xsl:element>
</xsl:for-each>
<xsl:element name="sequence" namespace="http://www.w3.org/1999/XSL/Transform">
<xsl:attribute name="select" select="concat('$result', count($steps))"/>
</xsl:element>
</xsl:element>
</xsl:element>
</xsl:variable>
<xsl:result-document href="./bootstrap.xsl" indent="yes">
<xsl:sequence select="$bootstrap-decl"/>
</xsl:result-document>
</xsl:template>
</xsl:stylesheet>
@gimsieke
Copy link

gimsieke commented Sep 6, 2019

Excellent, thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment