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中で使う際には例えば<というように、実体参照で書く必要があり、なんとも格好悪い。
述語で使える関数がたくさん用意してあって、こんな指定できないのかな、と思ったら大抵できるようになっている。
また、四則演算もできる。+-*は普通のプログラミング言語と同じだが、割り算に関しては/をパスの区切りに使ってしまっているので、代わりにdivを使う。
他にも関数が色々と用意してあって、position()
なんかが代表的なもの。
前述のitem[整数]
はitem[position()=整数]
とも書ける。
てな感じで、基本的なノード指定自体は、分かりやすいんじゃないかと思うんだけど、XSLTのどの部分で使えるのかとか、述語の記述方法や、関数の使い方だとか、ちょっと応用が入るとよくわかんなくなっちゃう。
うーむ、困ったものだ。
そんなわけで、今回は分かりやすいところまでで終了。