Hatena::ブログ(Diary)

m2

2011-02-23

jQuery 1.4.4 で使えなくなってるセレクタ

jQuery 1.4.4 の document.querySelectorAll を使う部分で、属性値をクォートする(ような)コードが入っています。

(L.4084)

// Make sure that attribute selectors are quoted
query = query.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']");

うーん、なんで必ずクォートされないといかんのだろ。少なくとも Opera ではどっちでも動くみたい。

(Google トップページで)

javascript:alert(document.querySelectorAll('input[name=q]').length) // 1
javascript:alert(document.querySelectorAll('input[name="q"]').length) // 1

これによって Struts なんかの indexed な name の要素が取得できないようになっています。(たとえきちんとエスケープしていてもです!)

javascript:(function(){
  var query = 'input[name=hoge\\[0\\]\\.fuga]';
  alert(query.replace(/\=\s*([^'"\]]*)\s*\]/g, "='$1']")); // input[name='hoge\[0\']\.fuga]
})()

で、チケットを検索したら数多く報告されているようです。

This is a known regression and has been reported numerous times. You wouldn't have run into this issue when using the syntax recommended on api.jquery.com. Which says "Quotes are mandatory." for attribute values in attribute selectors. Like this

$(':input[name$="[bar]"]')

It has been fixed, you can check that with the recently released 1.5rc1 version in this test case

http://bugs.jquery.com/ticket/8058

属性値はクォートしてね、とのこと。

jQuery('[attribute="value"]')

attribute

An attribute name.

value

An attribute value. Quotes are mandatory.

http://api.jquery.com/attribute-equals-selector/

余談ですが

実は 1.4.2 では属性値をエスケープしなくても $('input[name=hoge[0].fuga]') のような要素が取得できます。これはなぜかと言うと

jQuery 1.4.2

Sizzle = function(query, context, extra, seed){
    context = context || document;

    // Only use querySelectorAll on non-XML documents
    // (ID selectors don't work in non-HTML documents)
    if ( !seed && context.nodeType === 9 && !isXML(context) ) {
        try {
            return makeArray( context.querySelectorAll(query), extra );
        } catch(e){}
    }

    return oldSizzle(query, context, extra, seed);
};

例外が発生して oldSizzle が何とかしてくれるからです。

動くとはいえこれでは querySelectorAll が使われません(遅い)し、CSSセレクタとしても Valid ではありませんので修正すべきです。前述のとおりクォートすれば CSSjQueryセレクタとして問題ありません。

--

結論として、同じ 1.4 系でも 1.4.4 はバグセレクタの仕様が大きく変わっています。現状動いているならバージョンアップは控えるべきでしょう。

(2011/02/28 追記)

・冒頭で挙げているように、jQuery 1.4.4 はユーザーの入力したセレクタを改変してしまう不完全なクォート処理が含まれていますので、私はオススメしません。

jQuery で属性セレクタを書く時は常に属性値をクォートするようにしましょう。

--

(2011/02/24 追記)

間違ったセレクタを使っているコードを全部直してverupするのが正解では?

http://b.hatena.ne.jp/monjudoh/20110223#bookmark-31495385

ありがとうございます。問題なく動いていたので、『間違った』セレクタだとは思ってませんでした。

querySelector(All) で使用できる属性セレクタの仕様は CSS3 を見ればよさそうです。

Attribute values must be CSS identifiers or strings. [CSS21] The case-sensitivity of attribute names in selectors depends on the document language.

6.3.2. Substring matching attribute selectors - Selectors Level 3

CSS identifiers」か「strings」でなければならない、とのことです。

まず先に「string」というのは今回話題になっている「クォートされた文字列」のことです。

Strings can either be written with double quotes or with single quotes. Double quotes cannot occur inside double quotes, unless escaped (e.g., as '\"' or as '\22'). Analogously for single quotes (e.g., "\'" or "\27").

"this is a 'string'"

"this is a \"string\""

'this is a "string"'

'this is a \'string\''

4.3.7 Strings - 4 Syntax and basic data types - Cascading Style Sheets Level 2 Revision 1 %28CSS 2.1%29 Specification

この後に適切にエスケープすれば改行も含められると書いてあります。

CSS identifiers」については以下のような仕様になっています。

In CSS, identifiers (including element names, classes, and IDs in selectors) can contain only the characters [a-zA-Z0-9] and ISO 10646 characters U+00A0 and higher, plus the hyphen (-) and the underscore (_);

4.1.3 Characters and case - 4 Syntax and basic data types - Cascading Style Sheets Level 2 Revision 1 %28CSS 2.1%29 Specification

アルファベット・数字・ハイフン・アンダースコアと「U+00A0」以上のユニコード文字だけが使える、と。

んーですがこの後に

Identifiers can also contain escaped characters and any ISO 10646 character as a numeric code (see next item). For instance, the identifier "B&W?" may be written as "B\&W\?" or "B\26 W\3F".

4.1.3 Characters and case - 4 Syntax and basic data types - Cascading Style Sheets Level 2 Revision 1 %28CSS 2.1%29 Specification

『「\」でエスケープできるよ』とあり、CSS 的には「hoge\[0\]\.fuga」は間違ったセレクタでは無いように思えます。

時間が無いのでここまで。

--

(2011/02/28 追記)

エスケープしていない Invalid なセレクタを使用するために jQuery 1.4.2 を推奨するような記述になっていたため、修正しました。

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

トラックバック - http://d.hatena.ne.jp/miya2000/20110223/p0