logo Pascarello.com Integrating the Client with the Server
Ajax XML Document Error

When Dave Crane and I were dealing with the testers for Ajax in Action a common problem was that people may not have there server set up correctly to serve XML documents back. Another problem that can cause an error is a person forgetting to set the content type of the dynamically created XML file on the server correctly.  Well there is a way to avoid all of these problems by using a little DOM method that takes a given string with XML syntax and converts it over to a properly defined XML document. Of course IE and Safari do not support it so a little "Hack" needs to be involved. First lets test the code to see what the error is exactly. The form below allows us to manipulate how our "business" logic works on this application. The first choice we can set is what is returned from the server, the correct DDT is xml, but if a person forgets to set it, the default is html. The next choice we have is to use the DOM method on the clientside to convert the responseText string returned from the server to the XML document. By clicking the button you send the request to the server to get the node text in the XMl document.

Declare Document Type on server:

text/xml
text/html

Use Dom XML Parser:

Use String to XML Conversion


Now with this test you should see that the text/xml result does not depend on the state of the checkbox. However the text/html will error out if the checkbox is not checked. This shows you by converting the document to the XML format, we will not have to worry about the document type declaration. (You should set it!!, but lets ignore that fact for now!) So lets see the code above in some detail, which allows us to read the XML document with DOM with the wrong DDT being sent back from the server.

First thing first is we need to include one of the Ajax loaders code from Ajax In Action.
<script type="text/javascript" src="net.js"></script>

With that external library added to the page we can make the request. In this case we are checking to see the state of our radio button. If the xml is checked, we send that value to the server as a form parameter being posted to the server.

function makeRequest(){
  var strMeth = (document.Form1.r1[0].checked)?"XML":"HTML";
  var loader1 = new net.ContentLoader("TestHTMLXMLfromServer.aspx",finishRequest,null,"POST","method=" + strMeth);
}

The server code in return is rather simple. We check the form parameter, set the right Content Type and add an xml document to read on the client.

Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
    If Request.Form.Get("method").ToString.ToLower = "xml" Then
        Response.ContentType = "text/xml"
    Else
        Response.ContentType = "text/html"
    End If
    Response.Write("")
    Response.Write("TEST TEST")
End Sub

Now for the finishRequest function that our ContentLoader is set to call. We need to grab the responseText nad responseXML returned frm the server. We need to do a little try catch to catch the ugly error that we know what is going to happen with the html option. The alertError function will be explained in a little bit. We check to see if our checkbox is checked. If it is we see if we do not have a valid XML document. !xmlDocument is for Gecko detecttion and childNodes.length is for IE. We then use the DOMParser to convert the responseText into an XML document. Now the DOMParser is not supported by IE or Safari so we need to create functionality from it.

function finishRequest(){
    var strDocument = this.req.responseText; 
    var xmlDocument = this.req.responseXML;
    try{ 
        if(document.Form1.cb1.checked){ 
            if(!xmlDocument || xmlDocument.childNodes.length==0){ 
               xmlDocument = (new DOMParser()).parseFromString(strDocument, "text/xml");
            } 
        } 
        var strNode = xmlDocument.getElementsByTagName("test")[0].firstChild.nodeValue; 
        alert("responseXML nodeText Result:\n\n" + strNode); 
    } 
    catch(e){ 
        alertError(e,"Error: Not a valid XML document"); 
    }
}

Now I got the IE funcitonality for t function from http://erik.eae.net/archives/2005/07/03/20.19.18/ when I was looking for a solution to the problem. The code for the DOMParser is below and returns an XML document back from the string.

if (typeof DOMParser == "undefined") { DOMParser = function (){}
  DOMParser.prototype.parseFromString = function (str, contentType) {
    if (typeof ActiveXObject != "undefined") {
      var d = new ActiveXObject("MSXML.DomDocument");
      d.loadXML(str); 
      return d;
    }
    else if (typeof XMLHttpRequest != "undefined") {
      var req = new XMLHttpRequest;
      req.open("GET", "data:" + (contentType || "application/xml") + 
                                 ";charset=utf-8," + encodeURIComponent(str), false);
      if (req.overrideMimeType) {
        req.overrideMimeType(contentType);
      }
      req.send(null);
      return req.responseXML;
    }
  }
}

The only part left to explain is the alertError function which loops through the error object and returns the message to be displayed.

function alertError(objError,strMessage){
  var strError = strMessage + "\n\n";
  for (var i in objError)strError += i + ': ' + objError[i] + '\n';
  alert(strError);
}

And that is the basic idea behind taking an XML document that has an invalid DDT and converting it over to the correct format. Hopefully this will help solve some of the issues you are having with your Ajax application. The correct solution would be to make sure that your server and document are set up correctly, then you will not have to go through this mess! The files for this example are included in the zip file that you can save here: http://www.pascarello.com/downloads/ConvertToXMLDoc.zip

2005 Pascarello.com