Xpath 入門

[話者] Xpathは重要だと思うので、しっかり会得するまで学習だ。

http://www.atmarkit.co.jp/fxml/rensai/rexml08/rexml08.html
Xpathの最初の初歩には、この記事がわかりやすかった。


[合いの手] 図がわかりやすいね。
ノードには基本的に以下の3つがあるのか。

  1. element node 要素ノード、ようするにHTMLタグ
  2. text node テキストノード、ようするにHTMLタグにはさまれた文字列
  3. attribute node 属性ノード、ようするにHTMLタグ内部に書いてある class="foo" とか id="bar" とかの属性。

テキストノードは要素ノードの下にあるんだね。


[話者] しかしこの記事はXSLT入門の一環なので、詳しいことまでは書いてない。


学習のために、こんなサンプルHTMLを作成した。
https://sites.google.com/site/itouhiro/2010/xpathtest01.html

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"><html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Xpath test</title></head><body><div id="saiyan">バーダック<div class="younger">カカロット<div class="elder">孫悟飯<div>パン</div></div><div class="younger">孫悟天</div></div><div class="elder">ラディッツ</div></div></body></html>


[合いの手] HTMLに改行がないよ。横に長すぎ。


[話者] 1行にしたのは、改行を入れると無駄なテキストノードが増えて学習のジャマになるから。


改行を入れると、次のようになるよ。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC
          "-//W3C//DTD XHTML 1.0 Strict//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja" lang="ja">

<head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>Xpath test</title>
</head>

<body>

<div id="saiyan">
バーダック

  <div class="younger">
  カカロット

    <div class="elder">
    孫悟飯

      <div>
      パン
      </div>
    </div>

    <div class="younger">
    孫悟天
    </div>
  </div>

  <div class="elder">
  ラディッツ
  </div>
</div>

</body>
</html>

さっきの記事
http://www.atmarkit.co.jp/fxml/rensai/rexml08/rexml08.html
の図のように表示するなら、
こんな構造だ。


DOM Inspectorで表示した場合は、こうなる。


[合いの手] ふむふむ。


[話者] このDOMツリーを、Xpathで自由自在に選択したり値を取り出そう。

http://d.hatena.ne.jp/itouhiro/20101218 の環境、FirefoxFireBugで実行しているよ。


この画像では3つの命令を実行している。$x(' ')で挟まれた部分が命令本体だ。


まず、最初の命令。
ルートノードを表示。

/

上の画像をよく見てくれ。$x('/') のところで、この「/」を実行しているよ。その結果は Document xpathtest01.html となっているな。


ルートノードの下に何があるか?

/node()

このnode()というのは、規格書
http://www.w3.org/TR/1999/REC-xpath-19991116/
に書いてあるけど、

  • element node 要素ノード
  • text node テキストノード

のどちらのノードも選択するよ。


上の画像の出力結果にある DocumentType { } というのは、HTMLの中に書かれた <!DOCTYPE のことらしい。なにも意味ある内容はないので、ここは見ないことにしよう。出力結果は2つあって、もう一つは html だね。


[合いの手] じゃあ、html っていうのが「ルートノードの下にあるノード」か。


[話者] それを最上位ノードとか、ルート要素とかいうってさっきの記事に書いてあったな。
これは<html>タグのことだし、「要素ノード」だな。


ルートノードの下にある、最上位ノード。

/html


[合いの手] これはさっきの「/node()」と同じものを選んだだけだよね。


[話者] そうだよ。


次の4つの命令は‥‥


最上位ノードの下に何があるか?

/html/node()


[合いの手]上の画像見ると head と body という二つの要素ノードがある。


[話者] bodyタグの下に何があるか?

/html/body/node()


[合いの手] <div>タグがあるね。div#saiyan っていうのは、CSSスタイルシート)と同じで、id="saiyan" と指定してあるdivタグってことか。


[話者] 「bodyタグの下のdivタグ」の下に何があるか?

/html/body/div/node()


[合いの手] おっ、テキストノードがあった。


[話者] ちなみに、テキストノードなしで、要素ノードだけ表示するには node() の代わりに * を使う。

/html/body/div/*


[合いの手] ふーん。


[話者] 逆に、テキストノードだけ表示するには text() を使う。

/html/body/div/text()


「bodyタグの下のdivタグ」の下のdivタグの下には何がある?

/html/body/div/div/node()


[合いの手] あれ、図と比べたらわかるけど、2つの、親の違う子ノードが混ざっているよ。


[話者] どっちも親ノードが<div>タグだから混ざるんだな。


[合いの手] カカロットのほうの<div>だけ表示するにはどうすればいいんだろう。


[話者] 2つのやり方を紹介する。
1. HTMLファイルの中で出てきた順番で指定する方法

/html/body/div/div[1]/node()

最初に出てきた<div>タグを div[1] で、次に出てきたのは div[2] と指定すればいい。


2. <div>についている属性で指定する方法

2つある<div>タグには、兄貴(elder)と弟(younger)というclass属性がついているので、それを利用する。

/html/body/div/div[@class="younger"]/node()


[合いの手] そうなのか。


[話者] あと、このXMLだともう一つやり方を思いついた。

/html/body/div/div/div/div/node()

ここまで<div>タグを掘り下げるとパンちゃんしかいなくなる。

そのあとで、<div>タグをさかのぼっていくと、パンちゃんの親の親であるカカロットの<div>タグだけを選択することができるぞ。

/html/body/div/div/div/div/../../node()


[合いの手] いろいろ、やりようはあるってことね。


[話者] さて、ここまで学んできたのは「絶対ロケーションパス」というものだった。ルートノードから順に下に向かって、ノードをたぐっていくやり方ね。


次に「相対ロケーションパス」というのを学ぶよ。

//div

とすると、階層に関係なく、<div>タグをすべて選択できるのだ。


[合いの手] まあ。


[話者]

//div[@id]

とすると、<div id="abc"> みたいに id属性のある<div>タグだけを選択できる。

//div[not(@id)]

とすると、id属性のない<div>タグだけ選択できる。

//div[@class="elder"]

とすると、兄貴キャラ(<div class="elder">)の<div>タグだけ選択できる。

//div[@class="elder"]/text()

とすると、兄貴キャラの名前がわかる。


[合いの手] こっちのほうが使いやすそうだな。


[話者] ここまで学べば、あとは以下のリンクを見て自習できるんじゃないかな。


[JavaScript][Web] Xpathの学習(2) GM「linkify」を解読
http://d.hatena.ne.jp/itouhiro/20101228

に続きます。




入門XML

入門XML