我的 HTML 有什么问题,jQuery 没有解析它?

What is wrong with my HTML that jQuery doesn't parse it?

提问人:Bram Vanroy 提问时间:5/11/2017 最后编辑:CommunityBram Vanroy 更新时间:5/19/2017 访问量:772

问:

我一直在尝试获取一个 HTML 文件并将其作为 jQuery 对象分配给变量。无济于事。我不确定 Stack Snippets 是否允许 GET 请求,所以这里也是一个 JSFiddle 链接

    var html = '<!DOCTYPE html><html lang="en"><head><title>Template</title></head><body itemscope itemtype="http://schema.org/WebPage"><main><header itemscope itemtype="http://schema.org/Country" itemprop="about"><h1 itemprop="name">Dummy heading</h1><p><span class="capital" title="Capital" itemprop="containsPlace"></span><span title="Dummy title" itemprop="additionalProperty" itemscope itemtype="http://schema.org/PropertyValue"><meta itemprop="name" content="Member of the EU since"><span itemprop="value" class="member-since">Dummy year</span></span></p></header><div itemprop="mainEntity" itemscope itemtype="http://schema.org/ItemList"><meta itemprop="description" content=""><article class="recipe loading" itemprop="itemListElement" itemscope itemtype="http://schema.org/Recipe"><meta itemprop="position" content=""><aside class="media"><div class="img-gallery" itemscope itemtype="http://schema.org/ImageGallery"></div><div itemscope itemtype="http://schema.org/VideoObject" class="youtube"><a itemprop="contentUrl" href="#" title=""><meta itemprop="name" content=""><meta itemprop="uploadDate" content=""><meta itemprop="description" content=""><img itemprop="thumbnailUrl" src="#" alt=""></a><div class="youtube-player"></div></div></aside><div class="text"><div class="wiki-text"><h1 itemprop="name">Dummy heading</h1><p itemprop="description"></p><p class="read-more">For more information about <span class="recipe-name"></span>, read the <a href="#" title="" itemprop="sameAs">Wiki</a>.</p></div><div class="rating" itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">Rated <span itemprop="ratingValue">3.5</span>/5 based on <span itemprop="reviewCount">11</span> customer reviews</div><div class="cooking"><h2>Bake it yourself!</h2><div><meta itemprop="cookTime" content=""><span>Bake time: <span class="bake-time"></span></span></div><div class="ingredients-wrapper"><h3>Ingredients <small>for <span itemprop="recipeYield"></span></small></h3><div class="ingredients"><h4>Dummy heading</h4><ul></ul></div></div><div class="how-to"><h3>Steps</h3><ol></ol></div></div></div></article></div></main></body></html>';
    
    $.ajax({
      type: 'post',
      url: "/echo/html/",
      dataType: "html",
      data: {
        html: html,
        delay: 1
      }
    }).done(function(data) {
      // string
    	console.log(data);
      // array
      console.log($(data));
      // array
      console.log($.parseHTML(data));
      // array
      console.log($($.parseHTML(data)));
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

HTML 有效。然而,我无法在对象中得到它。正如预期的那样,返回的数据是一个字符串。但是,当我尝试使用或将其放入jQuery选择器中或将其放入jQuery选择器中,甚至尝试两者时,我总是得到相同的结果:一个包含标题和主要元素的数组。$.parseHTML()$()

因此,jQuery仍然以某种方式解析它,并创建一个由头部中的元素和正文中的一个元素组成的数组。但为什么呢?我该如何解决这个问题,并将其转换为jQuery对象?我只对身体的内容感兴趣。

有一个类似的问题,但公认的解决方案在进入 JSFiddle 时无济于事,我在 XAMPP 本地也遇到了这个问题。

jQuery ajax html 解析

评论


答:

2赞 tao 5/11/2017 #1
document.querySelector("body").innerHTML = + 
  '<object type="text/html" data="'+html+'" ></object>';

...只是工作。所以我本来以为:

let parsedHtml = $('<object />', {
  type:'text/html',
  data:html
}).html()

也只是工作,但我猜当人们真正将其添加到 DOM 时会发生一些魔术。它解析它,为它构建 CSSOM 和 DOM,并加载所有依赖项,基本上是你期望浏览器对资源做的事情。.html

所以这里有一种方法可以做到这一点:

  1. 创建一个虚拟占位符,
  2. 放置里面,<object>
  3. 将虚拟人附加到 DOM 中,
  4. 得到(在它的事件上),.contents()<object>onload
  5. 并删除假人。
let html = '// your valid html...',
    dummyDiv = $('<div />',{
      html: '<object type="text/html" data="'+html+'" ></object>',
      style:"height:0;overflow:hidden;"
    });

$('html').append(dummyDiv);
console.log(dummyDiv.find('object').contents());

注意:Chrome 已经足够智能,可以检测到父级,并且不会加载 <object>。这就是我使用.您会注意到此元素的内容没有 jQuery 对象的典型结构,因为它是一个文档。你会发现果汁display:noneheight:0;overflow:hidden;

dummyDiv.find('object').contents()[1].innerHTML

当 html 字符串已经在变量中时,它会立即加载,但实际上您需要将侦听器放在 并且只运行 4. 和 5. 当侦听器触发时。onload<object>

评论

0赞 Bram Vanroy 5/11/2017
嗯,有什么方法可以在不先将元素添加到 DOM 的情况下做到这一点吗?问题是我想将内容加载到内存中,对其进行一些修改(克隆、分离、整个交易),然后将其添加到 DOM。在内存中,因为这应该比进行 DOM 修改更快。
0赞 tao 5/11/2017
我不知道。事情就是这样,它被正确解析。否则,你可以对你的字符串运行一些技巧,但它不是一个元素,所以不是所有的元素都可用。例如,在 ur 上运行并按类选择将起作用,而按标签选择则不起作用,因为它不是 DOM。这是一个字符串。使用上述方法,您不仅可以等待 ajax 加载,还可以等待生成的 DOM 正确加载(以防万一它有一些 DOM 操作脚本)。jQueryDOM.find()$(data)
0赞 Bram Vanroy 5/11/2017
明白了。聪明。因此,最好的主意可能是将其附加到 html/body,然后在 VAR 中执行 a,有效地将解析的内容放回内存中,删除虚拟内容。操纵 VAR,并将 VAR 添加回 DOM?.detach()
0赞 tao 5/11/2017
是的。jQuery将像在普通DOM上一样工作,因为它是普通的DOM,即使与现有DOM分离也是如此。但是,我不知道如何在不将其放入 DOM 的情况下触发它的解析/加载。我敢肯定这是可能的(毕竟 DOM 做到了,对吧?我只是对内部流程了解不够。坦率地说,只要我得到结果,我就不在乎,哈哈。
1赞 Bram Vanroy 5/11/2017
我会把这个问题搁置一会儿,加上一个小赏金,也许一些jQuery大师可以启发我们。:-)
1赞 guest271314 5/16/2017 #2

jQuery.ajax() 选项设置为 。用于将字符串解析为 ; 获得申报; 写入并解析为当前或其他 .processDatafalseDOMParser()htmldocumentXMLSerizlizer()DOCTYPEdocument.write()DOCTYPEdocument.documentElement.outerHTMLhtmldocument

processData(默认值:true)

类型:Boolean

默认情况下,数据作为对象传入到选项中 (从技术上讲,除字符串以外的任何内容)将被处理并 转换为查询字符串,适合默认的 content-type “application/x-www-form-urlencoded”。如果您想发送一个 DOMDocument 或其他未处理的数据,将此选项设置为 。datafalse


我不确定 Stack Snippets 是否允许 GET 请求

是的。可以通过将资源设置为 或表示资源来回显请求,或者 ,请参阅 Stack Overflow 是否在代码片段中有一个“回显页面”来测试 AJAX 请求?GETurldata URIBlob URL$.ajax()XMLHttpRequest()fetch()

var html = `<!DOCTYPE html>
<html lang="en">

<head>
  <title>Template</title>
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <main>
    <header itemscope itemtype="http://schema.org/Country" itemprop="about">
      <h1 itemprop="name">Dummy heading</h1>
      <p><span class="capital" title="Capital" itemprop="containsPlace"></span><span title="Dummy title" itemprop="additionalProperty" itemscope itemtype="http://schema.org/PropertyValue"><meta itemprop="name" content="Member of the EU since"><span itemprop="value" class="member-since">Dummy year</span></span>
      </p>
    </header>
    <div itemprop="mainEntity" itemscope itemtype="http://schema.org/ItemList">
      <meta itemprop="description" content="">
      <article class="recipe loading" itemprop="itemListElement" itemscope itemtype="http://schema.org/Recipe">
        <meta itemprop="position" content="">
        <aside class="media">
          <div class="img-gallery" itemscope itemtype="http://schema.org/ImageGallery"></div>
          <div itemscope itemtype="http://schema.org/VideoObject" class="youtube">
            <a itemprop="contentUrl" href="#" title="">
              <meta itemprop="name" content="">
              <meta itemprop="uploadDate" content="">
              <meta itemprop="description" content=""><img itemprop="thumbnailUrl" src="#" alt=""></a>
            <div class="youtube-player"></div>
          </div>
        </aside>
        <div class="text">
          <div class="wiki-text">
            <h1 itemprop="name">Dummy heading</h1>
            <p itemprop="description"></p>
            <p class="read-more">For more information about <span class="recipe-name"></span>, read the <a href="#" title="" itemprop="sameAs">Wiki</a>.</p>
          </div>
          <div class="rating" itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">Rated <span itemprop="ratingValue">3.5</span>/5 based on <span itemprop="reviewCount">11</span> customer reviews</div>
          <div class="cooking">
            <h2>Bake it yourself!</h2>
            <div>
              <meta itemprop="cookTime" content=""><span>Bake time: <span class="bake-time"></span></span>
            </div>
            <div class="ingredients-wrapper">
              <h3>Ingredients <small>for <span itemprop="recipeYield"></span></small></h3>
              <div class="ingredients">
                <h4>Dummy heading</h4>
                <ul></ul>
              </div>
            </div>
            <div class="how-to">
              <h3>Steps</h3>
              <ol></ol>
            </div>
          </div>
        </div>
      </article>
    </div>
  </main>
</body>
</html>`;


$.ajax({
    type: "GET",
    url: "data:text/html," + html,
    processData: false
  })
  .then(function(data) {
    // string
    console.log(data);
    var parser = new DOMParser();
    // document
    var d = parser.parseFromString(data, "text/html");
    // `document`, `document` as jQuery object
    console.log(d, $(d));
    // get elements having `itemscope` attribute
    console.log($(d).find("[itemscope]"));
    // do stuff
    var dt = new XMLSerializer().serializeToString(d.doctype);
    document.write(dt, d.documentElement.outerHTML);
  })
  .fail(function(jqxhr, textStatus, errorThrown) {
    console.log(errorThrown);
  });
  
  
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

也可以将属性设置为 的 当前 using 元素导入 ,请参阅如何使用 jquery 附加整个 html 文件htmldocumentdocument<link>rel"import"

评论

0赞 guest271314 5/16/2017
您也可以使用 with set to 获取 as at 或 event,或者 获取 as 。XMLHttpRequest().responseType"document"#documentXMLHttpRequest.responseloadreadystatechangefetch()Response.blob()htmlBlob
0赞 Bram Vanroy 5/16/2017
与使用 dataType: html 有什么区别?这难道不是它应该做的吗?将检索到的内容处理为 html?
0赞 guest271314 5/16/2017
使用 返回相同的结果。dataType:"html"
0赞 guest271314 5/16/2017
@BramVanroy 也就是说,当同样使用 .DOMParser
0赞 Asav Vora 5/16/2017 #3

问题是您正在尝试访问直接html,但实际上它是一个字符串。

因此,您必须渲染 html 才能访问数据。

为此,将响应数据存储到任何 html 元素中并通过它进行访问。

我更改了你的 jsfiddle,所以你可以看到。

0赞 ハセン 5/18/2017 #4

我总是得到相同的结果:一个包含标题和主元素的数组。

问题到底出在哪里?

jQuery仍然解析它,并创建一个由头部中的元素和正文中的一个元素组成的数组。但是为什么?

你期待什么?

这似乎是 parseHtml 的行为。

下面是另一个示例:

$.parseHTML("<div>Hello<span>World</span></div>")

它返回一个包含一个元素的数组:div

如果你看一下 parseHTML 的文档,它说:

将字符串解析为 DOM 节点数组。

所以它似乎正在做它应该做的事情。

我只对身体的内容感兴趣。

正如你所指出的,正文的内容是第二个元素。main

你想用它做什么?

可以通过将 jQuery 对象传递给 jQuery 构造函数来将其包装在 jQuery 对象中。

var html = '<!DOCTYPE html><html lang="en"><head><title>Template</title></head><body itemscope itemtype="http://schema.org/WebPage"><main><header itemscope itemtype="http://schema.org/Country" itemprop="about"><h1 itemprop="name">Dummy heading</h1><p><span class="capital" title="Capital" itemprop="containsPlace"></span><span title="Dummy title" itemprop="additionalProperty" itemscope itemtype="http://schema.org/PropertyValue"><meta itemprop="name" content="Member of the EU since"><span itemprop="value" class="member-since">Dummy year</span></span></p></header><div itemprop="mainEntity" itemscope itemtype="http://schema.org/ItemList"><meta itemprop="description" content=""><article class="recipe loading" itemprop="itemListElement" itemscope itemtype="http://schema.org/Recipe"><meta itemprop="position" content=""><aside class="media"><div class="img-gallery" itemscope itemtype="http://schema.org/ImageGallery"></div><div itemscope itemtype="http://schema.org/VideoObject" class="youtube"><a itemprop="contentUrl" href="#" title=""><meta itemprop="name" content=""><meta itemprop="uploadDate" content=""><meta itemprop="description" content=""><img itemprop="thumbnailUrl" src="#" alt=""></a><div class="youtube-player"></div></div></aside><div class="text"><div class="wiki-text"><h1 itemprop="name">Dummy heading</h1><p itemprop="description"></p><p class="read-more">For more information about <span class="recipe-name"></span>, read the <a href="#" title="" itemprop="sameAs">Wiki</a>.</p></div><div class="rating" itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating">Rated <span itemprop="ratingValue">3.5</span>/5 based on <span itemprop="reviewCount">11</span> customer reviews</div><div class="cooking"><h2>Bake it yourself!</h2><div><meta itemprop="cookTime" content=""><span>Bake time: <span class="bake-time"></span></span></div><div class="ingredients-wrapper"><h3>Ingredients <small>for <span itemprop="recipeYield"></span></small></h3><div class="ingredients"><h4>Dummy heading</h4><ul></ul></div></div><div class="how-to"><h3>Steps</h3><ol></ol></div></div></div></article></div></main></body></html>';

var parsed = $.parseHTML(html)
var main = parsed[1]
var $main = $(main)
// $main is a jQuery object
console.log("h4 content:", $main.find('h4').text())