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