adahas

අදහස්

Download Day

innerHTML in application/xhtml+xml

As you may already know, JavaScript ‘innerHTML’ attribute fails when the document is served with the content-type as application/xhtml+xml. But when the same page is served as text/html, the code works fine. One way to get through is use DOM Object and createRange() method of JavaScript. It works with application/xhtml+xml, but fails in text/html.

The requirement of code that work with both content-types arise when a page is served usually in application/xhtml+xml, and sometimes in text/html for browsers that do not support the previous; for example, this site.

So, I tried to build a work-around to write code that will result the same output in both the application/xhtml+xml and text/html. The result was this,


<script type="text/javascript">
<!--//--><![CDATA[//><!--
 
function doInnerHTML(elementId, stringHTML) {
 
   try {
      var elem = document.getElementById(elementId);
      var children = elem.childNodes;
 
      for (var i = 0; i < children.length; i++) {
         elem.removeChild(children[i]);
      }
 
      var nodes = new DOMParser().parseFromString(
         stringHTML, 'text/xml');
      var range = document.createRange();
      range.selectNodeContents(
         document.getElementById(elementId));
      range.deleteContents();
 
      for (var i = 0; i < nodes.childNodes.length; i++) {
         document.getElementById(elementId).appendChild(
            nodes.childNodes[i]);
      }
      return true;
      } catch (e) {
         try {
            document.getElementById(elementId).innerHTML =
               stringHTML;
            return true;
         }
      catch(ee) {
         return false;
      }
   }
}
 
doInnerHTML('replace', '<div><p>Good morning,</p>' +
   '<p>Have a <strong>nice</strong> day.</p></div>');
 
//--><!]]>
</script>

This works in both the content-types, and if it fails, the method returns false, so that it’s known whether assignment to innerHTML was done or not.

One known problem of this code is that when doInnerHTML() method is used, the second parameter (stringHTML) should be XML compliant text, meaning that any tags opened should be closed and the while string should be contained in one root tag/element.

For example, this code is wrong,

doInnerHTML('replace', '<p>Good morning,</p>' +
   '<p>Have a <strong>nice</strong> day.</p>');

because the second parameter is not contained in one root tag/element. The correct code to get the same thing done is,

doInnerHTML('replace', '<div><p>Good morning,</p>' +
   '<p>Have a <strong>nice</strong> day.</p></div>');

Thought it’ll be useful for you as well, so thought I’ll share it. Please point out if there’s any problems in my code, or any suggestions on improving the code.

4 responses to 'innerHTML in application/xhtml+xml'

  1. Nobody says:

    instead of passing a string inside a div, have it write it to the string when you call the function and the current mimetype is application/xhtml+xml, like so:


    function doInnerHTML(elementId, unprocessed_stringHTML) {
    try {
    var stringHTML = “” + unprocessed_stringHTML + “”; //

  2. Nobody says:

    It messed up my code when removing tags, well, I’m sure you get the idea.

  3. Nobody says:

    It didn’t work with images in Mozilla, so I had to hack it a little and here’s what I got:
    http://www.chudosok.info/21/innerhtml.js

  4. Nobody says:

    Replace:
    var nodes = new DOMParser().parseFromString(stringHTML, ‘text/xml’);
    With:
    var nodes = new DOMParser().parseFromString(stringHTML, ‘text/xml’).documentElement;

    and

    Replace:
    document.getElementById(elementId).appendChild(nodes.childNodes[i]);
    With:
    document.getElementById(elementId).appendChild(document.importNode(nodes.childNodes[i], true));

    It will work a lot better, especially with Mozilla.

leave a reply

Please feel free to leave a comment about this post.

(required)
(will not be published ,but required)