开发者

jQuery parsing raw HTML, and hasOwnProperty on Firefox

I load up some HTML using $.get or $.ajax. In the debugger for both Chrome and Firefox i can see the html has been loaded properly:

> data

"<html><head><title></title></head><body>
<div id="topdiv" style="display:none;width:880px; height:600px;"></div>
</body</html>"

So it's a string of HTML. Great. Next I try to use jQuery to parse it:

$doc = $(data);

> $do开发者_Go百科c

[<TextNode textContent="\n\n">, 
title, 
<TextNode textContent="\n\n\n">, 
div#topdiv, 
<TextNode textContent="\n \n">]

Whoah, what? Where did html, head, body go? OK, well anyway, all I care about is the div

$div = $data.find('div');

> $div

[]

Huh??

OK. The div is empty. Upon further experimentation, I realize that jQuery basically ignores any top-level tags. Then it doesn't actually let you select any 2nd level tags, and so if there is a div nested inside the outer div, that WILL be selected. But... what??

Seems jQuery kind of chokes on those "TextNode" elements, that, curiously, it created itself (instead of html, body). So I wrote some code to get around this by looping through the elements, and extracting the non-text nodes directly:

function getNodes($doc) {
    var result = new Array();
    for (var i = 0; i < $doc.length; i++) {
        if ($doc[i].hasOwnProperty("tagName")) {
            result.push($doc[i]);
        }
    }
    return $(result);
}

Worked great! On Chrome.

Tried it in Firefox, and nothing works again.

Turns out that not every object in Firefox has a hasOwnProperty function. WHAT?? Ok. So rewrite to this:

typeof($tempHtml[i].tagName) !== 'undefined'

Finally, works in Firefox too.

Wow. Am I just being stupid? Why is so much post processing needed just to turn a string of HTML into a jQuery object? I feel like I must be missing something obvious. Is there a way to do this that does not involve such mayhem?

All I am trying to do is load up some HTML and turn it into a jQuery object. Yet it seems to be an increasingly baffling ordeal. Am I just doing something fundamentally wrong? Why is this so complicated?


Read the jQuery documentation - it addresses this issue.

When you have a HTML string that contains <html>, <head>, or <body> elements, and you do this:

$(str)

then those elements will be ignored. Only elements that can be put inside a DIV are valid and will be added to the resulting jQuery instance object.


$div = $data.find('div');

This will result in an empty jQuery object because find() searches the descendants of the current set of elements (which is one TITLE element and one DIV element in your case - and those two elements don't have descendant DIV elements).


In order to remove the Text Node objects from your jQuery object, I recommend this approach:

$data.filter(function() { return this.nodeType === 1; });

To get the DIV element, I recommend this approach:

$('<div>').html(str).find('div');

where str is your HTML string.


Alternative approach:

$(str).filter('div');


A working solution: http://jsfiddle.net/peeter/FuNhF/

As for why it's not working: http://bugs.jquery.com/ticket/6380

As for why you cannot find a child element div is because after the html and body tags are stripped you end up with a title and a div, two different un-nested elements.

    var data = $('<title></title><div id="topdiv" style="display:none;width:880px; height:600px;"></div>');
    console.log(data[0]); //Title
    console.log(data[1]); //Div

As opposed to:

var data = $('<div><div id="topdiv" style="display:none;width:880px; height:600px;"></div></div>');

console.log(data);

Where the console output is the main div with topdiv nested inside it.

You should also make sure the HTML you pass in is valid, as otherwise you will have "unexpected" results, example: http://jsfiddle.net/peeter/6wKk3/


One quick addition to @Sime's excellent answer. If you're not chaining your commands you need to set $data to the results of the filter. The filter function doesn't apply to the original collection.

$data = $data.filter(function() { return this.nodeType === 1; });
// do other stuff with your properly filtered $data collection
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜