views:

287

answers:

1

I'm trying to traverse an AJAX response, which contains a remote web page (an HTML output).

My goal is to iterate through the 'script', 'link', and 'title' elements of the remote page - load them if necessary, and embed its contents to the current page.

Its working great in FF/IE, but for some reason - Chrome & Safari behaves differently: When I run a .each() loop on the response, Chrome/Safari seems to omit everything that is under the section of the page.

Here's my current code:

$.ajax({
    url: 'remoteFile.php',
    cache: false,
    dataFilter: function(data) { 
        console.log(data); 
        /* The output seems to contain the entire response, including the <head> section - on all browsers, including Chrome/Safari */

        $(data).filter("link, script, title").each(function(i) {
            console.log($(this)); 
            /* IE/FF outputs all of the link/script/title elements, Chrome will output only those that are not in the <head> section */
        });

        console.log($(data)); 
        /* This also outputs the incomplete structure on Chrome/Safari */

        return data;
    },
    success: function(response) {}
});

I've been struggling with this problem for quite a while now, i've found some other similar cases on google searches, but no real solution. This happens on both jQuery 1.4.2, and jQuery 1.3.2.

I really don't want to parse the response with .indexOf() and .substring() - it seems to me that it will be an overkill for the client.

Many thanks in advance!

+1  A: 

I think this has to do with how jQuery processes HTML strings and creates DOM nodes from them. Amongst a bunch of other things, jQuery will create a temporary <div> and set its innerHTML to whatever HTML you pass to $(...) thus producing a bunch of DOM nodes which can be extracted from the <div> and handed back to you as a jQuery collection.

The problem, I believe, occurs because of the <html>, <head> and <body> elements, all of which don't respond well to being appended to a <div> element. Browsers tend to behave differently, -- some appear to ignore these top-level elements and just hand you back their contents -- others completely ignore the elements, and won't even give you their descendants.

It seems, the way to avoid this cross-browser issue is to simply replace the troublesome elements with some other fake elements before parsing. E.g.

$(
    // replace <html> with <foohtml> .. etc.
    data.replace(/<(\/?)(head|html|body)(?=\s|>)/g, '<foo$1$2')
).filter("link, script, title").each(function(i) {
    console.log($(this));
    // do your stuff
});

Also, I don't think filter will be sufficient, since it won't target descendent elements. This may be a better approach:

$(
    // replace <html> with <foohtml> .. etc.
    data.replace(/<(\/?)(head|html|body)(?=\s|>)/g, '<foo$1$2')
).find('link,script,title').andSelf().filter("link,script,title").each(function(i) {
    console.log($(this));
    // do your stuff
});
J-P
Thank you so much!I would've never guess that this was the source of the problem, your solution works great!Thank you for your suggestion as well!much appreciated
jitzo