この文書「セレクター API Level 1」は、W3C の WebApps Working Group による「Selectors API Level 1 (W3C Candidate Recommendation 22 December 2009)」の日本語訳です。
規範的な文書は原文のみとなっています。この日本語訳は参考情報であり、正式な文書ではないことにご注意ください。また、翻訳において生じた誤りが含まれる可能性があります。
原文が勧告 (Recommendation) ではなく、策定途中の勧告候補 (Candidate Recommendation) であることにご注意ください。
原文の最新版 は、この日本語訳が参照した版から更新されている可能性があります。また、この日本語訳自身も更新されている可能性があります。日本語訳の最新版は、http://standards.mitsue.co.jp/resources/w3c/TR/selectors-api/ から参照することができます。
古い仕様の日本語訳は、Web 標準仕様 日本語訳一覧から参照することができます。
Copyright © 2006-2009 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C liability, trademark and document use rules apply.
CSS で広く利用されているセレクターは、木構造をもつ要素群から、目的のものを探すための仕組みです [SELECT][CSS21]。セレクター API 仕様は、セレクターを指定して DOM から Element ノードを取り出すメソッドを定義します。この API は、文書の中から特定の要素に対し DOM 操作を行いたい時、とても有用なものです。このメソッドにより、特定の要素を抽出する処理を、従来の仕組みより簡単に行うことができます。
この章は、この文書の公開時におけるステータスについて説明しています。このため、他の仕様がこの文書を上書きしている可能性があります。W3C による他の出版物およびこの技術レポートの最新版は W3C 技術レポートインデックス (http://www.w3.org/TR/) で探すことができます。
この文書は、2009 年 12 月 22 日付の「セレクター API」勧告候補です。勧告候補とは、仕様が安定しており、開発者コミュニティに対し実装を呼びかけられる段階を表します。Web Applications (WebApps) Working Group は今後 Selectors API のテストスイート を作成し、それらにパスする実装が 2 つ以上あることを確かめてから、この仕様を勧告案に進めることを Director に提案します。
いくつかの実装が完了し、また互換性も確保されています。WebApps Working Group はテストスイートの作成と実装の検証を 2010 年初頭より開始することを検討しています。しかし、2010 年 4 月 30 日以前に Proposed Recommendation への要請を行う予定はありません。また、現時点において正式な実装レポートは存在していません。
この仕様の最終草案には、多くのコメントが寄せられました。すべてのコメントは解決され、Disposition of Comments よりアクセスできます。
W3C メンバーや他の団体は、この文書をレビューし、コメントを送ることができます。コメントの送信先は public-webapps@w3.org (公開アーカイブ) で、件名には [selectors-api] を含めてください。なお、コメントの最終期限は 2010 年 4 月 30 日です。(なお、2008 年中頃まで違うメーリングリストが利用されていたため、古いメッセージは public-webapi に保存されています)。編集段階にあるこの仕様書の最新版は W3C CVS より取得可能です。また、変更点の詳細は CVS サーバー からも所得可能です。
この文書は Web Applications Working Group により策定されました。Working Group はこの草案を勧告 (Recommendation) とすることを考えています。
勧告候補としての仕様書公開は、W3C メンバーによる支持を意味するものではありません。この文書は更新されたり他の文書と置き換えられたり、また破棄される可能性もある草稿段階の仕様書です。策定中ということを明記せずに、この文書を引用することは適当でありません。
この文書は 5 February 2004 W3C Patent Policy の下で活動するグループにより作成されました。W3C は 特許情報の開示に関する公開リスト を関連する団体と共に、その成果物とあわせて管理しています。リストには情報開示に関する説明もありますので、ご参照ください。特許について十分に知識のある人物が、当該仕様に関し Essential Claim(s) が認められると判断した場合は、W3C 特許方針の第 6 章 に従い情報を開示する必要があります。
このセクションは非規範的です。
この仕様は、セレクターを引数に取り、それに適合する要素を返す二つのメソッドを定義します。このメソッドを利用することにより、従来よりも簡単に Element ノードを取得できるようになるため、getElementsByTagName() で得られた結果にさらにフィルタをかけるなどといったことをする必要がなくなります。
このセクションは非規範的です。
この例は ECMAScript [ECMA-262] によって書かれています。
HTML 4.01 で、簡単な表を記述してみます。
<table id="score">
<thead>
<tr>
<th>Test
<th>Result
<tfoot>
<tr>
<th>Average
<td>82%
<tbody>
<tr>
<td>A
<td>87%
<tr>
<td>B
<td>78%
<tr>
<td>C
<td>81%
</table>
たとえば、グラフを描きたいといった理由で、この表から結果 (“Result”) のみを取得したいといった場合があります。これには二つの方法が考えられます。ひとつは、DOM Level 2 の API のみを利用する方法です。このやり方では、table 内の tbody から、各 tr をイテレートして、その行にある 2 番目のセルを見つけることになります。
var table = document.getElementById("score");
var groups = table.tBodies;
var rows = null;
var cells = [];
for (var i = 0; i < groups.length; i++) {
rows = groups[i].rows;
for (var j = 0; j < rows.length; j++) {
cells.push(rows[j].cells[1]);
}
}
もう一つは、querySelectorAll() メソッドを利用する方法です。このメソッドを使用すると、スクリプトをとても簡潔に記述することができます。
var cells = document.querySelectorAll("#score>tbody>tr>td:nth-of-type(2)");
このスクリプトは DOM 上で動作するため、文書がどの構文で書かれているかは関係ないことに注意してください。つまり、このスクリプトは HTML だけではなく、製形式の XHTML や DOM API を利用し動的に生成され挿入された表に対しても動作するでしょう。
仕様書中のすべての図、例、注釈は非規範的なものとなります。また、明示的に非規範的とされたセクションも非規範的なものとなります。それ以外の部分については、規範的なものとなります。
規範的な文章中にあるキーワード must、should、may、recommended は、RFC 2119 で示されるとおりに解釈されます [RFC2119].
この仕様では、次の適合性クラスについても検討され、定義されています。
NodeSelector インターフェースを実装し、関連するすべての must レベル基準に適合するユーザーエージェントのこと。
この仕様で利用される用語は、セレクター仕様のものです [SELECT]。
アルゴリズムとして記された適合性要件や特定のステップについては、結果が同じものである限りどのような方法を用いて実装することも可能です (may)。
この仕様で利用される IDL は、Web IDL で定義された構文を用いています [WEBIDL]。
Foo が実際にはインターフェースであるにも関わらず、"Foo オブジェクト" と表記されることがあります。これは、"Foo インターフェースをインプリメントするオブジェクト" という意味で用いられています。
仕様書の中で使われているにも関わらず定義されていない Document, DocumentFragment, Node, Element などのインターフェースは、DOM Level 3 Core [DOM-LEVEL-3-CORE] で定義されています。
このセクションは非規範的です。
セレクターの実装状況は、実装により異なる可能性があります。あるセレクターをサポートする実装としない実装が存在する場合、そのセレクターを利用したコードは異なる結果を返すことになるでしょう。このため、製作者はこれらの API から投げられる DOM の例外を調べ、Graceful Degradation によるフォールバックを提供することをおすすめします。
このセクションは非規範的です。
この仕様で定義される API の拡張は 奨励されません (strongly discouraged)。実装者やワーキンググループ、そして他の団体は、拡張について public-webapi@w3.org などの公開フォーラムで議論するべきです。
この仕様を実装するにあたって、ユーザーがセキュリティに関するリスクを負わないようにすることが望まれます。
セキュリティポリシーに違反すると判断される状況に遭遇した場合、実装は処理を中止し、セキュリティ例外を発生させることができます (may)。この仕様や関連する仕様の範囲外でエラーが起こった場合、実装は処理を中止し、言語バインディング固有、または実装固有の例外を発生させることができます (may)。
プライバシーに関して考えられる懸念のひとつに、履歴の取得が挙げられます。セレクター [SELECT] の :visited 擬似クラスをクエリーにかけたとき、訪問済みのリンクを取得できることが問題視されています。
しかしながら、これは古くからある問題です。訪問済みリンクの取得は、CSS と getComputedStyle() など既存の DOM API により取得することができるからです [DOM-LEVEL-2-STYLE]。
次の例では、vlinks がユーザーが訪れたリンクを取得します。悪意を持った製作者はここから URI を取得し、悪用することができます。
var vlinks = document.querySelectorAll(":visited");
for (var i = 0; i < vlinks.length; i++) {
doSomethingEvil(vlinks[i].href);
}
セレクター で定義されている ([SELECT], section 6.6.1) 通り、ユーザーエージェントはすべてのリンクを未訪問のリンクとして扱うことができます (may)。実装は、サポートされるセレクターについて、その他の用途と一貫性を持たせ挙動することが推奨されます (recommended)。
メソッドの定義で使われる 最初 (first) とは、document order で最初のもの (first in document order) を表します。document order は、該当する DOM ツリーまたはそのサブツリーに対し、深さ優先の先行順走査 (depth-first pre-order traversal) を行ったもの表します。コンテキストノード (context node) は、メソッドが呼び出されるノードを表します。ノードのサブツリー (node’s subtrees) は、コンテキストノード の子孫要素のコレクションを表します。マッチする Element ノード (matching Element node) は、セレクターの要素マッチング規則 [SELECT] に則り、メソッドに渡されたセレクター (selectors) にマッチする Element ノードを表します。
NodeSelector インターフェースmodule dom {
[Supplemental, NoInterfaceObject]
interface NodeSelector {
Element querySelector(in DOMString selectors);
NodeList querySelectorAll(in DOMString selectors);
};
Document implements NodeSelector;
DocumentFragment implements NodeSelector;
Element implements NodeSelector;
};
NodeSelector インターフェースの querySelector() メソッドは、呼び出されたときに、ノードのサブツリー中で与えられたセレクターに最初にマッチする Element ノードを返す必要があります (must)。もし該当するノードが存在しない場合、このメソッドは null を返す必要があります (must)。
NodeSelector インターフェースの querySelectorAll() メソッドは、呼び出されたときに、ノードのサブツリー中で与えられたセレクターにマッチするすべての Element ノードを、document order で格納した NodeList として返す必要があります (must)。もし該当するノードが存在しない場合、このメソッドは空の NodeList を返す必要があります (must)。
querySelector() と querySelectorAll() は selector string (selectors) を引数にとります。
querySelectorAll() メソッドから返される NodeList オブジェクトは 動的 (live) ではなく、静的 (static) である必要があります ([DOM-LEVEL-3-CORE], section 1.1.1) (must)。元文書の構造が変化しても、その変化が NodeList オブジェクトに反映されることは許されていません (must not)。つまり、返されるオブジェクトは、リストが生成された時点で文書に存在していたノードに対しクエリをかけ、マッチする Element ノードを取得することを意味します。
selector string とは セレクターのグループ ([SELECT], section 5) を表します。渡されるセレクターは、selectors_group production ([SELECT], section 10) にマッチするべきです (should)。ただし、セレクターの前後に 空白文字 ([SELECT], section 4) を含めることは許可されています。また、渡されるセレクターは、解決される必要のある名前空間接頭辞 を利用すべきではありません (should not)。
selectors の値に null や undefined が渡された場合、実装者は Web IDL [WEBIDL] に従い処理するように望まれています。製作者は、これらの値を渡さないようにすることが望まれています。
擬似要素をセレクターに使うことは可能ですが、これは文書中のどの要素にもマッチしないため、何も要素を返さないことになります。このため、製作者はこの使用で定義されるメソッドにおいて、擬似要素を含むセレクターを利用しないことが推奨されます。
実装はまず、引数のセレクター (selectors) から先頭と最後の 空白文字 (whitespace) を取り除く必要があります (must)。そして、セレクターの文法 ([SELECT], section 10) にしたがって値を処理する必要があります (must)。セレクターは当該要素が存在する全 DOM ツリーに対し評価されます。与えられたセレクターが 不正 ([SELECT], section 13) であるとき、実装は 例外 SYNTAX_ERR を発生させる 必要があります ([DOM-LEVEL-3-CORE], section 1.4) (must)。
CSS をサポートするユーザーエージェントにおいて、実装は CSS でサポートするセレクターと同じサポートを、API に対しても行うべきです (should)。
セレクターが 解決される必要のある名前空間接頭辞 を含む場合、実装は 例外 NAMESPACE_ERR を発生させる 必要があります ([DOM-LEVEL-3-CORE], section 1.4) (must)。
この仕様は現在のバージョンにおいて、名前空間接頭辞を解決するメカニズムをサポートしていません。しかし、将来的に追加することを検討しています。
解決される必要のある名前空間接頭辞 (namespace prefix needs to be resolved) とは、名前空間コンポーネントが (null 名前空間を表す) 空の状態 (例: |div) であるものや、どの名前空間をも表すアスタリスク (例: *|div)、このどちらにも当てはまらないものを表します。アスタリスクや空名前空間接頭辞は解決される必要がないため、セレクターの名前空間構文をサポートする実装は、これら二つをサポートする必要があります [SELECT] (must)。
セレクターの名前空間構文をサポートしない実装は、代わりに例外 SYNTAX_ERR を投げることがあります。これは、サポートしない実装において、その構文が不正なものとして扱われるからです。
DOM3 Core では、インターフェースのサポート状況を確かめたり、インターフェースの実装を得たりするため、feature 文字列 (feature strings) を利用するいくつかのメソッドを定義しています ([DOM-LEVEL-3-CORE], section 1.3.6)。DOM アプリケーションはこのメソッドの引数 feature に "Selectors-API" を、そして version には "1.0" を指定することで利用することができます。
これらの引数を hasFeature メソッドに与えたとき、適合する実装は true を返す必要があります (must)。しかし、true が返されたとしても、実装が完全に仕様に適合しているわけではなく、また false が返されたとしても、実装がサポートしている可能性もあります。よって、このメソッドの仕様は奨励されません。
このセクションで解説するコードは、次の XHTML 文書を利用しています。
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Selectors API Example</title>
</head>
<body>
<div id="foo">
<p class="warning">This is a sample warning</p>
<p class="error">This is a sample error</p>
</div>
<div id="bar">
<p>...</p>
</div>
</body>
</html>
メソッドは、複数のセレクター (カンマ区切り) を引数に持つことができます。次の例は、class に "error" または "warning" を持つ p 要素すべてを選択します。
var alerts = document.querySelectorAll("p.warning, p.error");
querySelector() メソッドも複数のセレクターを引数に持つことができますが、返すのはマッチしたもののうち最初の要素のみとなります。
var x = document.querySelector("#foo, #bar");
x は、ID に foo または bar を指定された要素のうち、最初に現れたものを格納します。このセクションの先頭にあるサンプル文書に対しクエリーを実行すると、ID に foo を持つ div 要素が選択されます。なぜなら、この要素は document order 上で最初にマッチするからです。引数に複数のセレクターを渡しても、その順序は結果に何も影響を及ぼしません。次のように順番を逆にしても、おなじ結果を得ることができます。
var x = document.querySelector("#bar, #foo");
二つのメソッドは、要素上から呼び出すこともできます。次の例では、イベントハンドラーが要素に対して登録されているものとします。なので、このメソッドはイベントのターゲットとなる要素から呼び出されます。
function handle(evt) {
var x = evt.target.querySelector("span");
...
// Do something with x
}
しかし、メソッドは要素から呼び出されますが、セレクターは文書全体を評価します。次の例において、body 要素は div 要素の子孫でないにも関わらず、メソッドは div 要素の子である p にマッチします。
var div = document.getElementById("bar");
var p = bar.querySelector("body p");
次のようなナビゲーションメニューを持つ文書があるとします。
<ul class="nav"> <li><a href="/">Home</a></li> <li><a href="/products">Products</a></li> <li><a href="/about">About</a></li> </ul>
次の例は、すべての li 要素を選択し、その結果の NodeList をイテレートする様子を表しています。
var lis = document.querySelectorAll("ul.nav>li");
for (var i = 0; i < lis.length; i++) {
process(lis.item(i));
}
ECMAScript では、NodeList を配列として扱うことが可能なため、次のように書き換えることができます。
for (var i = 0; i < lis.length; i++) {
process(lis[i]);
}
メソッドから返される NodeList オブジェクトは動的ではないため、DOM に行われた変更はリストの内容に変更を及ぼすことがありません。たとえば、前の例で次の関数 process() を実行したとします。
function process(elmt) {
elmt.parentNode.removeChild(elmt);
}
このコードは、DOM から選択された要素ひとつずつを削除します。しかし、各要素は NodeList に残ります。もしリストが動的な NodeList であれば、DOM から要素を削除したときに、リストの要素も変更され、関連する要素のインデックスも調整されるでしょう。結果として、ループにおいて意に反する効果が行われます。これは、全ての要素が処理されていないからです。
複数の名前空間が混在する文書において、それぞれ異なる名前空間に属する要素が、同じローカル名を持つことが起こりえます。この API はセレクターの名前空間を解決するメカニズムを備えていないため、特定の名前空間に属する要素を取得するには、何段階かのステップを踏むことになります。次の例は、SVG と XHTML の名前空間が混在する文書から、video 要素を取得するものです。
<svg id="svg1" xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<video id="svgvideo1" xlink:href="myvideo.ogg" width="320" height="240"/>
<foreignObject width="100" height="100">
<video id="htmlvideo1" src="myvideo.ogg" xmlns="http://www.w3.org/1999/xhtml">No video1</video>
</foreignObject>
</svg>
次のスクリプトは、最初に video 要素全てを取得し、次に名前空間でフィルタをかけ目的の要素のみを抽出します。
var list = document.querySelectorAll("svg video");
var result = new Array();
var svgns = "http://www.w3.org/2000/svg"
for(var i = 0; i < elms.length; i++) {
if(elms[i].namespaceURI == svgns) {
result.push(elms[i]);
}
}
編集者はこの仕様の策定に当たり貢献してくれた、次の方々に感謝しています (ファーストネーム順)。
Adam van den Hoven, Alan Gresley, Alex Russell, Bjorn Hohrmann, Boris Zbarsky, Cameron McCormack, Charles McCathieNevile, Chris Wilson, Christophe Jolif, Daniel Glazman, Daniel Schierbeck, Dave Massy, David "liorean" Andersson, David Hasather, Dean Jackson, Doug Schepers, Erik Dahlstrom, Francois Remy, Garret Smith, Hallvord R. M. Steen, Ian Hickson, Ivan Enderlin, Jean-Yves Bitterlich, Jim Ley, Joao Eiras, John Resig, Jon Ferraiolo, Jonas Sicking, Jorgen Horstink, Karl Dubost, Kartikaya Gupta, L. David Baron, Maciej Stachowiak, Magnus Kristiansen, Martijn, Masataka Yakura, Mihai Sucan, Mohamed Zergaoui, Nicholas C. Zakas, Nicolas Mendoza, Philip Taylor, Robert Sayre, Robin Berjon, Sander, Sergey Ilinsky, Simon Pieters, Steven Pemberton, Tarquin Wilton-Jones, Travis Leithead, and William J. Edney
提案や修正を提供し、この仕様に貢献してくれた方々にも感謝しています。