次々と技術が進化するのでとてもキャッチアップできませんが、2月7日はXSLT 3.0にとって特別な日になったようです.
XSL Transformations (XSLT) Version 3.0
W3C Candidate Recommendation 7 February 2017
ついにというかようやくXSLT 3.0はW3Cの最終Candidate Recommendation(勧告候補)となりました.そしてXSLT 3.0のインプリメントはXPath 3.1のデータモデルをサポートします.(というかしなければなりません.)
W3C Proposed Recommendation 17 January 2017
XPath 3.1で重要なデータ型の追加になったのはマップ型(map)と配列型(array)です.この日に同時にリリースされたSaxonでちゃんとサポートされたようなので配列型をすこし触ってみました.といってもちょうどSaxon PE(プロフェッショナルエディション)のバージョンアップの期間が切れてしまい、新しいのはオープンソースのHE(ホームエディション)でしかテストできません.
例として、用紙とその幅、高さを表現することを考えてみました.
Letterは幅215.9mm、高さ279.4mm
Legalは幅215.9mm、高さ355.6mm
B4は幅250mm、高さ353mm
A4は幅210mm、高さ297mm
というようなものです.これは今まではitem()*で表すしか手がなかったように思えます.例えば
<xsl:variable name="paperInfoSeq" as="item()*" select="('Letter',215.9,279.4,'Legal',215.9,355.6,'B4',250,353,'A4',210,297)"/>
という感じです.あまりきれいではありません.用紙単位に情報がグルーピングできないからです.配列を使えば次のように素直に表現できます.
<xsl:variable name="paperInfoArray" select="[('Letter',215.9,279.4),('Legal',215.9,355.6),('B4',250,353),('A4',210,297)]"/>
さっそく次のようなスタイルシートを書いてみます.oXygen 18.1でやっていますが、まだoXygenは古いSaxonをバリデーションに使用しているのでボロボロエラーが出ますが気にせずコーディングします.
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
xmlns:ahf="http://www.acme.com/names/xslt"
exclude-result-prefixes="xs array"
version="3.0">
<xsl:function name="ahf:returnPaperInfoArray" as="array(item()*)">
<xsl:sequence select="[('Letter',215.9,279.4),('Legal',215.9,355.6),('B4',250,353),('A4',210,297)]"/>
</xsl:function>
<xsl:template match="/">
<xsl:variable name="arrayVar" as="array(item()*)" select="ahf:returnPaperInfoArray()"/>
<xsl:for-each select="1 to array:size($arrayVar)">
<xsl:variable name="paperInfo" as="item()*" select="$arrayVar(position())"/>
<xsl:message select="concat('[',position(),'] paper=',string($paperInfo[1]),' width=',string($paperInfo[2]),'mm height=', string($paperInfo[3]),'mm')"/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
最初のahf:returnPaperInfoArrayという関数は、配列がXPath 3.1では「型」になったことを確認するものです.as="array(item()*)で型として記述できます."["と"]"で配列のコンストラクトができます.これは次のようにも記述できます.
<xsl:sequence select="array{('Letter',215.9,279.4),('Legal',215.9,355.6),('B4',250,353),('A4',210,297)}"/>
その下のテンプレートは、配列を$arrayVarに格納し、配列の各要素をxsl:messageで表示させています.配列のサイズはarray:size()で取得できます.
これを動かした結果は次のようなものになります.
ここで大事なことは配列の要素(member)の自由度が高いことです.配列のメンバーには関数やマップなども可能なはずです、Saxon Heでは残念ながらここまでしか試せませんが、新しいSaxon PE 9.7.0.15が手に入れられたら試してみたいと思います.