2

I would like to convert the following string to DOM structure.

text node <div>div node</div>text node<p>paraph node</p> text node

One approach is,

mydiv = document.createElement('div');
mydiv.innerHTML = 'text node <div>div node</div>text node<p>paraph node</p> text node';

In this approach, the DOM structure is wrapped by another div, which is not i wanted.

After do searching and reading, I found document.createDocumentFragment() is the best way, because when append a fragment to node, it just append fragment's childNodes, not fragment itself

unfortunately, innerHTML method is not available in a fragment.

what should i do? thanks

wukong
  • 2,430
  • 2
  • 26
  • 33

4 Answers4

8

Try this:

var frag = document.createDocumentFragment();
var mydiv = document.createElement('div');
mydiv.innerHTML = 'text node <div>div node</div>text node<p>paraph node</p> text node';


while( mydiv.firstChild ) {
    frag.appendChild( mydiv.firstChild );
}

document.body.appendChild( frag );
Esailija
  • 138,174
  • 23
  • 272
  • 326
5

I tried all the solutions on this page and none were working sufficiently for my case (a more complex HTML string). I ended using this very simple approach with insertAdjacentHTML that I found here: https://stackoverflow.com/a/7327125/388412

div.insertAdjacentHTML( 'beforeend', str );
Community
  • 1
  • 1
auco
  • 9,329
  • 4
  • 47
  • 54
1

Esailija's answer will work cross-browser and in most situations and is what I'd favour in general, for now. Another option designed for precisely this task is the createContextualFragment() method of Range (see also DOM Parsing and Serialization spec). The idea is that it will create a DocumentFragment for the specified HTML string that is relevant to the location in the document represented by the start of a Range. Unfortunately, this method is not supported in IE <= 9, although IE 10 will support it.

Here's an example. Let's assume you're planning to insert the fragment at the end of the body:

var html = "text node <div>div node</div>text node<p>paraph node</p> text node";
var range = document.createRange();
range.selectNodeContents(document.body);
range.collapse(false);
var frag = range.createContextualFragment(html);

document.body.appendChild( frag );
Tim Down
  • 318,141
  • 75
  • 454
  • 536
  • `createContextualFragment` is the best way to convert string to DOM nodes. `mydiv.firstChild` is tricky, you have to loop all the nodes in `mydiv` which lose performance.Thanks for your great answer – wukong Apr 23 '12 at 06:46
  • @wukong no, you will only have to loop the immediate children of mydiv, not all nodes. And the performance difference is equal or negligible at best, completely irrelevant at worst because drawing the graphics on the screen is the bottleneck. – Esailija Apr 23 '12 at 14:20
0

Okay, i just combine Tim's answer and Esailija's answer to one single function for convennience.

   function createDocumentFragment (inMarkup) {

        var range, fragment, dummy, elem;

        if (document.createRange && (range = document.createRange())
                && range.selectNodeContents
                && range.createContextualFragment) {

            range.collapse(false);

            range.selectNodeContents(document.body);

            fragment = range.createContextualFragment(inMarkup);

        } else {

            dummy = document.createElement('div');

            fragment = document.createDocumentFragment();

            dummy.innerHTML = inMarkup;

            while((elem = dummy.firstChild)) {

                fragment.appendChild(elem);

            }

        }

        return fragment;

    }
wukong
  • 2,430
  • 2
  • 26
  • 33
  • I'd recommend just using a battle tested library such as jQuery for this. – Esailija Apr 23 '12 at 14:23
  • @Esailija: I wouldn't. jQuery does nothing with `createContextualFragment()` and your answer does the job fine. – Tim Down Apr 23 '12 at 14:48
  • @TimDown Not sure what you mean with "jQuery does nothing with createContextualFragment()" as jQuery doesn't use it all. By battle tested I meant that this code(and mine) will have tons of bugs that jQuery's buildFragment doesn't. – Esailija Apr 23 '12 at 14:52
  • @Esailija: Yes, that was what I meant about `createContextualFragment()`. Re. jQuery's `buildFragment()`, you may be right. I haven't looked into it deeply and there seems to be no documentation on it whatsoever on the jQuery site. – Tim Down Apr 23 '12 at 15:24
  • @TimDown It's not documented because its meant for internal use only. There is no need for explicit use of fragments anyway if you are using jQuery/remotely decent dom library. But if you read the source for `$.buildFragment` and `$.clean`, you can easily see that we are reinventing square wheels here. – Esailija Apr 23 '12 at 15:36