Найти тег body в ответе ajax HTML
Я делаю 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). Я предполагаю, что тело - это тег, похожий на 'a'? Что я делаю неправильно?
Так что это работает для меня:
mas = $(data).find('a');
Но это не так:
mas = $(data).find('body');
4 ответа
Разбор возвращенного HTML через объект jQuery (т.е. $(data)
) чтобы получить body
тег обречен на провал, боюсь.
Причина в том, что возвращенный data
это string
(пытаться console.log(typeof(data))
). Теперь, согласно документации jQuery, при создании объекта jQuery из строки, содержащей сложную разметку HTML, используются такие теги, как body
могут быть раздеты. Это происходит потому, что для создания объекта HTML-разметка фактически вставляется в DOM, который не может разрешить такие дополнительные теги.
Соответствующая цитата из документации:
Если строка передается в качестве параметра в $(), jQuery проверяет строку, чтобы увидеть, выглядит ли она как HTML.
[...] Если HTML является более сложным, чем отдельный тег без атрибутов, как в приведенном выше примере, фактическое создание элементов обрабатывается механизмом innerHTML браузера. В большинстве случаев jQuery создает новый элемент и присваивает свойству innerHTML элемента тот фрагмент HTML, который был передан. Когда параметр имеет один тег (с необязательным закрывающим тегом или быстрым закрытием) - $( "") или $( ""), $( " a >") или $( "") - jQuery создает элемент с помощью встроенной функции JavaScript createElement().
При передаче сложного HTML некоторые браузеры могут не генерировать DOM, который точно копирует предоставленный исходный код HTML. Как уже упоминалось, jQuery использует свойство браузера.innerHTML для анализа переданного HTML-кода и вставки его в текущий документ. Во время этого процесса некоторые браузеры отфильтровывают определенные элементы, такие как элементы ,
или В результате вставленные элементы могут не соответствовать исходной переданной строке.
Я закончил с этим простым решением:
var body = data.substring(data.indexOf("<body>")+6,data.indexOf("</body>"));
$('body').html(body);
Работает также с головой или любым другим тегом.
(Решение с синтаксическим анализом xml было бы лучше, но с недопустимым ответом XML вы должны выполнить некоторый "синтаксический анализ строки".)
Я немного поэкспериментировал и определил причину до такой степени, поэтому в ожидании реального ответа, который меня заинтересует, вот хак, чтобы помочь понять проблему
$.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's `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
Я выяснил что-то чудесное (я думаю!)
Получил ваш 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.
Решение Regex, которое сработало для меня:
var head = res.match(/<head.*?>.*?<\/head.*?>/s);
var body = res.match(/<body.*?>.*?<\/body.*?>/s);
Подробное объяснение: https://regex101.com/r/kFkNeI/1