Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parsing of html string using jquery

Tags:

jquery

I am trying to parse this html through jQuery to get data1, data2, data3. While I do get data2 and data3 I am unable to get data3 with my approach. I am fairly new to jQuery so please pardon my ignorance.

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

Here is how I am calling this in my 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

Only alert($(datahtml).find(".class0").text()); is not working the rest are working as expected. I am wondering it may be because class0 has multiple tag inside it or what?? How to get data1 in such scenario?

like image 902
lazyguy Avatar asked Oct 09 '12 21:10

lazyguy


People also ask

How do you parse text in HTML?

If you just want to parse HTML and your HTML is intended for the body of your document, you could do the following : (1) var div=document. createElement("DIV"); (2) div. innerHTML = markup; (3) result = div. childNodes; --- This gives you a collection of childnodes and should work not just in IE8 but even in IE6-7.

What is parseHTML?

parseHTML uses native methods to convert the string to a set of DOM nodes, which can then be inserted into the document. These methods do render all trailing or leading text (even if that's just whitespace).

What is $() in jQuery?

$() = window. jQuery() $()/jQuery() is a selector function that selects DOM elements. Most of the time you will need to start with $() function. It is advisable to use jQuery after DOM is loaded fully.

What is .html in jQuery?

The html() Method in jQuery is used to set or return the innerHTML content of the selected element. Syntax: It returns the content of first matched element. $(selector).html() It sets the content of matched element.


3 Answers

None of the current answers addressed the real issue, so I'll give it a go.

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) is a jQuery object containing only the div.class0 element, thus when you call .find on it, you're actually looking for descendants of div.class0 instead of the whole HTML document that you'd expect.

A quick solution is to wrap the parsed data in an element so the .find will work as intended:

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

Fiddle


The reason for this isn't very simple, but I assume that as jQuery does "parsing" of more complex html strings by simply dropping your HTML string into a separate created-on-the-fly DOM fragment and then retrieves the parsed elements, this operation would most likely make the DOM parser ignore the html and body tags as they would be illegal in this case.

Here is a very small test suite which demonstrates that this behavior is consistent through jQuery 1.8.2 all the way down to 1.6.4.

Edit: quoting this post:

Problem is that jQuery creates a DIV and sets innerHTML and then takes DIV children, but since BODY and HEAD elements are not valid DIV childs, then those are not created by browser.

Makes me more confident that my theory is correct. I'll share it here, hopefully it makes some sense for you. Have the jQuery 1.8.2's uncompressed source side by side with this. The # indicates line numbers.

All document fragments made through jQuery.buildFragment (defined @#6122) will go through jQuery.clean (#6151) (even if it is a cached fragment, it already went through the jQuery.clean when it was created), and as the quoted text above implies, jQuery.clean (defined @#6275) creates a fresh div inside the safe fragment to serve as container for the parsed data - div element created at #6301-6303, childNodes retrieved at #6344, div removed at #6347 for cleaning up (plus #6359-6361 as bug fix), childNodes merged into the return array at #6351-6355 and returned at #6406.

Therefore, all methods that invoke jQuery.buildFragment, which include jQuery.parseHTML and jQuery.fn.domManip - among those are .append(), .after(), .before() which invoke the domManip jQuery object method, and the $(html) which is handled at jQuery.fn.init (defined @#97, handling of complex [more than a single tag] html strings @#125, invokes jQuery.parseHTML @#131).

It makes sense that virtually all jQuery HTML strings parsing (besides single tag html strings) is done using a div element as container, and html/body tags are not valid descendants of a div element so they are stripped out.


Addendum: Newer versions of jQuery (1.9+) have refactored the HTML parsing logic (for instance, the internal jQuery.clean method no longer exists), but the overall parsing logic remains the same.

like image 119
Fabrício Matté Avatar answered Oct 05 '22 21:10

Fabrício Matté


Its behaviour is weird as it igonores the html and body tag and start from first div with class = "class0". The html is parsed as DOM elements but not added to DOM. For elements added to DOM the selector does not ignore body tag and apply selectors on document. You need to add the html to DOM as given below.

Live Demo

$('#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 

If we wrap your html within some html element to make it starting point instead of your first div with class="class0" then your selector will work as expected.

Live Demo

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 

What jQuery docs say about the jQuery parsing function jQuery() i.e. $()

When passing in complex HTML, some browsers may not generate a DOM that exactly replicates the HTML source provided. As mentioned, jQuery uses the browser"s .innerHTML property to parse the passed HTML and insert it into the current document. During this process, some browsers filter out certain elements such as <html>, <title>, or <head> elements. As a result, the elements inserted may not be representative of the original string passed.

like image 22
Adil Avatar answered Oct 05 '22 21:10

Adil


I think I have an even better way:

let's say you've got your 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>'

Here's the thing you've been hoping to do:

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

dataHtml now works exactly like the ordinary jquery objects you're familiar with!!

The wonderful thing about this solution is that it will not strip body, head, or script tags!

like image 22
Gershom Maes Avatar answered Oct 05 '22 23:10

Gershom Maes