2017年の4月頃からずっとxsl:packageに興味を持ちいろいろやってみたのですが、仕様を読む力不足でなかなか動くところまでたどり着きませんでした.すこしだけですが試せるところまで来れたので、紹介します.
まずxsl:packageを作るのは、それほど難しくありません.例えば
[test-pkg-xslt3.xsl]
<?xml version="1.0" encoding="UTF-8"?>
<xsl:package xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:ahf="http://www.antennahouse.com/Names/XSLT/Document"
package-version="1.0"
name="urn:test:pkg:xslt3"
exclude-result-prefixes="xs ahf"
version="3.0"
default-mode="normal">
<xsl:mode name="normal" visibility="public"/>
<xsl:mode/>
<xsl:template match="*[contains(@class,' topic/ph ')]" name="tplPh">
<fo:inline>
<xsl:apply-templates/>
</fo:inline>
</xsl:template>
<xsl:package xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:ahf="http://www.antennahouse.com/Names/XSLT/Document"
package-version="1.0"
name="urn:test:pkg:xslt3"
exclude-result-prefixes="xs ahf"
version="3.0"
default-mode="normal">
<xsl:mode name="normal" visibility="public"/>
<xsl:mode/>
<xsl:template match="*[contains(@class,' topic/ph ')]" name="tplPh">
<fo:inline>
<xsl:apply-templates/>
</fo:inline>
</xsl:template>
<xsl:template match="*[contains(@class,' hi-d/b ')]" priority="2" name="tplB">
<fo:inline font-weight="bold">
<xsl:apply-templates/>
</fo:inline>
</xsl:template>
<xsl:function name="ahf:setRed" as="attribute()*" visibility="public">
<xsl:attribute name="color" select="'red'"/>
</xsl:function>
</xsl:package>
<fo:inline font-weight="bold">
<xsl:apply-templates/>
</fo:inline>
</xsl:template>
<xsl:function name="ahf:setRed" as="attribute()*" visibility="public">
<xsl:attribute name="color" select="'red'"/>
</xsl:function>
</xsl:package>
などと書けます.@visibility="public"としてやれば、外部からxsl:functionは使えるはずです.またこの時点では、xsl:templateも
- xsl:package/@default-mode="normal"で
- <xsl:mode name="normal" visibility="public"/>としてあるので
使えるものと思っていました.
問題はxsl:packageを使用する方、つまりxsl:use-packageの方です.例えば上記のパッケージを使うためには、@nameで指定されたURIを指定してやります.
<xsl:use-package name="urn:test:pkg:xslt3"/>
ここで疑問に思うのは、xsl:use-package/@nameはxsl:include/@href, xsl:import/@hrefと同じようにURIなのですが、@package-versionとかも指定できるので、通常のURI⇒実際のファイルパスというマッピングに使用される機構、例えばOASISのカタログファイルのようなものでは役不足ということなのです.このマッピングはXSLTプロセッサのインプリメンテーションにより異なります.
例えばSaxonは最新のバージョンではSaxonのコンフィグレーションファイルに指定します.コンフィグレーションファイルはSaxonのコマンドラインの-configパラメータで指定します.
[Saxonのコンフィグレーションファイルの例]
<?xml version="1.0" encoding="UTF-8"?>
<configuration xmlns="http://saxon.sf.net/ns/configuration"
edition="EE">
<xsltPackages>
<package name="urn:test:pkg:xslt3" version="1.0" sourceLocation="test-pkg-xslt3.xsl"/>
<package name="urn:test:pkg2:xslt3" version="1.0" sourceLocation="test-pkg2-xslt3.xsl"/>
</xsltPackages>
</configuration>
<configuration xmlns="http://saxon.sf.net/ns/configuration"
edition="EE">
<xsltPackages>
<package name="urn:test:pkg:xslt3" version="1.0" sourceLocation="test-pkg-xslt3.xsl"/>
<package name="urn:test:pkg2:xslt3" version="1.0" sourceLocation="test-pkg2-xslt3.xsl"/>
</xsltPackages>
</configuration>
また例えばまだβ版ですが.NETで動くExselt(http://www.exselt.net/)は同様にパッケージカタログファイルというものを用意し、コマンドラインの-pcパラメータで指定します.
<?xml version="1.0" encoding="UTF-8"?>
<package-catalog xmlns="http://exselt.net/package-catalog"
default-file-extension="pxsl">
<packages>
<package name="urn:test:pkg:xslt3"
version="1.0"
href="file:/C:/Users/toshi/OneDrive/Documents/test/xslt/20170718-package/test-pkg-xslt3.xsl"/>
<package name="urn:test:pkg2:xslt3"
version="1.0"
href="file:/C:/Users/toshi/OneDrive/Documents/test/xslt/20170718-package/test-pkg2-xslt3.xsl"/>
</packages>
</package-catalog>
<package-catalog xmlns="http://exselt.net/package-catalog"
default-file-extension="pxsl">
<packages>
<package name="urn:test:pkg:xslt3"
version="1.0"
href="file:/C:/Users/toshi/OneDrive/Documents/test/xslt/20170718-package/test-pkg-xslt3.xsl"/>
<package name="urn:test:pkg2:xslt3"
version="1.0"
href="file:/C:/Users/toshi/OneDrive/Documents/test/xslt/20170718-package/test-pkg2-xslt3.xsl"/>
</packages>
</package-catalog>
文句を言えばですが、まだまだXSLT 3.0のインプリメンテーションは初歩的で、このようなものを大規模なスタイルシート開発でいちいち用意するのは大変に思えます.すくなくともパッケージ毎に分割して記述し、それをインクルードできるような仕組みが必要に思えます.
これでメインの側で
<?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"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:ahf="http://www.antennahouse.com/Names/XSLT/Document"
exclude-result-prefixes="xs math ahf"
version="3.0"
>
<xsl:use-package name="urn:test:pkg:xslt3"/>
<xsl:template match="/*">
<fo:block>
<xsl:copy-of select="ahf:setRed()"/>
<xsl:apply-templates mode="normal"/>
</fo:block>
</xsl:template>
</xsl:stylesheet>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:fo="http://www.w3.org/1999/XSL/Format"
xmlns:ahf="http://www.antennahouse.com/Names/XSLT/Document"
exclude-result-prefixes="xs math ahf"
version="3.0"
>
<xsl:use-package name="urn:test:pkg:xslt3"/>
<xsl:template match="/*">
<fo:block>
<xsl:copy-of select="ahf:setRed()"/>
<xsl:apply-templates mode="normal"/>
</fo:block>
</xsl:template>
</xsl:stylesheet>
のようにでも書いてやれば、とりあえず動かすことはできます.例えば入力ファイルとして次のようなDITAもどきを用意してやれば、
[input.xml]
<?xml version="1.0" encoding="UTF-8"?>
<dita-doc>
<ph class="- topic/ph ">Phrase text</ph>
<b class="+ topic/ph hi-d/b ">Bold text</b>
<i class="+ topic/ph hi-d/i ">Italic text</i>
</dita-doc>
<?xml version="1.0" encoding="UTF-8"?>
<dita-doc>
<ph class="- topic/ph ">Phrase text</ph>
<b class="+ topic/ph hi-d/b ">Bold text</b>
<i class="+ topic/ph hi-d/i ">Italic text</i>
</dita-doc>
次のようなそれなりの出力結果を受け取れます.
[output.xml]
<?xml version="1.0" encoding="UTF-8"?>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" color="red">
<fo:inline>Phrase text</fo:inline>
<fo:inline font-weight="bold">Bold text</fo:inline>
<fo:inline>Italic text</fo:inline>
</fo:block>
<?xml version="1.0" encoding="UTF-8"?>
<fo:block xmlns:fo="http://www.w3.org/1999/XSL/Format" color="red">
<fo:inline>Phrase text</fo:inline>
<fo:inline font-weight="bold">Bold text</fo:inline>
<fo:inline>Italic text</fo:inline>
</fo:block>
ちょっとおかしいのではないか?何故メインの側もxsl:packageでないのか?と思った方は相当鋭いです.本来のパッケージの使い方は、メインの側もxsl:stylesheetではなくxsl:packageなのでしょう.