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

I am trying to get an HTML file and assign it to a variable as a jQuery object. But to no avail. I'm not sure if Stack Snippets allow GET requests, so here's a JSFiddle link .

    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>
      

Run codeHide result


HTML is valid. However, I am unable to get it in the object. The returned data is, as expected, a string. But when I try to parse this string as HTML using, $.parseHTML()

or put it in a jQuery selector, $()

or even try both, I always get the same result: an array containing the title and main element.

So somehow, the way jQuery still parses it and creates an array of element in the head and one element in the body. But why? And how can I fix this and turn it into a jQuery object? I'm only interested in the contents of the body.

There is a similar question but the accepted solution does not help as it is included in the JSFiddle and I am also experiencing this problem locally with XAMPP.

+3


source to share


4 answers


document.querySelector("body").innerHTML = + 
  '<object type="text/html" data="'+html+'" ></object>';

      

... just works. So I expected:

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

      

also simple to work, but I'm guessing some magic happens when someone actually adds it to the DOM. It parses it, creates a CSSOM and DOM for it and loads all dependencies, basically what you would expect from a browser with a resource .html

.

So, here's how to do it:



  • Create a dummy placeholder,
  • put <object>

    inside,
  • add fiction to the DOM,
  • get .contents()

    from <object>

    ( onload

    event on it ),
  • and delete the dummy file.
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());

      

Note. Chrome is already smart enough to detect display:none

from a parent and not download <object>

. This is why I used height:0;overflow:hidden;

. You will notice that the content of this element does not have the typical structure of a jQuery object, because it is a document. you will find juice in

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

      

When the html string is already in a variable, it loads instantly, but in reality you need to place the listener onload

on <object>

and only run 4. and 5. when the listener starts.

+2


source


Install the variant . Use to parse lines into ; to get an ad ; write and disassemble into current or other .jQuery.ajax()

processData

false

DOMParser()

html

document

XMLSerizlizer()

DOCTYPE

document.write()

DOCTYPE

document

.documentElement.outerHTML

html

document

processData strong> (default: true

)

Type: Boolean

By default, the data is passed to the parameter data

as an object (technically, nothing but a string) will be processed and converted to a query string, matching the default content type "Application / x-WWW-forms-urlencoded". If you want to send a DOMDocument or other unprocessed data, set this parameter to false

.


I'm not sure if Stack Snippets allow GET requests



Yes. It is possible to request the request GET

by setting url

in data URI

or Blob URL

the resource view in $.ajax()

, XMLHttpRequest()

or fetch()

, see Do you have an "echo page" for inspecting AJAX requests inside a code snippet?

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>
      

Run codeHide result


Also can be imported html

document

into current document

using element <link>

with attribute rel

set to "import"

, see How to add whole html file with jquery .

+1


source


The problem is you are trying to access the direct html, but it is actually a string.

So you have to render html for data access.

To do this, store the response data in any html element and step through it.

I've changed jsfiddle

so you can see.

0


source


I always get the same result: an array containing the title and main element.

What exactly is the problem?

jQuery still parses it and creates an array of element in the head and one element in the body. But why?

What are you expecting?

This is similar to the behavior of parseHtml.

Here's another example:

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

      

It returns an array with one element: div

If you look at the docs for parseHTML it says:

Parses a string into an array of DOM nodes.

So it looks like it does what it should.

I'm only interested in the contents of the body.

The body content main

, which you noted is the second item.

What do you want to do about it?

You can wrap it in a jQuery object by passing it to the jQuery constructor.

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())

      

0


source







All Articles