Найти тег тела в ответе HTML ajax

Я делаю ajax-вызов для извлечения содержимого и добавления этого содержимого следующим образом:

$(function(){
    var site = $('input').val();
    $.get('file.php', { site:site }, function(data){
        mas = $(data).find('a');
        mas.map(function(elem, index) {
            divs = $(this).html();
            $('#result').append('' + divs + '');
        })
    }, 'html');
});

Проблема в том, что когда я изменяю a в body, я ничего не получаю (нет ошибки, просто нет html). Я предполагаю, что тело - это тег, как "а"? Что я делаю неправильно?

Итак, это работает для меня:

 mas = $(data).find('a');

Но это не так:

 mas = $(data).find('body');

Ответы

Ответ 1

Анализ допустимого HTML через объект jQuery (т.е. $(data)), чтобы получить тег body, обречен на провал, я боюсь.

Причина в том, что возвращенный data является string (try console.log(typeof(data))). Теперь, согласно документации jQuery, при создании объекта jQuery из строки, содержащей сложную разметку HTML, теги, такие как body, скорее всего, будут разделены. Это происходит, поскольку для создания объекта разметка HTML фактически вставлена ​​в DOM, которая не может допускать такие дополнительные теги.

Соответствующая цитата из документации:

Если строка передается как параметр в $(), jQuery проверяет строку, чтобы увидеть, выглядит ли она как HTML.

[...] Если HTML более сложный, чем один тег без атрибутов, как в приведенном выше примере, фактическое создание элементов обрабатывается механизмом браузера innerHTML. В большинстве случаев jQuery создает новый элемент и устанавливает свойство innerHTML этого элемента в фрагмент HTML, который был передан. Когда параметр имеет один тег (с дополнительным закрывающим тегом или быстрым закрытием) - $( "< lt, img/" > ") или $(" <img> "), $(" <a> </a> ") или $(" <a> ") - jQuery создает элемент с использованием встроенного JavaScript createElement().

При передаче сложного HTML некоторые браузеры не могут генерировать DOM что точно реплицирует предоставленный HTML-источник. Как уже упоминалось, jQuery использует свойство .innerHTML браузера для анализа прошедших HTML и вставьте его в текущий документ. Во время этого процесса некоторые браузеры отфильтровывают определенные элементы, такие как <html> , <title> , или <head> элементов. В результате вставленные элементы могут не быть представитель исходной строки.

Ответ 2

Я закончил с этим простым решением:

var body = data.substring(data.indexOf("<body>")+6,data.indexOf("</body>"));
$('body').html(body);

Работает также с головой или любым другим тегом .

(Решение с синтаксическим анализом xml было бы лучше, но с неверным ответом XML вы должны выполнить "синтаксический анализ строк".)

Ответ 3

Я немного экспериментировал и определил причину к точке, поэтому, ожидая реального ответа, который мне будет интересен, вот взлом, чтобы помочь понять проблему.

$.get('/',function(d){
    // replace the `HTML` tags with `NOTHTML` tags
    // and the `BODY` tags with `NOTBODY` tags
    d = d.replace(/(<\/?)html( .+?)?>/gi,'$1NOTHTML$2>',d)
    d = d.replace(/(<\/?)body( .+?)?>/gi,'$1NOTBODY$2>',d)
    // select the `notbody` tag and log for testing
    console.log($(d).find('notbody').html())
})

Изменить: дальнейшее экспериментирование

Кажется, что если вы загружаете контент в iframe, вы можете получить доступ к содержимому кадра через некоторую иерархию объектов dom...

// get a page using AJAX
$.get('/',function(d){

    // create a temporary `iframe`, make it hidden, and attach to the DOM
    var frame = $('<iframe id="frame" src="/" style="display: none;"></iframe>').appendTo('body')

    // check that the frame has loaded content
    $(frame).load(function(){

        // grab the HTML from the body, using the raw DOM node (frame[0])
        // and more specifically, it `contentDocument` property
        var html = $('body',frame[0].contentDocument).html()

        // check the HTML
        console.log(html)

        // remove the temporary iframe
        $("#frame").remove()

    })
})

Изменить: больше исследований

Похоже, что contentDocument является стандартным способом удержания элемента window.document iFrame, но, конечно, IE действительно не заботится о стандартах, так вот как получить ссылку на iFrame window.document.body объект в кросс-платформенном способе...

var iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
var iframeBody = iframeDoc.body;
// or for extra caution, to support even more obsolete browsers
// var iframeBody = iframeDoc.getElementsByTagName("body")[0]

Смотрите: contentDocument для iframe

Ответ 4

Я ЧЕРЕЗ ЧЕРЕЗ ЧЕРЕЗ (я думаю!)

Получил ваш html как строку?

var results = //probably an ajax response

Здесь объект jquery, который будет работать точно так же, как элементы, которые в настоящее время подключены к DOM:

var superConvenient = $($.parseXML(response)).children('html');

Ничего не будет удалено из superConvenient! Вы можете делать такие вещи, как superConvenient.find('body') или даже

superConvenient.find('head > script');

superConvenient работает точно так же, как элементы jquery, к которым все привыкли!!!!

Примечание

В этом случае строка results должна быть корректной XML, потому что она передается методу JQuery parseXML. Общей чертой HTML-ответа может быть тег <!DOCTYPE>, который в этом смысле недействителен. Теги <!DOCTYPE> могут быть удалены перед использованием этого подхода! Также обратите внимание на такие функции, как <!--[if IE 8]>...<![endif]-->, теги без закрывающих тегов, например:

<ul>
    <li>content...
    <li>content...
    <li>content...
</ul>

... и любые другие функции HTML, которые будут интерпретироваться с помощью браузеров мягко, но приведет к сбою анализатора XML.