あなおそろしきxsl:import

DITA 1.3のインプリメントをやってきてXML mention Domainの実装にさしかかりました.XML mention DomainはXMLの要素(<xmlelement>)や属性(<xmlatt>)を表す要素の集合体です.例えばxmlelementのp@class属性は次のようになっています.

class="+ topic/keyword markup-d/markupname xml-d/xmlelement "

これからいえることは、雑駁に言えばkeywordからmarkupnameが特殊化され、markupnameからemlelementが特殊化されたということです.ですので一般的なスタイルシート

[dita2fo_bodyelements.xsl]
<xsl:template match="*[contains(@class, ' topic/keyword ')]">
[dita2fo_markup_domain.xsl]
<xsl:template match="*[contains(@class, ' markup-d/markupname ')]" priority="2">
[dita2fo_xml_mention_domain.xsl]
<xsl:template match="*[contains(@class, ' xml-d/xmlelement ')]" priority="4">

とpriorityで区別するものと考えていました.私のスタイルシートは実際そう作りました.ところがPDF2はどう作っているのか?と覗いてみると@priorityがないのです.

[commons.xsl]
<xsl:template match="*[contains(@class, ' topic/keyword ')]">
[markup-domain.xsl]
<xsl:template match="*[contains(@class, ' markup-d/markupname ')]">
[xml-domain.xsl]
<xsl:template match="*[contains(@class, ' xml-d/xmlelement ')]">

で実際に動かしてみると、テンプレートのバッティングは発生せずにエラーなしで次のような結果が得られます.xmlelementのオーサリングにはちゃんと前後に"<"と">"がついています.他もしかりです.

イメージ 1


何故こんなうまいことが出来るのだろうと調べてみたら、仕掛けはxsl:imortでした.

<xsl:import href="commons.xsl"/>
 ...
<xsl:import href="markup-domain.xsl"/>
 ...
<xsl:import href="xml-domain.xsl"/>
 ...

と順にインポートしているのです.このような場合、バッティングするテンプレートがあっても後からインポートした方がprecedenceが高くなり優先されるのです.そこでちょっとイジワルをしてxsl:importの順を変えてみました.

<xsl:import href="commons.xsl"/>
 ...
<xsl:import href="xml-domain.xsl"/>
 ...
<xsl:import href="markup-domain.xsl"/>
 ...

すると結果は次のようになります.すべてのxml-domainの要素はmarkupnameのテンプレートで処理されて、単にフォントがモノスペースになるだけです.
結果としてはまったくダメなのですが、オソロシイことに一切のエラーは報告されません.

イメージ 2


このxsl:importでtemplateの優先順位を制御するやり方はxsl:template/@priorityを管理しなくて済みます.そのかわりxsl:importの順序に細心の注意を払わねばなりません.順番を間違えてもエラーは出ないで、まったく期待しない結果になってしまうからです.

xsl:template/@priorityで制御する方法は手数がかかるかもしれませんが、@proorityの値を間違えるとXSLTプロセッサが「どちらのテンプレートにもマッチしてしまう!」というエラーを出すので、すぐ原因がわかります.また@rriorityの値により、その要素の特殊化のレベルもわかります.

xsl:importの順序で制御するやり方は分かっている人にとっては楽ちんなのかもしれませんが、私にはちょっとアブナイので従来通り@priorityで制御する構造のテンプレートにしたいと考えています.