Search code examples
xmlajaxdomxmlhttprequestgetelementsbytagname

turning Ajax ResponseXML into HTML


I'm doing an Ajax request in which I have the server returning well-formed HTML, specifically table row ("tr") elements. I had hoped to use the DOM to insert these rows into a table by reading from the "responseXML" member on the request object (XMLHttpRequest). Basically, I have

var myTable = document.getElementById("myTable");
var tableRows = responseXML.getElementsByTagName("tr");
for (var i = 0; i < tableRows.length; i++) {
  myTable.appendChild(tableRows[i]);
}

Lots of things go right here. The "responseXML" contains the correct data, and the call to "getElementsByTagName" also works correctly. Sadly, it breaks down when I try to add a row by calling appendChild (I get a vague javascript error). I think this is because although each item in the "tableRows" array is a correct XML element, the browser can't automatically interpret it as an HTML element. I've noticed that if I make a new using document.createElement("tr") and examine it during run-time, it looks different in memory from the items in the "tableRows" array. Also, I am able insert that new (the one made with "createElement") into the table without an error.

Is there a good way to do what I'm trying to do here? I was hoping that I could make the browser interpret the elements correctly by returning the content as XML and using responseXML/getElementsByTagName. That way, I could avoid using responseText for what is really HTML, and I could also avoid using "innerHTML" because it's not a standard. Most examples online use innerHTML, however. Is that really the best way?


Solution

  • If it is well-formed HTML, you can try using document.importNode() like so:

    //myXHTML is your HTML/XHTML (if it is well-formed, you should be ok).
    //myObject is the parent node. This is the node you want to insert your HTML into
    function insertXHTML(myXHTML, myObject) {
       var parser = new DOMParser();
    
       //Doing this to make sure that there is just one root node.
       //You can change the namespace, or not use it at all.
       var xmlToParse = "<div xmlns = \"http://www.w3.org/1999/xhtml\">" + myXHTML + "</div>";
       var XMLdoc = parser.parseFromString(xmlToParse, "application/xhtml+xml");
    
       var root = XMLdoc.documentElement;
    
       for(i = 0; i < root.childNodes.length; i++) {
           myObject.appendChild(document.importNode(root.childNodes[i], true));
       }
    }
    

    This is code I wrote some time ago (to get around the use of innerHTML); it should still work. The only thing I am worried about is DOMParser(); not sure how cross-browser it is.

    EDIT

    The problem with your approach (doing things with just pure JS) is that you'll run into cross-browser issues :(. For importNode, take a look at this cross-browser implementation. Your other option is to use something like jQuery. It normalizes a lot of the cross-browser differences.