javascript でノードを拾うのCSSセレクタ(document.querySelector/querySelectorAll)だけなく、Xpathも使いたいよねってこと。DOM Level3も使えるし。
jQueryは使われすぎてバージョンHellで・・・
DOM の Evaluete/Xpath は今後はどうなるかわからないけど使えなくなるってのはなさそうだし
具体的サンプルの前に。
ブラウザでXpathを手軽に実行できる、document.evaluate 関数ですが、理屈が分からないと使いにくいので、document.xpathを紹介します。
document.evaluate でXPATH
実際にノードを探して使うサンプル
document.evaluate('//input[@value="削除"]',document,null,XPathResult.ANY_TYPE,null)
結果は、XPathResultオブジェクトになって取得される。
結果は、必ずしも配列にならない。(countなど)
結果がiterable のときはiterateNext()を使って順番に取り出せるので配列に変換できる。
ただし、XPathResultは node.remove()後に、iterateNext()がエラーになる。mutableじゃないから、dom変更後のsnapshotが使えないよってオコ(ノードへのショートカット)
結果は配列に放り込める。
複数ノードをとるのであれば、
いったん配列に入れてしまうことが便利
a=[]; while(e=ret.iterateNext()){a.push(e);}; a.forEach(function(e){console.log(e)} )
Array.from/Array.apply が使えれば良かったのに。
単一値を返すものは
ret.numberValue
プロパティーにアクセスでとれる。
なので、このよくある処理をまとめて・・・・
document.xpath 関数を作る
document.xpath = function(expression) { ret = document.evaluate(expression,document,null,XPathResult.ANY_TYPE,null); switch(ret.resultType){ case 1: return ret.numberValue; case 2: return ret.stringValue; case 3: return ret.booleanValue; case 4: case 5: var a=[]; while(e=ret.iterateNext()){a.push(e);}; return a; default: return ret; } }
ここまでがよく使うワンセット。
ここからはこのxpath関数を使ってサンプルを紹介します。
いかXPATHのサンプル覚え書き
特定タグ(h1)で一覧
document.xpath("//h1")
特定タグで特定属性があるもの
document.xpath("//a[@href]") document.xpath("//a[@onclick]")
全部のタグで特定属性があるもの
document.xpath("//*[@href]") document.xpath("//*[@onclick]")
文字列が一致するもの
属性値が特定のもの
document.xpath("//*[@rel='stylesheet']") document.xpath("//*[@type='text/css']")
テキストが一致するもの
document.xpath("//a[text()='次へ']")
ただし、一致は改行・タブ・空白文字が面倒なので、=の完全一致ではなく、次のように「部分一致」を行う。
文字列を「含む」もの(部分一致)
document.xpath("//link[contains(@rel, 'icon')]") document.xpath("//a[contains(./text(),'記事')]")
ノード以外に属性やテキストが結果に欲しい。
マッチしたノードの属性値を取り出す。
document.xpath("//link[contains(@rel, 'icon')]/@rel") document.xpath("//link[contains(@rel, 'icon')]/@href")
マッチしたノードのテキストを取り出す。
document.xpath("//a[@href]/text()")
除外(not)する条件で書く
条件を以外と書いて楽をしたい --> not 関数
document.xpath("//a[not(@href)]")
関数だけど、not なので便利
複雑な条件の組み合わせ and or
or で複数条件のいずれかにマッチするノードを取り出せる
document.xpath("//link[@type='text/css' or @rel='stylesheet']")
and で複数条件絞り込みを書くことができるが、次の2つが同じ意味なのであまり使わない
document.xpath("//*[@rel and @href and @type]") document.xpath("//*[@rel][@href][@type]")
条件には、自ノード以外も使えるが、、使わないよね。
document.xpath("//head/*[@rel]") document.xpath("//*[@rel][name(..)='head']")
name( expression ) で 指定されたノードの要素名になり、二つは同じことを示す。
さらに応用
子ノードにformを持つTableを探す
document.xpath("//table[.//form[@name='WebMeisaiCommonInputForm']]")
子ノードにform name=myformA を持つTableを探す
document.xpath("//table[.//form[@name='myformA']]")
ある子ノードをもつ親ノードを検索できるって便利ですね。
XPATHの記述方法
Xpathにはいくつも記述方法があって覚えにくいし自信をなくす
要素の選択だけなら、まだ覚えることはできるが、
要素のテキストを数値評価して計算してその結果をマッチ条件に使うとかでき、デバッグ時に訳解らなくなる。。。
もし特定のノードからたどりたいときは
function xpath = function(expression,elem) { ret = document.evaluate(expression,elem,null,XPathResult.ANY_TYPE,null); switch(ret.resultType){ case 1: return ret.numberValue; case 2: return ret.stringValue; case 3: return ret.booleanValue; case 4: case 5: var a=[]; while(e=ret.iterateNext()){a.push(e);}; return a; default: return ret; } }
追記
DOM LEVEL3 は obsoleteで、DOM Standardになったようです。
https://developer.mozilla.org/en-US/docs/DOM_Levels#Original_Document_Information
http://dom.spec.whatwg.org/
https://developer.mozilla.org/en-US/docs/DOM/DOM_Reference
追記(2019-12-10)
変数名スコープがglobal に漏れてたので修正
参考資料
http://itref.fc2web.com/xml/xpath.html
http://yakinikunotare.boo.jp/orebase/index.php?XML%2FXPath%2FXPath%A4%CE%BD%F1%A4%AD%CA%FD
http://msdn.microsoft.com/ja-jp/library/ms256103(v=vs.110).aspx
http://help.dottoro.com/ljcraimk.php
http://www.atmarkit.co.jp/fxml/rensai2/xmlmaster12/master12.html
http://wiki.whatwg.org/wiki/DOM_XPath