views:

138

answers:

3

hi all,

I'm using jQuery to parse some XML, like so:

function enumOptions(xml) {
   $(xml).find("animal").each(function(){  
       alert($(this).text());
   });
}

enumOptions("<root><animal>cow</animal><animal>squirrel</animal></root>");

This works great. However if I try and look for nodes called "option" then it doesn't work:

function enumOptions(xml) {
   $(xml).find("option").each(function(){  
      alert($(this).text());
   });
}

enumOptions("<root><option>cow</option><option>squirrel</option></root>");

There's no error, just nothing gets alerted, as if the find isn't finding anything. It only does it for nodes called option everything else I tested works ok!

I'm using the current version of jQuery - 1.4.2.

Anyone any idea?

TIA.

bg

+1  A: 

This is probably some special handling for the HTML <option> element, but I can't find that in the source.

SLaks
+1 - This is correct, I've seen the same thing with `<table>` in XML, any valid html elements the browser may interfere with.
Nick Craver
+1  A: 

On line 4448 of the unminified source for 1.4.2 is the culprit:

// ( div = a div node )
// ( elem = the xml you've passed to it )

div.innerHTML = wrap[1] + elem + wrap[2]; 

Consider this code:

var d = document.createElement('div');
d.innerHTML = "<foo><option>bar</option><b>blah</b></foo>";

alert(d.innerHTML); // <foo>bar<b>blah</b></foo>

// tested on Firefox 3.6

So, don't ask me why exactly, but it looks like something in the way the DOM handles it, not necessarily jQuery's fault.

Perhaps just use a different node name?

nickf
Just found that too. As far as I can tell, jQuery itself doesn't do any XML parsing whatsoever - it leverages "innerHTML" to convert a string into DOM nodes. Thus, it's not even XML that we're talking about: it's whatever you can convince the browser's HTML parser is valid markup.
Pointy
@Pointy - good response - you should make it an answer
nickf
+2  A: 

jQuery relies on the HTML DOM using innerHTML to parse the document which can have unreliable results when tag names collide with those in HTML.

Instead, you can use a proper XML parser to first parse the document, and then use jQuery for querying. The method below will parse a valid XML document in a cross-browser fashion:

// http://www.w3schools.com/dom/dom_parser.asp
function parseXML(text) {
    var doc;

    if(window.DOMParser) {
        var parser = new DOMParser();
        doc = parser.parseFromString(text, "text/xml");
    }
    else if(window.ActiveXObject) {
        doc = new ActiveXObject("Microsoft.XMLDOM");
        doc.async = "false";
        doc.loadXML(text);
    }
    else {
        throw new Error("Cannot parse XML");
    }

    return doc;
}

Once the XML DOM is constructed, jQuery can be used as normal - http://jsfiddle.net/Rz7Uv/

var text = "<root><option>cow</option><option>squirrel</option></root>";
var xml = parseXML(text);
$(xml).find("option"); // selects <option>cow</option>, <option>squirrel</option>
Anurag