Allegro.cc - Online Community

Allegro.cc Forums » Off-Topic Ordeals » "AJAX" - That's right, I said it! (XML DOM) ***Please Help***

Credits go to ImLeftFooted and Matthew Leverton for helping out!
This thread is locked; no one can reply to it. rss feed Print
"AJAX" - That's right, I said it! (XML DOM) ***Please Help***
bamccaig
Member #7,536
July 2006
avatar

(Some names have been changed to protect the innocent... ;D)

Today at work I was asked to create a javascript "class" to manage some basic AJAX requests. By the end of the day I have one working synchronously, but not asynchronously.

My search of the forums revealed suggestions for using JSON (it looks worse than the XML tree) and parsing of XMLHttpRequest.responseText. However, I've been asked to use XML and my class is already designed to parse the XML prettily so those aren't options (and I think I'd prefer to get the XML working anyway).

If you wish to skip the code below and just answer my question I'm trying to create an XMLDOM object from the XMLHttpRequest.responseXML property.

As is, the class is designed similar to a recordset to make it feel like you were simply accessing a database table. For example:

1 function body_onLoadHandler()
2 {
3 var objMyAJAXClass = null;
4 var strInnerHTML = "";
5 var strFilename = "sample.xml";
6 var blnAsync = false;
7 var strRootElement = "Sample";
8 
9 if(!(objMyAJAXClass = new MyAJAXClass(strRootElement))
10 return null;
11 
12 with(objMyAJAXClass)
13 {
14 Request(strFilename, blnAsync);
15 
16 strInnerHTML += "\tRecordCount: " + RecordCount() + "<br />\n";
17 strInnerHTML += "<br />\n";
18 
19 if(!EOF())
20 {
21 strInnerHTML += "\t<table border='1'>\n";
22 strInnerHTML += "\t\t<tr>\n";
23 strInnerHTML += "\t\t\t<td>FieldName1</td>\n";
24 strInnerHTML += "\t\t\t<td>FieldName2</td>\n
25 strInnerHTML += "\t\t\t<td>FieldName3</td>\n
26 strInnerHTML += "\t\t</tr>\n";
27 
28 do
29 {
30 strInnerHTML += "\t\t<tr>\n";
31 strInnerHTML += "\t\t\t<td>" + Item("FieldName1") + "</td>\n";
32 strInnerHTML += "\t\t\t<td>" + Item("FieldName2") + "</td>\n";
33 strInnerHTML += "\t\t\t<td> + Item("FieldName3") + "</td>\n";
34 strInnerHTML += "\t\t</tr>\n";
35 }while(!EOF());
36
37 strInnerHTML = "\t</table>\n";
38 }
39 }
40
41 document.body.innerHTML = strInnerHTML;
42 }

The only methods required to implement the class in this example are Request(), RecordCount(), EOF(), and Item().

When the form loads the above code would draw something like the following:

    RecordCount: 3

    +------------+------------+------------+
    | FieldName1 | FieldName2 | FieldName3 |
    +------------+------------+------------+
    | 1          | foo        | 2352       |
    +------------+------------+------------+
    | 2          | bar        | 34243      |
    +------------+------------+------------+
    | 3          | foo2       | 12         |
    +------------+------------+------------+

Using the following XML:

    <?xml version="1.0" encoding="iso-8859-1"?>
    <Request>
        <Sample>
            <Records>
                
                    1
                    foo
                    2352
                
                
                    2
                    bar
                    34243
                
                
                    3
                    foo2
                    12
                
            </Records>
        </Sample>
        <Sample2>
            <Records>
                
                    The strRootElement is used to select a set of
                                data from potentially more than one "table" of
                                information...
                    
                    foo
                
                
                    bar
                    foo2
                
            </Records>
        </Sample2>
    </Request>

Anybody still reading, thank you. ;D That Request() method of the MyAJAXClass class is currently loading an XML file into an XMLDOM object. As far as I can tell, there is no way to set a callback function for when it finishes loading (asynchronously) so I enforce a synchronous load. The plan, however, is to asynchronously load the xml file and process it when it finishes.

Does anybody know how to define an onLoad callback for the XMLDOM object or preferably how to create an XMLDOM object from the XMLHttpRequest.responseXML?

?????????

(Some names have been changed to protect the innocent... ;D)

kazzmir
Member #1,786
December 2001
avatar

I'm mildly impressed you couldn't figure it out by yourself but all you need to do for asynchronous processing is ajax_thing.onreadystatechange = function{ ... }

Here some code I used:

1function convertText(){
2 var http_request = false;
3 
4 if (window.XMLHttpRequest) { // Mozilla, Safari,...
5 http_request = new XMLHttpRequest();
6 if (http_request.overrideMimeType) {
7 http_request.overrideMimeType('text/xml');
8 // See note below about this line
9 }
10 } else if (window.ActiveXObject) { // IE
11 try {
12 http_request = new ActiveXObject("Msxml2.XMLHTTP");
13 } catch (e) {
14 try {
15 http_request = new ActiveXObject("Microsoft.XMLHTTP");
16 } catch (e) {}
17 }
18 }
19 
20 if (!http_request) {
21 alert('Giving up Cannot create an XMLHTTP instance');
22 return false;
23 }
24 
25 http_request.onreadystatechange = function() {
26 if (http_request.readyState == 4) {
27 if (http_request.status == 200) {
28 rot13 = document.getElementById( 'rot13' );
29 rot13.value = http_request.responseText;
30 } else {
31 alert('There was a problem with the request.');
32 }
33 }
34 };

Matthew Leverton
Supreme Loser
January 1999
avatar

Let me just say that using XML is crazy dumb. Whoever told you to do that better have an incredibly good reason for doing so. If not, disobey and use JSON.

And regarding kazzmir's code, I've found it's best to check for the ActiveX control first. IE 7's native control is apparently buggy and broken.

Jonatan Hedborg
Member #4,886
July 2004
avatar

Haven't you heard? XML is like a faucet. A faucet that when opened spews out endless amounts of money. It also gets you laid. A lot.

bamccaig
Member #7,536
July 2006
avatar

kazzmir said:

I'm mildly impressed you couldn't figure it out by yourself but all you need to do for asynchronous processing is ajax_thing.onreadystatechange = function{ ... }

I'm mildly impressed myself. >:( The problem isn't with using asynchronous processing. The problem is creating an XML DOM (XMLDOM object) from the XMLHttpRequest object's responseXML property.

Alternatively, if you know how to use the XMLDOM object to load() an XML file asynchronously (as far as I can tell there is no onreadystatechange event for XMLDOM) as you do for XMLHttpRequest that would probably solve my problem as well.

Matthew Leverton said:

Let me just say that using XML is crazy dumb. Whoever told you to do that better have an incredibly good reason for doing so. If not, disobey and use JSON.

I'm not really a huge fan of XML, but JSON looks pretty ugly to me. Disobeying isn't really an option if I want to keep my job, though I could recommend a change. I don't really see the point. I appreciate the advice, but what I really want/need is to know how to create the XMLDOM object from the XMLHttpRequest, since the processing of XML is already taken care of.

As I mentioned, implementing my class the only method calls I need to access data are the constructor to create the object, Request() to make the request, and from there EOF() and Item() to access the fields.

Matthew Leverton said:

And regarding kazzmir's code, I've found it's best to check for the ActiveX control first. IE 7's native control is apparently buggy and broken.

Noted. ;D

ImLeftFooted
Member #3,935
October 2003
avatar

XML is the way to go. Much better then JSON. Answering specific questions first...

Quote:

Does anybody know how to define an onLoad callback

Don't. Its ugly, its hacky, encourages globals and there is no good reason for it. If you would like to background the function that is calling xmlHttpRequest::send so it executes in its own thread, that makes sense. You can use SetTimeout with a timeout of 0 to achieve this.

Quote:

how to create an XMLDOM object from the XMLHttpRequest.responseXML

It already is.

Quote:

When the form loads the above code would draw something like the following:

RecordCount: 3

+------------+------------+------------+
| FieldName1 | FieldName2 | FieldName3 |
+------------+------------+------------+
| 1 | foo | 2352 |
+------------+------------+------------+
| 2 | bar | 34243 |
+------------+------------+------------+
| 3 | foo2 | 12 |
+------------+------------+------------+

Using the following XML:

<?xml version="1.0" encoding="iso-8859-1"?>
<Request>
<Sample>
<Records>
1 foo 2352
2 bar 34243
3 foo2 12
</Records>
</Sample>
</Request>

Ok lets look at how you might do this...

Heres how to parse the xml itself:

var xml = BlahXmlObject.responseXML;
var records = xml.getElementsByTagName("Record");

for(var i = 0; i < records.length; i++) {
  
  for(var j = 0; j < records<i>.childNodes.length; j++) {
    
    alert("Field name is " + records<i>.tagName);
    alert("Value for this field is " + records<i>.childNodes[j]);
  }
}

You could also use xpath which could theoritcally cleaner, but makes you less backwards-compatible.

As for how to display that table (construct the HTML with values etc), I have the (I believe) perfect method. Unfortunetly I'm not in the mood to explain it right now, so maybe later.

Matthew Leverton
Supreme Loser
January 1999
avatar

Quote:

XML is the way to go. Much better then JSON. Answering specific questions first...

Uhm, no. XML is only better if you need to use XPath to access large amounts of arbitrary data. And even then, browsers' (IE) native XPath support is not good.

If you are dealing with known data (either small datasets or for iteration), JSON is way better.

eval(json);
alert(json.foo);

The only other reason to use XML is if you actually already have well-formed XML documents stored on the server.

ImLeftFooted
Member #3,935
October 2003
avatar

Ah, so thats how json works.. cool.

bamccaig
Member #7,536
July 2006
avatar

Dustin Dettmer said:

var records = xml.getElementsByTagName("Record");

That sounds right and I hope it is, but I'm having trouble utilizing it right now. Can you see what might be the problem with this:

1 if(!(objXMLDocument = gobjXMLHttpRequest.responseXML))
2 {
3 alert("Error! Failed to load city data!");
4 return;
5 }
6 
7 with(objXMLDocument)
8 {
9 for(var i=0; i<objXMLDocument.getElementsByTagName("City").length; i++)
10 {
11 objOption = document.createElement("option");
12 with(objXMLDocument.getElementsByTagName("City")<i>)
13 {
14 objOption.value = getElementsByTagName("CityID")[0].text;
15 objOption.text = getElementsByTagName("Name")[0].text;
16 }
17 cmbCity.add(objOption);
18 }
19 
20 btnLoadCities.disabled = true;
21 btnLoadCities.style.display = "none";
22 cmbCity.disabled = false;
23 cmbCity.style.display = "inline";
24 }

It's very possible there is a bug (or many) in my code somewhere, but this is basically blowing up. Firebug detects an uncaught exception (which is messy) and IE7's <select> appears to somewhat "break".

Firebug said:

uncaught exception: [Exception... "Component returned failure code: 0x80070057 (NS_ERROR_ILLEGAL_VALUE) [nsIXMLHttpRequest.open]" nsresult: "0x80070057 (NS_ERROR_ILLEGAL_VALUE)" location: "JS frame :: javascript: eval(__firebugTemp__); :: anonymous :: line 1" data: no]

Line 0

The exception caught by firebug isn't necessarily from the block of code that I showed you... And I'm not working with the code I wrote at work today; I'm using old code I hacked together experimenting with AJAX an unknown number of months ago...

** EDIT **

Dustin Dettmer said:

Ah, so thats how json works.. cool.

Actually, after looking up JSON syntax on Wikipedia it actually looks much nicer than the other threads made it seem. I didn't know you could represent objects with JSON... :) And for the record, it looks a lot nicer when carried over multiple lines.

I still want help parsing the XML from XMLHttpRequest.responseXML, however, I'll also play with JSON and consider recommending it to the company.

:)

ImLeftFooted
Member #3,935
October 2003
avatar

The error you pasted I believe I've seen before. I think its caused by problems using the XmlHttpRequest object. Maybe its time to rewrite that 'experimental AJAX from an unknown number of months ago'.

Quote:

Can you see what might be the problem with this:

Uh well that depends on what you're doing. Technically speaking that could be 100% legitmate javascript. I have a hard time reading it because of all your redundant calls to getElementsByTagName. You should really be caching the results, and then maybe even displaying error messages when your indecies are invalid instead of assuming the tags are all there.

All that aside, I discovered the perfect way to insert data into a webpage about 2 days ago (couldn't fall asleep cause I was figuring it out). If I'm more in the mood later I'll explain it.

edit
On second thought I don't think I'm going to explain it. Whats the point of expressing brilliant ideas to be digested and spat in your face by people who can't understand what you're actually saying.

I deal with that enough at work.

bamccaig
Member #7,536
July 2006
avatar

kazzmir
Member #1,786
December 2001
avatar

earlier ddustin said:

I have the (I believe) perfect method. Unfortunetly I'm not in the mood to explain it right now, so maybe later.

then he said:

All that aside, I discovered the perfect way to insert data into a webpage about 2 days ago (couldn't fall asleep cause I was figuring it out). If I'm more in the mood later I'll explain it.

edit
On second thought I don't think I'm going to explain it. Whats the point of expressing brilliant ideas to be digested and spat in your face by people who can't understand what you're actually saying.

Arrogance: its whats for dinner.

ImLeftFooted
Member #3,935
October 2003
avatar

Its slowly developed over the years. I stopped caring to stop it.

Matthew Leverton
Supreme Loser
January 1999
avatar

You may also want to check out http://json.org/, as it has libraries for various languages to convert the native objects to a JSON string.

bamccaig
Member #7,536
July 2006
avatar

Matthew Leverton said:

You may also want to check out http://json.org/, as it has libraries for various languages to convert the native objects to a JSON string.

Much appreciated. ;D There's an ASP/VBScript class which might make it a little bit easier to work with. ;D My only fear is licensing issues and whether or not my company would want to use it, though the "license" does say to use it freely so long as the credits are maintained. :-/

** EDIT **

I'm trying to parse the XML and I'm getting an error that gobjXMLDOM.getElementsByTagName("SampleElement")[0] doesn't support the getElementsByTagName method. What am I doing wrong? :-/

I checked with IE's script debugger and there is an object returned by gobjXMLDOM.getElementsByTagName("SampleElement")[0], but it doesn't seem to be the first "SampleElement" element, rather, it seems to be the <?xml version="1.0" encoding="iso-8859-1"?> element... :-/

1 gobjXMLHttpRequest.onStateChangedCallback = function()
2 {
3 if(gobjXMLHttpRequest.readyState == 3 && gobjXMLHttpRequest.status == 200)
4 {
5 // Process it.
6 gobjXMLDOM = gobjXMLHttpRequest.responseXML;
7 
8 if(mobjXMLDOM != null)
9 {
10 with(gobjXMLDOM.getElementsByTagName("SampleElement")[0].getElementsByTagName("Records")[0])
11 {
12 gintRecordCount = (getElementsByTagName("Record").length|0);
13 if(gintRecordCount > 0)
14 gintPosition = 0;
15 }
16 }
17 }
18 }

** EDIT (10 minutes after the first) **

However, when I tried gobjXMLDOM.documentElement.getElementsByTagName("SampleElement")[0] it seemed to work. :)

Samuel Henderson
Member #3,757
August 2003
avatar

err. I was asked to bump this thread, sooo... bump?

Edit:

Oh snap. That's the last time I bump for anyone.

=================================================
Paul whoknows: Why is this thread still open?
Onewing: Because it is a pthread: a thread for me to pee on.

bamccaig
Member #7,536
July 2006
avatar

Samuel Henderson said:

err. I was asked to bump this thread, sooo... bump?

Yes, and as fate would have it within minutes of the bump I figured out the problem... :-/ Thanks though.

Go to: