sxpathが分かりにくかった

sxpathが分かりにくかったのでメモ。

使い方

まず、sxpathは関数を返す

gosh> (sxpath '())
#<closure (sxpath loop)>

ので使うときはこんな感じになる。(以下でshtmlはSHTMLデータとする)

(use sxml.sxpath)

((sxpath '(html head title)) shtml)

クエリ

上で'(html head title)としたようにクエリを与えて目的のデータを取得する。
この例だと「html要素の直下にあるhead要素の直下にあるtitle要素」を取得できる。
他にも

((sxpath '(// (div (@ class (equal? "hoge"))) *)) shtml)

でshtml内の、「class属性の値がhogeであるdiv要素の全ての子ノード」を取得できる。
記号の意味はそれぞれ、

  • //:そのノード自身と全ての子孫ノード
  • @:属性リスト
  • *:任意の要素(属性リストやテキストノードは含まない)。

また、括弧で条件が指定できて、上の例だと
「全てのノードを取り出す(//)」→「その中でdiv要素なものを取り出す」→「その中でclass属性を持つものを取り出す」→「その中で値がhogeであるものを取り出す」
の様に適用されている。
(「sxpathがとてもわかりにくい - 再帰の反復blog」で丁寧に解説されている)

XPath

クエリにはXPathを使うこともできる。
SXPathと比較して書くと以下の様になる。

; SXPath
((sxpath '(// (div (@ id (equal? "content"))))) shtml)
;XPath
((sxpath "//div[@id='content']") shtml)

; SXPath
((sxpath '(// h2 *text*)) shtml)
;XPath
((sxpath "//h2/text()") shtml)

; SXPath
((sxpath '(// (div (@ title)) *text*)) shtml)
;XPath
((sxpath "//div[@title]/text()") shtml)

; SXPath
((sxpath '(// (div (@ class (equal? "problem_content"))) *)) shtml)
;XPath
((sxpath "//div[@class='problem_content']/*") shtml)

個人的にはXPathの方が読みやすいので好み。