XSLT:XPathってなんだ?

XSLは仕様の集合なのだ

 あんまり知らなくてもXSLTは使えるんですが、そもそもXSLTにXSL-FOととXPathという仕様を追加した仕様集合をXSLといいます。
 そのXSLというのはeXtensible Style Languageの略でして、日本語で言うと拡張可能なスタイル言語ってことになります。詳しくはExtensible Stylesheet Language - Wikipediaを参照のこと。
 つまり、文書にスタイル(装飾)を行うための仕様全体がXSLで、XSLTはその一部ということになります。
 その中のXSL-FOはTeXに近い仕様で、CSSの機能と似ている感じのものなんですけど、Webに出力するならHTML+CSSでいいんじゃね?って感じだし、印刷するならTeXでいいんじゃね?ってなってて、正直あんまり使われてないように思います。
 そもそもXSL-FOを処理できるソフト自体、私も知らないし(調べなさいよ)詳しくはXSL Formatting Objects - Wikipediaを参照のこと。
 要するに、XSLT以上に学習する価値が怪しい仕様です(笑)

 で、XSLの残りはXSLTとXPathってことになりますが、XSLTは前回解説した通りですから、謎なのはXPathです。
 パスって名前から察した方もいるかとおもいますが、これはXMLの中に含まれる要素や属性その他の内容を指定するための住所(path)の書き方の仕様です。
 XSLTはXMLからデータを抽出して再フォーマットするわけですけど、ここでデータを抽出する際にXPathを使うというわけです。
 これはXSLTとXPathの関係は、切っても切れませんね。詳しくは例によってXML Path Language - Wikipediaを参照のこと。
 あと、XPath Tutorialなんかを読むといいんじゃないてでしょーか。

で、XPath

 詳細な仕様はXML Path Language (XPath)XMLパス言語 (XPath)を読んでもらうとして、このページでも大づかみに紹介しておきましょう。
 私が大づかみにしか理解してないから(笑)

 XPathはXSLTとは独立した仕様なので、XSLT以外でも使える。
 例えば最近のブラウザのJavaScriptではXPathが使える。JavaScriptプログラマなら、もはや知らな方がおかしいだろう。それをXPathだと意識して使っているかどうかはともかく。
 こうなると、ますますXSLT使う理由が薄くなるなーわははー。
 JavaScriptでいいじゃんよー。

 しかしここは XSLTを解説するためのページなので、気を取り直して続ける。
 XPathの使い方として具体的にはXSLT中の属性にmatchとかselectとか出てきたときに、その値としてXPathを指定する。
 大まかな感じはPOSIX Path(UNIXで使われるパス)と同じなので、さほど難しいことはないと思う。
 またXSLTを使ってみようというような人ならURLとも同じなので、慣れているはずだ。

 例えば前回にルートノードを指定するのにmatch="/"を使った。POSIX Pathそっくり! てゆーか同じだ!
 後は予想通りにスラッシュ(/)で区切ってノードを追加していけばノードツリーを辿れる。
 また、最初をスラッシュで開始しなければ相対指定になるし、コンマ(.)は現在のノード、コンマ二つ(..)で親ノードになるのも一緒。
 じつこれらは省略構文で、例えば親を示すparent::という完全な構文もある。
 しかし省略構文(..)が簡単だし慣れててわかりやすいし、記述がごちゃつかずに見やすい。

 ワイルドカード(*)も使える、文脈によって細かい挙動の違いがあったりするが、だいたい使い良いように変わるので、あんまり細かな挙動は意識しなくて使える。

 さらにPOSIXにはない構文もたくさんある。
 //とスラッシュを二回つければ、子孫全部という意味になる。
 属性を指定するには@をつければ良い。
 例えば/html/body/@idという感じで<body id="">のid属性を指定できる。
 body@idのような気もするかもしれないが、@の前にもきっちりスラッシュを入れること。

 ノードを指定した後[]をつけると述語(条件)を記述できる。
 例えば[9]という感じに[]の中に整数を書けば、番号順でノードを特定できる。
 他にも[@id='main']と書くと、id属性が"main"のものが抽出されるなど、それなりにきめ細かな指定ができる。
 この述語はツリー指定の途中のどのノードにも書ける。

 まとめると、/軸::ノード[述語]/軸::ノード[述語]/…の繰り返しでXML中のノードを指定するのがXPathというわけだ。

軸(axis)

 軸には次のようなものがある。DOMで見たなーという感じのものだったり、そうでもないものだったり。
 実際は略記の方でほとんどなんとかなるので、あんまり使う事もないかもしんない。

ancestor::
祖先(親、親の親、…)
ancestor-or-self::
祖先、及びカレントノード
attribute::
属性(@)
child::
子供(特に指定しなければこの軸)
descendant::
子孫
descendant-or-self::
子孫、及びカレントノード(/descendant-or-self::node()/の省略が//)
following::
終了タグの後にあるもの
following-sibling::
後の兄弟
namespace::
名前空間ノード
parent::
親( parent::node() の省略が .. )
preceding::
開始タグの前にあるもの
preceding-sibling::
前の兄弟
self::
カレントノード( self::node() の省略が . )

ノード(テスト)

 基本的には要素名か@属性名を書けば良いんだけど、名前が付いてないノードとか、グループでの指定をする場合とかに関数による指定ができる。

node()
ノード(要素、属性、および名前空間ノード)
text()
テキストノード(文字列)
comment()
コメントノード(<!-- … -->という形のノード)
processing-instruction("ノード名")
XML処理命令ノード(<?ノード名 … ?>という形のノード)

述語

 [述語]の部分の書式は、結構複雑な指定ができる。
 以下、要素itemに付く述語、という形で書く。

連番

 item[整数]という形で書けば、要素を連番で指定できる。開始は1からで0ではない。

属性

 item[@id]と書けば、id属性を含むものすべて。
 item[@id='main']と書けば、id属性が"main"であるitem要素、という意味になる。
 このへんわりと素直な仕様なので、迷うこともないかと思う。

要素

 item[name='sample']と書くと、item要素に含まれるname要素が"sample"であるitem要素ということになる。
 属性(@)と要素を同じようなノリで扱えるということ。

 この述語の部分で使える演算子は、=の他に<や>などもあるが、XML中で使う際には例えば&lt;というように、実体参照で書く必要があり、なんとも格好悪い。
 述語で使える関数がたくさん用意してあって、こんな指定できないのかな、と思ったら大抵できるようになっている。
 また、四則演算もできる。+-*は普通のプログラミング言語と同じだが、割り算に関しては/をパスの区切りに使ってしまっているので、代わりにdivを使う。
 他にも関数が色々と用意してあって、position()なんかが代表的なもの。
 前述のitem[整数]item[position()=整数]とも書ける。

 てな感じで、基本的なノード指定自体は、分かりやすいんじゃないかと思うんだけど、XSLTのどの部分で使えるのかとか、述語の記述方法や、関数の使い方だとか、ちょっと応用が入るとよくわかんなくなっちゃう。
 うーむ、困ったものだ。

 そんなわけで、今回は分かりやすいところまでで終了。