Occurrence Indicatorの使い方(2)

このまえOccurrence Indicatorについて少し書きましたが、どうも私の認識は甘かったようです.何が甘かったかというと、世の中には「必ずしも意図しない誤った使い方」が存在しているからです.特に?と*のxsl:paramでの使い方です.

例えば以下のようなコードがあります.

<xsl:template name="xxx">
  <xsl:param name="prmXxx" as="xs:string"/>
  <xsl:param name="prmYyy" as="xs:string"/>
  <xsl:param name="prmStr" as="xs:string?"/>

  <xsl:choose>
    <xsl:when test="$prmStr != ''">
      ~
    </xsl:when>
    <xsl:otherwise>
      ~
    </xsl:otherwise>
  </xsl:choose>
  
テンプレートを読んでいる箇所を見ると必ずしも$prmStrを渡していません.どうも元々は  <xsl:param name="prmStr" as="xs:string"/>とコーディングしていたようです.しかしこのようにパラメータを渡さないと、XSLTプロセッサは$prmStrをヌルシーケンスの()で初期化しようとします.でも型がxs:stringなのでヌルシーケンスは許容されません.このため、

XTDE0610: A value must be supplied for parameter $prmStr because the default value is not a valid instance of the required type at xsl:call-template name="xxx" (file:/~/style.xsl#20)
Transformation failed: Run-time errors were reported

のエラーとなります.どうも単にこのエラーを回避したくてxs:string?としていたようです.この場合エラーは出なくなり、$prmStr = ''はfalse()を返します.しかしあまり気持ちの良いものではありません.ヌルシーケンスとの比較では$prmStr != ''もfalse()を返すからです.やるならヌルシーケンスを意識してstring($prmStr) eq ''とすべきです.

しかし元々がxs:stringなら、as="xs:string?"はas="xs:string"と書いて、明確にselect="~"で初期値を書くべきですね.

また、もっとひどい場合は、<xsl:param name="prmStr" as="xs:string*"/>となっている場合です.インタフェース仕様だけみて、呼び出し側をコーディングする開発者が、$prmStrに('ABC','')を渡したとします.そうすると、<xsl:when test="$prmStr = ''"> はtrue()で、<xsl:when test="$prmStr != ''"> もtrue()になります.たぶんテンプレートは意図通りには動いてくれないでしょう.

シーケンスを比較する一般比較演算子は、ほとんどの場合それなりに動きますが、時として思わぬ結果を返します.どうもこのあたりがあまり理解されていない印象を受けます.

いずれにせよOccurrence Indicatorを適切に使えるか否かは、XSLT2.0でスタイルシートをコーディングする場合の開発者の理解程度を示すモノサシのようなものではないかと思います.