querySelectorAll相当の機能を実装してみた(uupaa.jsのCSSセレクタを書き直した)
ここ数日は、uupaa.js の CSSセレクタ部分を書き直してました。
CSSセレクタ部分とは、jQuery("div > p") とか $$("#hoge~span") を解釈し要素を選択する機能です。document.querySelectorAll() としても標準化されています。
uupaa.js(ver 0.5)まではCSSセレクタをXPath式に変換する方法で一応CSS3セレクタもサポートしていたのですが、XPathではできないことが結構ありまして、かなりダメポな実装になっていました。
とまぁ、時間的な理由で書き直せずにくすぶっていたのですが、(IE5で)最速セレクターを作ってみた - ?D of K で紹介されたことで、書き直すきっかけをいただきました。id:ofkさんに感謝。
uupaa.js(ver 0.6)のCSSセレクタは、新しい実装に置き換わります。
CSS3.info のテスト用のHTMLをお借りして、各ライブラリ毎のCSSセレクタの比較もしてみました。
比較
passがテストをパスした数で, testが全テスト項目の件数。pointが合格率。
IE6 and IE7
Lib | pass/test | point |
---|---|---|
jQuery | 379/580 | 65% |
kQuery | 545/580 | 94% |
Prototype.js | 538/580 | 93% |
uupaa.js | 566/580 | 98% |
Opera9.27
Lib | pass/test | point |
---|---|---|
jQuery | 384/580 | 66% |
kQuery | 552/580 | 95% |
Prototype.js | 538/580 | 93% |
uupaa.js | 563/580 | 97% |
Opera9.6β
Lib | pass/test | point |
---|---|---|
jQuery | 387/580 | 67% |
kQuery | 555/580 | 96% |
Prototype.js | 485/580 | 84% |
uupaa.js | 570/580 | 98% |
Firefox2.0.16 and Firefox3.0.1
Lib | pass/test | point |
---|---|---|
jQuery | 391/580 | 67% |
kQuery | 559/580 | 96% |
Prototype.js | 548/580 | 94% |
uupaa.js | 570/580 | 98% |
Safari3.1 and Google Chrome
Lib | pass/test | point |
---|---|---|
jQuery | 387/580 | 67% |
kQuery | 263/580 | 45% |
Prototype.js | 545/580 | 94% |
uupaa.js | 580/580 | 100% |
jQuery(1.2.6), Prototype.js(1.6.0), uupaa.js(0.6 RC0)
なお、kQuery はリリースされていないようなので、javascripterさんのブックマークからたどって秘密裏に入手しました(w
uupaa.js が97%しか得点できない理由 とか 制限事項とか
querySelectorAllでは擬似要素を取得できないことになっているのと、:visited はセキュリティの都合で実装していません。not も実装していません。
- :link で訪問済みのリンクかどうか区別していない(-1点)
- :visited はセキュリティの関係で実装していない(-1点)
- :before, :after, :first-letter, :first-line はDOM要素と1対1で対応していないため、正攻法では実装できない(-4点)
- ::before, ::after, ::first-letter, ::first-line も同様(-4点)
:first-of-type, :last-of-type の一部解釈が仕様と異なる(-2点)解決済み- :not() 未実装(-2点)
超えられなかった壁
壁というか 作業中に遭遇したブラウザのバグ等。
- Opera9.2x には二つのバグがある。これはOpera9.5で修正されている。
- <div align="leftorright"> や <div align=" left "> を元に <div align="left"> といった(改ざんした)DOMツリーを構築するらしく、div[align=left] や div[align$=left]と不正にマッチしてしまう。
- このバグを回避する方法がないためOpera9.2xでは、pointが6点減っている。
- <div><!-- Just a comment --></div> の div.innerText は "" が返るのに、div.textContent からはコメントの中身 " Just a comment "が返る。
- このバグはOpera9.2xならinnerTextを参照するようにして回避している。
- <div align="leftorright"> や <div align=" left "> を元に <div align="left"> といった(改ざんした)DOMツリーを構築するらしく、div[align=left] や div[align$=left]と不正にマッチしてしまう。
- IEではDOMツリーに空白や改行だけのテキストノードが含まれないため、:empty が <div> </div> にマッチしてしまう。 -1点
- IE7以下にはhasAttributeがないため、E[attribute] で本来マッチしない要素もマッチしてしまう。 -2点
- こんなコードでなんとかpointを稼いだが完全解決はできなかった。
function hasAttribute(node, attrName) { if (uu.ua.ie && !uu.ua.ie8) { var attr = node.getAttributeNode(attrName); return attr && attr.specified; } return node.hasAttribute(attrName); }
反省会
- 実際にテストしてみたい方は、http://pigs.sourceforge.jp/blog/200809192139/ からどうぞ
- 各フォルダの中にある test.html がテスト本体になります。
- :target は ぱっと見でテストが失敗しているように見えますが、テスト項目を右クリックしてリンクを開き、それだけをテストするとオールグリーンになったりします。(上記の集計でも加味してあります)
- 各フォルダの中にある test.html がテスト本体になります。
- 自作ライブラリをテストしたい方は、ディレクトリごとダウンロードして、 selector.js の末尾に以下をくっつけると良いでしょう。
if (!("forEach" in Array.prototype)) { Array.prototype.forEach=function(fn,me){ for(var i=0,sz=this.length;i<sz;++i){(i in this)&&fn.call(me,this[i],i,this);} }; } var CSSSelector = $.find; // Prototype.js なら var CSSSelector = $$; にします。
-
- どっかまずいところがあったら教えてください。直しますので。
いかんいかん、コレを言い忘れるところだった。
「kQuery 恐るべし」
kQueryが本領を発揮するとすごいことになりそうです。uupaa.js も負けないようにがんばります。