- XML Reference Guide
- Overview
- What Is XML?
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Table of Contents
- The Document Object Model
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- DOM and Java
- Informit Articles and Sample Chapters
- Books and e-Books
- Implementations
- DOM and JavaScript
- Using a Repeater
- Repeaters and XML
- Repeater Resources
- DOM and .NET
- Informit Articles and Sample Chapters
- Books and e-Books
- Documentation and Downloads
- DOM and C++
- DOM and C++ Resources
- DOM and Perl
- DOM and Perl Resources
- DOM and PHP
- DOM and PHP Resources
- DOM Level 3
- DOM Level 3 Core
- DOM Level 3 Load and Save
- DOM Level 3 XPath
- DOM Level 3 Validation
- Informit Articles and Sample Chapters
- Books and e-Books
- Documentation and Implementations
- The Simple API for XML (SAX)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- SAX and Java
- Informit Articles and Sample Chapters
- Books and e-Books
- SAX and .NET
- Informit Articles and Sample Chapters
- SAX and Perl
- SAX and Perl Resources
- SAX and PHP
- SAX and PHP Resources
- Validation
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Document Type Definitions (DTDs)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XML Schemas
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- RELAX NG
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Schematron
- Official Documentation and Implementations
- Validation in Applications
- Informit Articles and Sample Chapters
- Books and e-Books
- XSL Transformations (XSLT)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XSLT in Java
- Java in XSLT Resources
- XSLT and RSS in .NET
- XSLT and RSS in .NET Resources
- XSL-FO
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XPath
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XML Base
- Informit Articles and Sample Chapters
- Official Documentation
- XHTML
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XHTML 2.0
- Documentation
- Cascading Style Sheets
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XUL
- XUL References
- XML Events
- XML Events Resources
- XML Data Binding
- Informit Articles and Sample Chapters
- Books and e-Books
- Specifications
- Implementations
- XML and Databases
- Informit Articles and Sample Chapters
- Books and e-Books
- Online Resources
- Official Documentation
- SQL Server and FOR XML
- Informit Articles and Sample Chapters
- Books and e-Books
- Documentation and Implementations
- Service Oriented Architecture
- Web Services
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Creating a Perl Web Service Client
- SOAP::Lite
- Amazon Web Services
- Creating the Movable Type Plug-in
- Perl, Amazon, and Movable Type Resources
- Apache Axis2
- REST
- REST Resources
- SOAP
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- SOAP and Java
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- WSDL
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- UDDI
- UDDI Resources
- XML-RPC
- XML-RPC in PHP
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Ajax
- Asynchronous Javascript
- Client-side XSLT
- SAJAX and PHP
- Ajax Resources
- JSON
- Ruby on Rails
- Creating Objects
- Ruby Basics: Arrays and Other Sundry Bits
- Ruby Basics: Iterators and Persistence
- Starting on the Rails
- Rails and Databases
- Rails: Ajax and Partials
- Rails Resources
- Web Services Security
- Web Services Security Resources
- SAML
- Informit Articles and Sample Chapters
- Books and e-Books
- Specification and Implementation
- XML Digital Signatures
- XML Digital Signatures Resources
- XML Key Management Services
- Resources for XML Key Management Services
- Internationalization
- Resources
- Grid Computing
- Grid Resources
- Web Services Resource Framework
- Web Services Resource Framework Resources
- WS-Addressing
- WS-Addressing Resources
- WS-Notifications
- New Languages: XML in Use
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Google Web Toolkit
- GWT Basic Interactivity
- Google Sitemaps
- Google Sitemaps Resources
- Accessibility
- Web Accessibility
- XML Accessibility
- Accessibility Resources
- The Semantic Web
- Defining a New Ontology
- OWL: Web Ontology Language
- Semantic Web Resources
- Google Base
- Microformats
- StructuredBlogging
- Live Clipboard
- WML
- XHTML-MP
- WML Resources
- Google Web Services
- Google Web Services API
- Google Web Services Resources
- The Yahoo! Web Services Interface
- Yahoo! Web Services and PHP
- Yahoo! Web Services Resources
- eBay REST API
- WordML
- WordML Part 2: Lists
- WordML Part 3: Tables
- WordML Resources
- DocBook
- Articles
- Books and e-Books
- Official Documentation and Implementations
- XML Query
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- XForms
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Resource Description Framework (RDF)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Topic Maps
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation, Implementations, and Other Resources
- Rich Site Summary (RSS)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- Simple Sharing Extensions (SSE)
- Atom
- Podcasting
- Podcasting Resources
- Scalable Vector Graphics (SVG)
- Informit Articles and Sample Chapters
- Books and e-Books
- Official Documentation
- OPML
- OPML Resources
- Summary
- Projects
- JavaScript TimeTracker: JSON and PHP
- The Javascript Timetracker
- Refactoring to Javascript Objects
- Creating the Yahoo! Widget
- Web Mashup
- Google Maps
- Indeed Mashup
- Mashup Part 3: Putting It All Together
- Additional Resources
- Frequently Asked Questions About XML
- What's XML, and why should I use it?
- What's a well-formed document?
- What's the difference between XML and HTML?
- What's the difference between HTML and XHTML?
- Can I use XML in a browser?
- Should I use elements or attributes for my document?
- What's a namespace?
- Where can I get an XML parser?
- What's the difference between a well-formed document and a valid document?
- What's a validating parser?
- Should I use DOM or SAX for my application?
- How can I stop a SAX parser before it has parsed the entire document?
- 2005 Predictions
- 2006 Predictions
- Nick's Book Picks
The most natural place to start a discussion of Asynchronous Javascript and XML is probably asynchronous Javascript, so let's get to it. Our overall goal is an RSS feed reader something like figure 1. We have a list of main categories, their subcategories in the middle, and the list of feeds at the bottom. Once we finally choose a feed, it appears on the right-hand side of the window.
The overall process works as follows:
- The user clicks a category or feed name.
- The browser makes a request to the appropriate URL.
- The browser receives the response.
- The browser adds the content of the response to the page.
There are more complicated ways to do this, of course. For example, in the next section, we'll look at using XSLT to transform the XML content before we add it to the page. In this case, however, we'll retreive our HTML and display it directly. We'll start with the basic HTML page:
<html> <head><title>test</title> <style type="text/css"> span {font-weight: bold; color: blue; text-decoration: underline} #feed {font-size: smaller} </style> <script type="text/javascript"> function loadHTML(url, destination){ alert(url); } </script> </head> <body> <table width="100%" border="0"> <tr> <td id="main" width="200" valign="top"><h3>Main categories</h3> <span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=1', 'sub')">Arts</span> (608)</br /> <span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=2', 'sub')">Business</span> (152)</br /> <span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=3', 'sub')">Comics</span> (21)</br /> <span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=4', 'sub')">Computers</span> (202)</br /> <span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=5', 'sub')">Games</span> (29)</br /> <span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=6', 'sub')">Health</span> (35)</br /> <span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=7', 'sub')">Home</span> (3)</br /> <span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=8', 'sub')">News</span> (66)</br /> <span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=9', 'sub')">Recreation</span> (21) </td> <td width="200" valign="top"><h3>Sub categories</h3> <div id="sub"></div> </td> <td rowspan="2" valign="top"><div id="status"></div> <div id="feed"></div></td> </tr> <tr> <td colspan="2"><h3>Feeds</h3> <div id="feedlist"></div> </td> </tr> </table> </body> </html>
Here we have an HTML table, with each section that will receive content identified using an ID attribute. (This will help us later,
when we're ready to add content. The first column has the main categories, with each one enclosed in a span
tag. Each span
tag has an onclick
handler specified. Just to make sure it's working,
I've added an alert box to the script we're calling. You can see the results in figure 2.
When we call this function, we want to initiate the remote download. How we do that depends on what browser we're using:
... var req; function loadHTML(url, destination){ if (window.XMLHttpRequest){ req = new XMLHttpRequest(); req.open("GET", url, true); req.send(null); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); if (req) { req.open("GET", url, true); req.send(); } } } ...
In the Mozilla browsers and Opera, the XMLHttpRequest
object is
built-in, so we can test for that. If it's there, we can create a request object,
and then use it to open a new connection. Once the connection is open, we can
specify and send the request. The process is virtually, but not completely, identical in Microsoft Internet
Explorer's implementation, identified by the presense of ActiveX objects.
Now we need to detect the response and do something with it. To that end, we need to specify an event handler, or a function to be called when something happens:
... function processStateChange(){ statusDiv = document.getElementById("status"); if (req.readyState == 0){ statusDiv.innerHTML = "UNINITIALIZED"; } if (req.readyState == 1){ statusDiv.innerHTML = "LOADING"; } if (req.readyState == 2){ statusDiv.innerHTML = "LOADED"; } if (req.readyState == 3){ statusDiv.innerHTML = "INTERACTIVE"; } if (req.readyState == 4){ statusDiv.innerHTML = "COMPLETE"; } } function loadHTML(url, destination){ if (window.XMLHttpRequest){ req = new XMLHttpRequest(); req.onreadystatechange = processStateChange; req.open("GET", url, true); req.send(null); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); if (req) { req.onreadystatechange = processStateChange; req.open("GET", url, true); req.send(); } } } ...
The processStateChange
function checks for the current status of the request and displays it on the
page by getting a reference to the status
div and setting its content, as you can see in figure 3:
Now we're ready to deal with the actual content. If the request was successful, it will return a status code of 200.
In that case, we extract the XML text of the response (which, in this case, is actually HTML) and add it as the content of the sub
div. If the request was not successful, we display the status code in the status
div:
... function processStateChange(){ statusDiv = document.getElementById("status"); if (req.readyState == 0){ statusDiv.innerHTML = "UNINITIALIZED"; } if (req.readyState == 1){ statusDiv.innerHTML = "LOADING"; } if (req.readyState == 2){ statusDiv.innerHTML = "LOADED"; } if (req.readyState == 3){ statusDiv.innerHTML = "INTERACTIVE"; } if (req.readyState == 4){ if (req.status == 200){ response = req.responseText; destinationDiv = document.getElementById("sub"); destinationDiv.innerHTML = response; } else { statusDiv.innerHTML = "Error: Status "+req.status; } } } ...
You can see the results in figure 4:
At this point, you should have a working, if incomplete, page. You may, however, be having trouble running it. Like Java applets before it, Javascript only opens a connection to the server from which it's downloaded. To solve this problem, you may need to upload your test file to a server to run it (and to serve your requested files), as I've done with mine.
That said, let's look at finishing this up. At this point, we can request anything we want (on our server, of course),
but it's all going to be deposited in the sub
bin. That's fine for our main categories (and
their subcategories), but we don't want to have to write separate scripts for the subcategories, which write to "feedlist",
and the feed links, which write to "feed".
For example, the code retreived and displayed in the sub
div is:
<span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=f1', 'feedlist')">Animation</span> (1)<br /> <span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/subcategories.php?cat_id=f2', 'feedlist')">Architecture</span> (1)<br /> ...
In this case, the subcategories
page retrieves the following code for the feeds
list:
<span onclick="loadHTML('http://www.nicholaschase.com/ajaxdemo/proxy.php?url=http://www.vanguardreport.com/phpnuke/backend.php', 'feed')">The Vanguard Science Fiction Report</span><br /> <span onclick="loadHTML('http://www.nicholaschase.com/blog/index.rdf', 'feed')">Chaos Magnet</span><br /> ...
(Notice that on the first feed, we're using a proxy to get around the issue of making requests off another server.)
Our loadHTML
script accepts the second parameter, the destination, but we need to find a way to make
it available when we need it.
Unfortunately, because of the way handlers are assigned, with no arguments, we can't just specify it when we assign the processStateChange
function, so we'll need to set it in a variable in the same scope as the request itself:
... var req; var dest; function processStateChange(){ statusDiv = document.getElementById("status"); if (req.readyState == 0){ statusDiv.innerHTML = "UNINITIALIZED"; } if (req.readyState == 1){ statusDiv.innerHTML = "LOADING"; } if (req.readyState == 2){ statusDiv.innerHTML = "LOADED"; } if (req.readyState == 3){ statusDiv.innerHTML = "INTERACTIVE"; } if (req.readyState == 4){ statusDiv.innerHTML = " "; } if (req.readyState == 4){ if (req.status == 200){ response = req.responseText; destinationDiv = document.getElementById(dest); destinationDiv.innerHTML = response; } else { statusDiv.innerHTML = "Error: Status "+req.status; } } } function loadHTML(url, destination){ dest = destination; if (window.XMLHttpRequest){ req = new XMLHttpRequest(); req.onreadystatechange = processStateChange; req.open("GET", url, true); req.send(null); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); if (req) { req.onreadystatechange = processStateChange; req.open("GET", url, true); req.send(); } } } ...
With this change in place, we can use a single function for all of our requests, as you can see in figure 5:
At this point we've got all of the requests handled, but the content isn't exactly ready for prime time. The next thing we'll do is use XSL Transformations to convert the raw feeds to HTML.