xsl:functionとxsl:template

いろいろ忙しかったのですが一段落しました.およそ4ヶ月くらいスタイルシートの作成の仕事をやっていたのですが、いろいろと勉強になりました.その一つにxsl:functionとxsl:templateの使い分けがあります.皆さんはどのようにやっておられますか?私の得た結論ですが、xsl:ifやxsl:whenなどの@test属性に書く式には「超」積極的にxsl:functionを使います.しかし、メインの要素処理には決してxsl:functionは使わず必ずxsl:templateを使います.
 
何故このような使い分けになったか?といいますと大きな理由があります.それは今回お客様の文書処理のスタイルシートを作ったのですが、最下層のインラインの要素の処理でなんとそこで使われているfont-familyの値が必須だったからです.具体的には、日本語OpenTypeフォントのグリフの異体字を指定する要素でした.通常OpenTypeはUnicodeマッピングされますが、フォントはこのマッピングされるグリフ以外にも異体字とよばれるグリフを持っています.これはUnicodeでなくグリフIDを使ってアクセスしなければならないのですが、このグリフIDが必ずしもフォントによって同じことが保障されているわけではないからです.そこでフォントファミリー名が必須となります.
 
実はスタイルシートの実装は文書の最上位要素から始めていたので、最下位のインラインでこのような要素が出てきてびっくりしたのですが、font-familyを設定するであろうすべての契機で、font-familyをトンネルパラメータにして下位へ渡すことで解決しました.以下のような具合です.
 
<xsl:apply-templates>
  <xsl:with-param name="prmFontFamily" as="xs:string" tunnel="yes" select="~"/>
</xsl:apply-templates>
 
あとラッキーだったのがメインの要素処理は(予感もあって)すべてトラディショナルなやり方でxsl:templateを使っていたことです.このためトンネルパラメータも一発で通すことができました.もし少しでもxsl:functionが入っていたら一貫の終わりです.なぜならxsl:functionはトンネルパラメータが通らない(というか通すことができない)からです.すべてxsl:functionをxsl:templateに書き直さねばなりません.
 
xsl:functionはxsl:templateのように引数を括弧で囲って一発で書けることが魅力ですが、同じことはxsl:templateでもできます.xsl:templateの方がいちいちxsl:call-template~xsl:with-paramと記述工数がかかることですが、やはりトンネルパラメータをちゃんと通せる点において記述工数の手間は補って余りあります.xsl:functionがas属性で戻り値を指定できるのと同じに、xsl:templateもas属性でテンプレートが返す戻り値(というかシーケンス)の型を指定できます.もちろんxsl:templateはXPath式中では使いようがありません.
 
また痛切に感じたのが、仕様どおりにXPath式を素直に書いているととてもではありませんが式が複雑になりすぎてしまい可読性が落ちることでした.
 
例えばDITAですがtopicref/@tocという属性があります.toc="no"だったらそのtopicは目次には出さないというものです.@tocがないときはtoc="yes"としたいとします.これをまともに書くと
 
<xsl:if test="empty(@toc) or string(@toc) eq 'yes'">
  ~
</xsl:if>
 
となります.これだけならたいしたことはありませんが、他の条件が重なってくるとXPath式はどんどん複雑化しこれにandとorと括弧が重なるとついには判読不能のお化けになります.
 
この例だと手間と思われるかもしれませんが、
 
<xsl:function name="ahf:isToc" as="xs:boolean>
  <xsl:param name="prmTopicref" as="element()"/>
  <xsl:sequence select="empty($prmTopicref/@toc) or string($prmTopicref/@toc) eq 'yes')"/>
</xsl:function>
 
と書くことにより
 
<xsl:if test="ahf:isToc(.)">
  ~
</xsl:if>
 
と簡略化されます.たいしたことはないように見えますが、私はこの間徹底してこの手のxsl:functionを作り続け、その数約100種類近くになりました.xsl:if/@testやxsl:when/@testが非常に読みやすくなったことはいうまでもありませんし、良い点は機能仕様に近い形で記述ができることです.
 
こういうxsl:functionは開発の最初で決意して作らないと後からではなかなか作れないものです.いわゆる私の作ったスタイルシートの前の「既存」のスタイルシートはこの手のxsl:functionのない玉砕型のXPath式でした.解読に苦労したことはいうまでもありません.
 
どうもこのようなスタイルシート作成の作法のノウハウがまだまだ日本には蓄積していないように思います.個々のプログラマー任せなのです.そして一度作ってしまったXPath式のお化けのスタイルシートはメンテナンスフェーズになると二度と見やすいように書き直されることはありません.おそろしくていじくれないからです.いつかはこういう悪循環を断ち切らねばならないと痛感しています.