37

我正在尝试通过 jQuery 解析这个 html 以获取 data1、data2、data3。虽然我确实获得了 data2 和 data3,但我无法通过我的方法获得 data3。我对jQuery相当陌生,所以请原谅我的无知。

<html>
<body>
   <div class="class0">
    <h4>data1</h4>
    <p class="class1">data2</p>
    <div id="mydivid"><p>data3</p></div>    
   </div>
</body>
</html>

这是我在 jquery 中的调用方式。

var datahtml = "<html><body><div class=\"class0\"><h4>data1</h4><p class=\"class1\">data2</p><div id=\"mydivid\"><p>data3</p></div></div></body></html>";

alert($(datahtml).find(".class0").text()); // Doesn't Work

alert($(datahtml).find(".class1").text()); // work 

alert($(datahtml).find("#mydivid").text()); // work

只有alert($(datahtml).find(".class0").text());不工作,其余的都按预期工作。我想知道这可能是因为 class0 里面有多个标签还是什么?在这种情况下如何获取 data1 ?

4

7 回答 7

58

目前的答案都没有解决真正的问题,所以我会试一试。

var datahtml = "<html><body><div class=\"class0\"><h4>data1</h4><p class=\"class1\">data2</p><div id=\"mydivid\"><p>data3</p></div></div></body></html>";

console.log($(datahtml));

$(datahtml)div.class0是一个仅包含元素的 jQuery 对象,因此当您调用.find它时,您实际上是在寻找后代div.class0而不是您期望的整个 HTML 文档。

一个快速的解决方案是将解析的数据包装在一个元素中,以便.find按预期工作:

var parsed = $('<div/>').append(datahtml);
console.log(parsed.find(".class0").text());

小提琴


这样做的原因不是很简单,但我假设 jQuery 通过简单地将 HTML 字符串放入单独的动态创建 DOM 片段然后检索解析的元素来“解析”更复杂的 html 字符串,此操作很可能会使 DOM 解析器忽略htmlandbody标记,因为在这种情况下它们是非法的。

这是一个非常小的测试套件,它证明了这种行为在 jQuery 1.8.2 一直到 1.6.4 都是一致的。

编辑:引用这篇文章

问题是 jQuery 创建了一个 DIV 并设置innerHTML然后获取 DIV 子元素,但由于 BODY 和 HEAD 元素不是有效的 DIV 子元素,因此浏览器不会创建这些元素。

让我更加确信我的理论是正确的。我会在这里分享它,希望它对你有一些意义。将 jQuery 1.8.2 的未压缩源与此放在一起。#表示行号。

所有通过(定义@#6122)生成的文档片段都将通过(#6151)(即使它是一个缓存的片段,它在创建时已经通过),并且正如上面引用的文本所暗示的那样,(定义@# 6275)在安全片段内创建一个新的作为已解析数据的容器 -在 #6301-6303 创建的元素,在 #6344 检索,在 #6347 删除 div 以进行清理(加上 #6359-6361 作为错误修复),在#6351-6355 处合并到返回数组中并在#6406 处返回。jQuery.buildFragmentjQuery.cleanjQuery.cleanjQuery.cleandivdivchildNodeschildNodes

因此,所有调用 的方法jQuery.buildFragment,其中包括jQuery.parseHTMLjQuery.fn.domManip- 其中包括.append().after().before()它们调用 domManipjQuery 对象方法,以及$(html)jQuery.fn.init(定义 @#97,处理复杂 [多个单个标签] html 字符串 @#125 , 调用jQuery.parseHTML@#131)。

几乎所有 jQuery HTML 字符串解析(除了单标签 html 字符串)都是使用div元素作为容器完成的,并且html/body标签不是div元素的有效后代,因此它们被剥离是有道理的。


附录:较新版本的jQuery(1.9+)已经重构了HTML解析逻辑(例如,内部jQuery.clean方法不再存在),但整体解析逻辑保持不变。

于 2012-10-09T21:49:28.863 回答
26

它的行为很奇怪,因为它忽略了 html 和 body 标记,并从 class = "class0" 的第一个 div 开始。html 被解析为 DOM 元素,但未添加到 DOM。对于添加到 DOM 的元素,选择器不会忽略 body 标签并在文档上应用选择器。您需要将 html 添加到 DOM,如下所示。

现场演示

$('#div1').append($(datahtml)); //Add in DOM before applying jquery methods.

alert($('#div1').find(".class0").text()); // Now it Works too

alert($('#div1').find(".class1").text()); // work   

alert($('#div1').find("#mydivid").text()); // work

如果我们将您的 html 包装在某个 html 元素中以使其成为起点而不是您的第一个带有 class="class0" 的 div,那么您的选择器将按预期工作。

现场演示

var datahtml = "<html><body><div><div class=\"class0\"><h4>data1</h4><p class=\"class1\">data2</p><div id=\"mydivid\"><p>data3</p></div></div></div></body></html>";

alert($(datahtml).find(".class0").text()); // Now it Works too

alert($(datahtml).find(".class1").text()); // work   

alert($(datahtml).find("#mydivid").text()); // work

jQuery 文档对 jQuery 解析函数 jQuery() 即 $() 的评价

在传递复杂的 HTML 时,某些浏览器可能无法生成完全复制所提供的 HTML 源的 DOM。如前所述,jQuery 使用浏览器的 .innerHTML 属性来解析传递的 HTML 并将其插入到当前文档中。在此过程中,一些浏览器会过滤掉某些元素,例如 <html><title>、 或 <head>元素。因此,插入的元素可能不能代表传递的原始字符串。

于 2012-10-09T21:57:00.513 回答
3

我想我有一个更好的方法:

假设你有你的 html:

var htmlText = '<html><body><div class="class0"><h4>data1</h4><p class="class1">data2</p><div id="mydivid"><p>data3</p></div></div></body></html>'

这是您一直希望做的事情:

var dataHtml = $($.parseXML(htmlText)).children('html');

dataHtml现在的工作方式与您熟悉的普通 jquery 对象完全一样!!

这个解决方案的美妙之处在于它不会剥离 body、head 或 script 标签!

于 2014-05-26T19:45:06.977 回答
2

尝试这个

alert($(datahtml).find(".class0 h4").text());

原因是您所指的文本在.. 的h4元素 内部,class0因此您的选择器将不起作用,或者直接访问内容..

alert($(".class0 h4").text()); 

alert($(".class1").text()); 

alert($("#mydivid").text()); 

编辑

var datahtml = "<html><body><div class=\"class0\"><h4>data1</h4><p class=\"class1\">data2</p><div id=\"mydivid\"><p>data3</p></div></div></body></html>";

$('body').html(datahtml);

   alert($(".class0 h4").text()); 

    alert($(".class1").text()); 

    alert($("#mydivid").text()); 

检查演示

于 2012-10-09T21:40:14.850 回答
1

除了将 HTML 放在一个临时的不可见容器中之外,我不知道任何其他方法。

$(document).ready(function(){
  var datahtml = $("<html><body><div class=\"class0\"><h4>data1</h4><p class=\"class1\">data2</p><div id=\"mydivid\"><p>data3</p></div></div></body></html>".replace("\\", ""));
  var tempContainer = $('<div style="display:none;">'+ datahtml +'</div>');
  $('body').append(tempContainer);
  alert($(tempContainer).find('.class1').text());
  $(tempContainer).remove();                                                                                                                                                        
});
​

这是一个jsfiddle 演示

于 2012-10-09T21:44:34.373 回答
0

它不起作用,因为<div>with 类class0没有任何文本节点作为直接子节点。将类添加到<h4>,它将起作用

于 2012-10-09T21:39:58.970 回答
0

我认为主要问题是你的 jquery 不能有 html。在您的情况下,Jquery 发生的事情是它试图找到第一个 html 标记,在您的情况下是带有 class0 的 div。

测试一下,看看我是对的:

if($(datahtml).hasClass('class0'))
    alert('Yes you are right :-)');

因此,这意味着您不能将 html 和/或 body 标记添加为其中的一部分以进行查询。

如果你想让它工作,只需尝试添加这部分代码:

<div>
    <div class="class0">
        <h4>data1</h4>
        <p class="class1">data2</p>
        <div id="mydivid"><p>data3</p></div>    
   </div>
</div>

所以试试这个:

var datahtml = "<div><div class=\"class0\"><h4>data1</h4><p class=\"class1\">data2</p><div id=\"mydivid\"><p>data3</p></div></div></body></div>";

alert($(datahtml).find(".class0").text()); // work

alert($(datahtml).find(".class1").text()); // work 

alert($(datahtml).find("#mydivid").text()); // work
于 2012-10-09T21:40:12.017 回答