【问题标题】:Find body tag in an ajax HTML response在 ajax HTML 响应中查找 body 标签
【发布时间】:2013-01-03 14:23:39
【问题描述】:

我正在进行 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)。我假设body是一个标签,就像'a'一样?我做错了什么?

所以这对我有用:

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

但这不是:

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

【问题讨论】:

  • 请添加您从查询 file.php 获得的示例响应
  • @Rafael 你是说我的控制台日志吗?
  • 它可以是 console.log(data) 或任何显示您通过 ajax 调用收到的完整字符串的任何内容。
  • 我刚刚检查过,使用简化的代码和不同的页面,可以确认我遇到了同样的问题。它可以选择body 中的元素,但不能选择body 本身。
  • @Rafael 我不确定,但我认为它必须是一个 url (fom input.val) 这可以是任何 url。

标签: javascript jquery ajax document-body


【解决方案1】:

通过 jQuery 对象(即$(data))解析返回的 HTML 以获取body 标记恐怕注定会失败。

原因是返回的datastring(试试console.log(typeof(data)))。现在,根据the jQuery documentation 的说法,当从包含复杂 HTML 标记的字符串创建 jQuery 对象时,body 等标签可能会被剥离。发生这种情况是因为为了创建对象,HTML 标记实际上被插入到不允许此类附加标签的 DOM 中。

来自the documentation的相关引用:

如果一个字符串作为参数传递给 $(),jQuery 会检查该字符串是否看起来像 HTML。

[...] 如果 HTML 比没有属性的单个标签更复杂,如上例所示,则元素的实际创建由浏览器的 innerHTML 机制处理。在大多数情况下,jQuery 会创建一个新元素,并将该元素的 innerHTML 属性设置为传入的 HTML sn-p。当参数有单个标签时(带有可选的关闭标签或快速关闭) - $( "" ) 或 $( "" )、$( "" ) 或 $( "" ) — jQuery 使用原生 JavaScript createElement() 函数创建元素。

在传入复杂的 HTML 时,某些浏览器可能不会生成 DOM 这完全复制了提供的 HTML 源代码。如前所述,jQuery 使用浏览器的 .innerHTML 属性来解析传递的 HTML 和 将其插入当前文档。在此过程中,一些 浏览器会过滤掉某些元素,例如 、

或 <meta http-equiv="Content-Type" content="text/html;charset=UTF-8"> 元素。因此,插入的元素可能不会 代表原始字符串传递。

【讨论】:

  • 如果您找到相关的解决方法,也将其作为答案发布。
  • 我不同意它注定要失败!我发布到此答案的解决方案完美运行,并且与 jquery 中的其他任何内容一样方便。
  • @GershomMaes OP提出的问题是关于直接解析返回的HTML字符串。您的解决方案虽然是一个巧妙的技巧,但通过首先间接将 HTML 字符串解析为 XML 文档来解决此问题。这并不能否定直接解析 HTML 会去除 body 标记的事实。
【解决方案2】:

我做了一些实验,并且已经确定了一定程度的原因,所以在等待我感兴趣的真正答案之前,这里有一个技巧可以帮助理解这个问题

$.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 是获取 iFrame 的 window.document 元素的符合标准的方式,但当然 IE 并不真正关心标准,所以这是获取 iFrame 的 @987654325 引用的方法@object 跨平台方式...

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 for an iframe

【讨论】:

  • 此外,选择器使用的语法似乎没有任何区别,因为它似乎是 jQuery 核心的限制,所以$('body',d)$(d).find('body') 具有相同的结果.
  • 您好,感谢您的关注。但是我想将我的代码用于任何给定的网站,因为我们知道有些网站不支持 iframe..
  • 也许它在“jquery 环境”中不起作用,我将不得不使用纯 javascript。到目前为止,我一直在尝试使用 document.getElementsByTagName("body")[0]; 的变体,但没有成功
  • 我认为问题在于,您不能向 DOM 添加另一个 HTMLHEADBODY。如果您尝试将DIV 标记的.innerHTML 设置为包含任何这些被禁止的元素,它根本不会添加它们——这就是我希望jQuery 无法选择它们的原因。
  • @Youss 你能解释一下哪些网站不支持 iframe 吗?我原以为这些天它们几乎得到了普遍支持。
【解决方案3】:

我想出了一些很棒的东西(我想!)

将您的 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 响应的一个共同特征可能是&lt;!DOCTYPE&gt; 标记,这会使文档在这个意义上无效。 &lt;!DOCTYPE&gt; 标签可能需要在使用这种方法之前被剥离!还要注意 &lt;!--[if IE 8]&gt;...&lt;![endif]--&gt; 等功能,没有结束标签的标签,例如:

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

...以及任何其他将被浏览器宽松解释但会使 XML 解析器崩溃的 HTML 功能。

【讨论】:

  • 太棒了!我很高兴有人能从中得到一些用处,因为当我偶然发现这个解决方案时,我个人受到了威胁:)
  • +1 虽然有明显的开销,因为 HTML 字符串被解析两次,而不是一次。对于大型 HTML 文档,这可能会很昂贵。
  • jQuery XML 解析器说以 '
【解决方案4】:

我最终得到了这个简单的解决方案:

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

也适用于 head 或任何其他 标签

(使用 xml 解析的解决方案会更好,但如果 XML 响应无效,您必须进行一些“字符串解析”。)

【讨论】:

  • 如果正文标签有任何额外的东西,比如你从 MS Word 中得到的,那将不起作用,例如.
【解决方案5】:

对我有用的正则表达式解决方案:

var head = res.match(/<head.*?>.*?<\/head.*?>/s);
var body = res.match(/<body.*?>.*?<\/body.*?>/s);

详解:https://regex101.com/r/kFkNeI/1

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-09
    • 2016-03-18
    • 2010-11-13
    • 2014-10-01
    • 2011-04-09
    • 2021-12-16
    • 2012-11-02
    相关资源
    最近更新 更多