A colleague told me that the jQuery 1.3.2 selector is very buggy. Let's see.
Tested to run on IE 7.0, FireFox 3.0, FireFox 3.5, Opera 9.64, Opera 10b, Chrome 2.0 and Safari 4.0.
$("div.test h1").length | 1 | |
$("div.test").find("h1").length | 1 | |
$("div.test p").length | 3 | |
$("div.test").find("p").length | 3 |
$("elm h1", xml_dom).length | 1 | |
$("elm", xml_dom).find("h1").length | 1 | |
$("elm p", xml_dom).length | 3 | |
$("elm", xml_dom).find("p").length | 3 |
$(_NS("ns\\:elm ns\\:h1"), xml_dom2).length | 1 | |
$(_NS("ns\\:elm"), xml_dom2).find(_NS("ns\\:h1")).length | 1 | |
$(_NS("ns\\:elm ns\\:p"), xml_dom2).length | 3 | |
$(_NS("ns\\:elm"), xml_dom2).find(_NS("ns\\:p")).length | 3 |
It looks like jQuery 1.3.2 is buggy for XML with namespace. But how many people use such XML?
jQuery manipulates namespaced XML poorly. First, jQuery uses ':' to denote a selector. That means the XML namespace must be escaped as '\:'. However, '\' is a special character in Javascript strings, so we need to write it as '\\:'.
Then, some browsers require you to omit the namespace when querying.
jQuery does not abstract this, so the caller has to do it. The only way
currently is to use a wrapper function, hence the wrapper _NS()
call.
The known browsers are, FireFox 2, Opera 9.x, Opera 10b, Chrome 2, Safari 3.x and Safari 4. Note that FireFox 3 requires the namespace, so there is precedence that browsers may change over time.
Thus, rather than hardcoding which browser requires special handling, we test it during startup:
$("ns\\:elm", xml_dom2).length | Access an element directly | |
$("elm", xml_dom2).length | Access it without the namespace |
Your browser is .
It can be very long, but that's how some browsers identify themselves.
(For speed, we will probably hardcode the known browser/versions and test only the unknown ones.)
Can your browser handle clone()
? HTML is not a problem, but
you cannot take it for granted for XML. It works in IE and FireFox, but not
Opera, Safari and Chrome. In particular, it gives an error in Opera.
$("div.test").clone().length | 1 | |
$("div.test").clone().children().length | 4 | |
$("*", "div.test").clone().length | 4 |
$(xml_dom).length | 1 | |
$(xml_dom).children().length | 1 | |
$(xml_dom).children().children().length | 2 | |
$(xml_dom).clone().length | 1 | |
$(xml_dom).clone().children().length | 1 | |
$(xml_dom).clone().children().children().length | 2 | |
$("*", xml_dom).clone().length | 9 | |
$(xml_dom).children().clone().length | 1 | |
$(xml_dom).children().clone().children().length | 2 |
This table gives us a clue what's wrong. $(xml_dom).length
is
1, but $(xml_dom).children().length
is also 1! Thus, the XML
object that we have is actually the XML document. The next level is the XML
DOM that we are interested in.
For some reason, some browsers do not allow us to clone the XML document. Now that we know this is the case, we clone the XML DOM instead. It works!
$(xml_dom2).length | 1 | |
$(xml_dom2).children().length | 1 | |
$(xml_dom2).children().children().length | 2 | |
$(xml_dom2).clone().length | 1 | |
$(xml_dom2).clone().children().length | 1 | |
$(xml_dom2).clone().children().children().length | 2 | |
$("*", xml_dom2).clone().length | 9 | |
$(xml_dom2).children().clone().length | 1 | |
$(xml_dom2).children().clone().children().length | 2 |
It is really unfortunate that Opera has such a small market share that people don't see the need to make it work.