self軸

次のような<p>要素に正確にマッチするテンプレートを書きなさいといわれたらどうされますか?

<?pi remove_begin?><p>~</p><?pi remove_end?>

つまり、直前が<?pi remove_begin?>という処理命令で、直後が<?pi remove_end?>という処理命令という要素にマッチする条件です.間にはホワイトスペースは入りません.

実は不勉強ながら最初はどうしたらよいかわかりませんでした.XSL-Listにでもnewbieの質問と言うことで聞いてみようかとして文案を書き始めたら、ヒントがあたまに浮かびました.それはpredicateの中でself軸を使って判定することです.

実はこのテンプレートはこのように書けます.

<xsl:template match="*[preceding-sibling::node()[1][self::processing-instruction('pi')][string(.) eq 'remove_begin']][following-sibling::node()[1][self::processing-instruction('pi')][string(.) eq 'remove_end']]" priority="2">
  ...
</xsl:template>

ミソは、[self::processing-instruction('pi')]と書くことです.チェックするノードは、必ずpreceding-sibling::node()[1]とfollowing-sibling::node()[1]でなければなりません.隣り合わせのノードである必要があるからです.

もしpreceding-sibling::processing-instruction('pi')[1]とfollowing-sibling::processing-instruction('pi')[1]と書いてしまうと、遠く離れた処理命令を見てしまうかもしれません.これはダメなのです.

self軸は次のような場合にも使えます.例えば最初の子要素の<p>が①~⑩という文字で始まっているか判定するのは次のように書けるでしょう.

<xsl:variable name="firstText" as="xs:string" select="string(p[1]/child::node()[1][self::text()])"/>
<xsl:variable name="match1To10" as="xs:boolean" select="matches(substring($firstText,1,1),'[①-⑩]')"/>

このように、selfはノードの種類を判定するのにとても便利です.

でも今開発している私のスタイルシートgrepしてみましたが、self::を使っているのは数千ステップのうちほんの2箇所くらいでした.(selfを使うのは今回気がついたくらいですから使っていなくて当然です.)

では世の中のほかの人はどうかな?と思ってちょっと見させていただきました.そうすると結構selfを使っているテンプレートがあるのです.

例えば

<xsl:template name="sample1">
  <xsl:choose>
    <xsl:when test="self::~">
      ...
    </xsl:when>
    <xsl:when test="self::~">
      ...
    </xsl:when>
    ...
  </xsl:choose>
</xsl:template>

という具合です.なんのことはない、このsample1というのはパラメータなしの超汎用のテンプレートで、コンテキストがどんな場合であれ呼び出して、カレントコンテキストが何の要素かを判定して処理をしているのでした.

これはちょっとびっくりしました.カレントコンテキストを使って処理させると言うのは極めてインタフェース条件があいまいだからです.私だったら必ず<xsl:param>でパラメータを渡します.例えば<p>をパラメータで渡して何か判定させるなら、

<xsl:template name="sample1">
  <xsl:param name="prmP" as="element(p)" required="yes"/>
  ...
</xsl:template>

という具合です.これなら間違いは絶対ありません.同じself軸でもこのようなコンテキストに依存したテンプレートを作るためにを使うのはちょっと考え物ではないかな?と思います.