XSLT3.0への道(2) xsl:try, xsl:catch

XSLT3.0からはXSLTスタイルシートでも、一般のプログラミング言語でいうところのtry、catchが使えるようになります.これはXSLT2.0で変数やパラメータの型定義が導入され、テンプレートのパラメータの必須有無、またテンプレートの戻り値も型定義できるようになったことによるものでしょう.
 
実際XSLT1.0スタイルシート/プロセッサを使っている限り、下手をすると無限ループしたりスタックオーバーフローになることはありましたが、そこそこなんとか動いてくれてしまったのです.実際XSLT1.0は本当に「寛容」な仕様でした.
 
ところがXSLT2.0のスタイルシートを書くようになるとXSLTプロセッサはランタイムエラー(動的エラー)を容赦なく報告するようになります.私もお客さんのスタイルシートをXSLT1.0からXSLT2.0に書き換えましたが、ランタイムエラーの障害報告は恥ずかしながら増えました.
 
基本的にランタイムエラーのほとんどはコーディングミスに起因するものでしたので、そのときはtry,catchの必要性はあまり感じませんでした.しかしパラメータを外部からユーザーに指定してもらうような場合も想定されます.XSLT3.0でのtry,catchの導入はXSLT2.0の発展として時宜を得たものでしょう.
 
まずXSLT3.0でのtry,catchの文法は以下に詳述されています.
 
例を示します.パラメータの値を整数値化して出力します.整数化できない場合はエラーメッセージを出して"0"を代わりに出力します.
[style.xml]
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:err="http://www.w3.org/2005/xqt-errors"
 exclude-result-prefixes="xs err">
    <xsl:output indent="yes"/>
    <xsl:param name="prmVal" as="xs:string"/>
    <xsl:template match="/">
        <val>
            <xsl:try select="xs:integer($prmVal)">
                <xsl:catch>
                    <xsl:message select="'Error code:', $err:code, 'Reason:', $err:description"/>
                    <xsl:sequence  select="'0'"/>
                </xsl:catch>
            </xsl:try>
        </val>
    </xsl:template>
</xsl:stylesheet>
 
これをSaxon9.3で以下のコマンドラインで呼び出すと次の出力を得ます.
 
[コマンドライン]
java net.sf.saxon.Transform -o:result.xml -s:input.xml -xsl:style.xsl prmVal=2e3
 
[コンソール出力]
Error code: err:FORG0001 Reason: Cannot convert string "2e3" to an integer
 
[result.xml]
<?xml version="1.0" encoding="UTF-8"?>
<val>0</val>
 
xsl:tryもxsl:catchもselect属性と、下位のsequence consutructorは排他的です.どちらかしか記述できません.xsl:tryはselect属性か下位のsequence consutructorを評価し、エラーがないときは「その値」を、エラーが発生した場合は「対応するcatchのselect属性かsequence constructorの値」を返してくれます.
 
ところでSaxon9.3のインプリメントにはまだバグがあるようで、次のようにxsl:eveluateでXPathの動的エラーを発生させてみようと思いましたが、NPE(Null Pointer Exception)でこけてしまいました.こんどSaxonのMLで報告しておこうと思います.
 
# このスタイルシートには誤りがあります.「XSLT3.0への道(3) 訂正 xsl:evaluate 」を参照ください.(2011/02/26)
 
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns:err="http://www.w3.org/2005/xqt-errors"
 exclude-result-prefixes="xs"
>
<xsl:output indent="yes"/>
<xsl:param name="prmXPathFile" as="xs:string" select="'xpath.xml'"/>
<xsl:template match="/">
    <output>
        <xsl:for-each select="doc($prmXPathFile)//xpath">
            <xsl:variable name="xPath" select="string(.)" as="xs:string"/>
            <xsl:message select="'XPath=',$xPath"/>
            <xsl:try>
                <xsl:evaluate xpath="string(.)"/>
                <xsl:catch>
                    <xsl:message terminate="yes" select="'XPath evaluation failed: Error code:', $err:code, 'Reason:', $err:description"/>
                </xsl:catch>
            </xsl:try>
        </xsl:for-each>
    </output>
</xsl:template>
</xsl:stylesheet>
 
xsl:try, xsl:catchが使用できるようになれば、スタイルシートのエラー処理も今より自然な形でできるようになると期待できます.何より今までは動的エラーをトラップする手段がなかったのですから、やはり必要な機能ですね.