やってはいけないスタイルシート

最近思うのですが、XSLT2.0をうたってあっても、その実内容はXSLT1.0レベルのスタイルシートがけっこうあります.XSLT1.0からの移行の段階でしかるべきコード書換えの決断をしないで単に<xsl:stylesheet version="2.0">と書いたものは、実はXSLT2.0の機能は使えるのですが、システムとしては恐ろしいことが起こりえます.ちょっと感じたことを書いてみたいと思います.
 
1.変数、パラメータの型付け
 
XSLT1.0はxslparamやxsl:variableにas属性はありませんでした.これは便利な反面、非常に恐ろしい性格を持っています.as属性がないと変数は使用されるたびにそのコンテキストに従って姿を変えます.文字列であったものが自動的に数値型として評価されたり、その逆に数値型が文字列として評価されます.
普通のJavaC++ではこのようなことはあり得ません.変数、パラメータは強く型付けされています.型を変換するには明示的にキャストが必要です.このあたりまえなことがas属性をつかわないと出来ません.
asがあれば、それに反する値が格納されたときにXSLTプロセッサがエラーを送出します.これはデバッグに非常に役立つのですが、asがないとほとんどの場面でエラーをかいくぐってしまいます.出るエラーは、ゼロ除算か数値がNaNになってさらに演算しようとしたときくらいではないでしょうか?
つまりasなしのスタイルシート実装は限りなくバグを隠蔽します.逆にasを使うと、スタイルシート仕様を書くほうも実装する方も今までにない緊張感を味わうことが出来ます.いったい今まで渡していたパラメータはxs:stringなのかxs:doubleなのか?知らないでシステムが組まれていたなんていうこともあるのです.いったんasを導入すると、近代的なプログラミング言語と同等の世界にようやく入ることが出来ます.
もしあなたのスタイルシートでxmlns:xs="http://www.w3.org/2001/XMLSchema"が宣言されていなかったら、それはまず10年以上は遅れていることを自覚してください.XSLT1.0が勧告になったのは1999年です.どのIT分野でもこの時代の到達点で今システムを作ろうとする人はいないでしょう.
 
2.エラー処理
1に大いに関係するのですが、エラー処理のないシステムは存在します.型を宣言しないとエラーチェックもできないので、エラー処理も必然的にないのです.私は自前のエラー処理ルーチンとエラーメッセージを持っていてどんな小さなシステムにも必ず使用するようにしています.ほとんどは論理エラーですが、初期のバグの検出に非常に役に立ちます.もしあなたの外注先が作ったスタイルシートがエラーメッセージ一覧を持っていなかったら、決してその品質を信じないでください.エラーがあっても検出できず、動いてしまっているだけだからです.
 
3.XPath
XSLT2.0ではXPath2.0が使えます.XPath2.0ではXPath1.0に比べて比べ物にならないほど関数が充実しています.しかし、XPath2.0勧告をよく読んでいない人の作ったXPath式は非常に冗長でわかりづらいものです.XPath2.0と提供関数(XQuery 1_0 and XPath 2_0 Functions and Operators )を使ってもっとスマートにXPath式を書こうではありませんか?SQLじゃないですが、XPath式を如何にスマートに書けるかはプログラマの技量にかかっているといっても過言ではありません.もしあなたが外注したスタイルシートのxsl:ifのtest属性がわかりづらかったらそれは、コーディングしたプログラマの技量が低いからです.XPath2.0は要求仕様に沿ったわかりやすいXPath式がかける手段を提供しています.仕様どおりになっていなかったら書き直すように要求してください.
 
4.コンテキスト依存
テンプレートがパラメータを受け取らず、なんの疑いもなくコンテキストに依存したコードを書いている場合があります.@idと出てきたらそれは./@idなのです.これがいくつものテンプレートにどんどん引き継がれると、いったいどの要素(ノード)がコンテキストだったのか忘れてしまいます.私はテンプレートを作るとき、まず必要のないテンプレートでも務めてパラメータでコンテキストを渡すようにしています.こうすればテンプレートがカレントコンテキスト依存しなくなるし、各テンプレートはどのノードを処理しているのかが明確にわかります.また異なったコンテキストからもパラメータさえ正確に渡せばテンプレートは動いてくれるようになります.カレントコンテキストの多用は便利な反面大きなシステムを作るときには決して使わない手法であることを頭にいれておく必要があるでしょう.
 
5.ループ
xsl:for-eachをやたらと使っているスタイルシートがあります.たいがいの場合私は信じません.XSLTのxsl:for-eachは他のC++Javaのループと違うことを理解しないでつかっていることが結構あるからです.私はxsl:for-eachはほとんど使いません.xsl:apply-templateでほとんど代用できます.また、再帰呼び出しで実現できるものもあります.XSLTスタイルシートの名言に「Do not loop. Use recurse.」というのがあります.XSLTではループは再帰で実現するものであることを理解できない初心者は多いようです.私はたいていの場合、xsl:for-eachがあると他の手段に書き換えます.(でもxsl:for-each-groupはXSLT2.0のすばらしい機能です.)
 
6.比較演算子
あなたはまだ"="を使っていませんか?私は"eq"を使うようにしています.同じじゃないかって?いえ、相当違います."="はシーケンス比較演算子です.思わぬところで思わぬ動きをします.例えばsection/para/@indent = '1.0'は通っても、section/para/@indent eq '1.0'はこけることがあります.そうsection/para/@indentがattribute()+を返してきたときです.一般にはシーケンス比較演算子はよっぽど意識して使う場合以外はつかいません."="より"eq"の方がプログラムエラーを検出してくれます.オペランドがシーケンスになったらエラーを返してくれるからです.でも例えば<xsl:if test="$color =('red','green','blue')のようなシーケンス比較演算子はバンバン使います.この方がorでつなげるよりはるかにコーディング量が少なくて済むからです.
 
さていろいろ書いてしまいました.そんなことはないと思われる方もいらっしゃるかもしれません.でも私の経験上、スタイルシートを書くほうも、納品を受ける方も決して「幸せ」にはなれないことばかりです.ぜひここに書いたことがお役にたてていただけたらと思います.