15

I'm looking for the best way to handle parsing HTML or XHTML (XML serialized) markup and inserting it into the DOM of a webpage which could either be text/html or application/xhtml+xml. Not looking to use libraries like jQuery and really only care about compatibility with the latest version of Chrome.

I see two possible solutions.

  • Template & innerHTML:

    let temp = document.createElement('template');
    temp.innerHTML = markuptext;
    document.body.appendChild(temp.content);
    
  • DOMParser:

    let parser = new DOMParser();
    let doc = parser.parseFromString('<div xmlns="http://www.w3.org/1999/xhtml">' + markuptext + '</div>', 'application/xhtml+xml');
    let frag = document.createDocumentFragment(), childNode;
    while (childNode = doc.documentElement.firstChild) {
        frag.appendChild(childNode);
    }
    document.body.appendChild(frag);
    

I was hoping someone could point out the advantages/disadvantages of these two approaches.

With Template & innerHTML I am assuming Chrome will choose to parse as HTML/XML depending on the content type of the page and there is probably no way to change that. It seems Template & innerHTML allows fragments like <tr><td></td></tr> outside of a <tbody> regardless of if it is parsing as HTML or XML. DOMParser allows this too but only if it is parsing as XML.

Chris_F
  • 4,991
  • 5
  • 33
  • 63
  • 2
    The DHTML property **innerHTML** which is a full-fledged HTML Parser, is a highly optimized and equally reliable in converting an HTML stream sequence into a DOM tree, instantly (on all browser engines). And as a bonus, it may also be able to make error corrections on an incomplete stream. – Bekim Bacaj May 16 '16 at 08:59
  • 1
    @BekimBacaj `"it may also be able to make error corrections on an incomplete stream"` I would consider that to be a negative if true. – Chris_F May 16 '16 at 09:09
  • 1
    I consider it a bonus - because the only reason, any sort of data-structuring language exists - is the actual data. That's all you are interested in, and you don't care how it's structured at all, as long as you get the info you are going after, or waiting for. Any behavior other than this is doomed to die prematurely just like xhtml did, regardless. – Bekim Bacaj May 16 '16 at 09:17
  • 3
    @BekimBacaj I completely disagree. I want my markup well formed and if it's not I want it to tell me, not silently try to guess what was actually meant. These are no excuses for errors in the markup. But i digress. – Chris_F May 16 '16 at 09:23
  • See https://stackoverflow.com/questions/37554623/can-a-new-domparser-parsefromstring-be-safer-than-createelement - `DOMParser` is safer – CertainPerformance Nov 29 '18 at 06:25
  • If you want, also to execute the scripts, maybe you want look at: http://stackoverflow.com/a/58862506/890357 – marciowb Nov 14 '19 at 19:26

3 Answers3

5

It depends what is your goal. If you want just append parsed html/xhtml 'as is' then go with .innerHTML, its easier and usually faster. Hovewer, from my experience, often, you have to do some kind of transformations, then using dom operations is best way. But you should avoid appending node by node to document.body in loop, because it is slow and inefficient, just create some 'dummy' dom element, add nodes to it in loop, than append whole object:

let div = document.createElement('div');
let childNode;
while (childNode = doc.documentElement.firstChild) {
    div.appendChild(childNode);
}
document.body.appendChild(div);

One important note, about trying to find most efficient solutions in JS. JS performance highly depend on javascript engine, and what parts of js will be optimized in the future. So you should always write some kind of performance tests ( or use prepared test suites), especially about slow 'parts' like DOM API. Good news is that engine developers tend to favor well known solutions and 'good practices' to be optimized and they usually leave 'bad parts'.

Here are some good tests on innerHTML vs DOM append: http://andrew.hedges.name/experiments/innerhtml/

Appending to DOm without creating 'dummy' div: https://coderwall.com/p/o9ws2g/why-you-should-always-append-dom-elements-using-documentfragments

And more technical explanations about .innerHTML, .appendChild, .insertAdjacentHTML" "innerHTML += ..." vs "appendChild(txtNode)"

Community
  • 1
  • 1
Jazzman
  • 181
  • 6
  • I updated my DOMParser code with the use of `DocumentFragment` to avoid multiple appends to document.body. – Chris_F May 16 '16 at 09:30
3

Maybe a mixed approach?

var dom = new DOMParser().parseFromString('<template>'+ markuptext +'</template>','text/html').head;
document.getElementById('my-div').appendChild(dom.firstElementChild.content);
swannty
  • 141
  • 5
0

On this page they advise the first solution which is to:

let tmpl = document.createElement('template');
tmpl.innerHTML = text;
shadowRoot.appendChild(tmpl.content.cloneNode(true));

https://developers.google.com/web/fundamentals/web-components/customelements

Nicolas Manzini
  • 8,379
  • 6
  • 63
  • 81