Crossword Web App, Part 6 0 Comments
Although it’s easy to get Javascript to read from an XML file, pulling out the appropriate data can sometimes be tricky. Here are some tips to help you tame the XML beast.
Part 6: Taming XML
Let’s look at a typical XMLHttpRequest again.
var url = 'xml/070814.xml';var xmlhttp = new XMLHttpRequest(); if (xmlhttp != null) {xmlhttp.onreadystatechange = stateChange;xmlhttp.open('GET', url, true);xmlhttp.send(null);} else {alert('Your browser does not support XMLHTTP.'); }} function stateChange() {if (xmlhttp.readyState == 4) {if (xmlhttp.status == 200) {/*A status of 200 means that the XML file wasloaded and parsed without error. At this pointyou'll want to sort through all of the data sothat it can be used by your program. I'll giveyou some tips on how to do this in the nextupdate.*/} else {alert('Problem retrieving XML data.');}}}Figure 1. The basic structure of an XMLHttpRequest
If the request succeeds without error, then we can use the xmlhttp object to access the contents of the loaded XML file. To understand how to work with an XMLHttpRequest object, let’s relate it to something a little more familiar to Web coders: the Javascript Document object.
document.getElementsByName('across') will return an array containing all of the elements on your Web page whose name attribute is “across.” For example, <div name="across">.
xmlhttp.responseXML.getElementsByTagName('across') will return an array containing all of the “across” XML nodes. For example, <across>Data</across>.
Nodes can have both attributes and values. Review Figure 2.
<?xml version="1.0" encoding="UTF-8"?><editor>Timothy Parker</editor><across><a1 a="POET" c="Burns or Byron" n="1" cn="1" /></across>Figure 2. c is an attribute of the a1 node.
“Timothy Parker” is the value of the editor node.
getElementsByTagName will always return an array. In the example above there is only one a1 node, therefore there’s no reason to keep an array of a1 nodes. Instead, using the code below, we can save only the first returned node (since that’s all that exists).
var a1Node = xmlhttp.responseXML.getElementsByTagName('a1')[0];Figure 3. Save a reference to the a1 XML node in a variable named a1Node.
Now that we’ve captured the a1 node specifically, we can access its c attribute using this simple code: var c = a1.getAttribute('c');.
Accessing node attributes is easy, but accessing node values is a little more confusing. Figure 4 demonstrates how to access the value of the editor node.
var editor = xmlhttp.responseXML.getElementsByTagName('editor')[0];var editorValue = editor.firstChild.nodeValue;Figure 4. Accessing the value of the editor node.
The firstChild method returns the first child of a node, duh. But the editor node does not appear to have any children. Well, it apparently (or not so apparently) does. When attempting to access the value of a node, imagine the value text as being a node itself. Access the nodeValue of the “text node” and you’ll get the result you’re looking for. Or, in more simple terms, always use .firstChild.nodeValue to access the value of a node.
<?xml version="1.0" encoding="UTF-8"?><across><a1 a="POET" c="Burns or Byron" n="1" cn="1" /><a2 a="BLAB" c="Give everything away" n="6" cn="5" /><a3 a="TALKS" c="Gives everything away" n="11" cn="9" /><a4 a="ALSO" c="Too" n="16" cn="14" /><a5 a="YOHO" c="Exclamation by Captain Jack Sparrow" n="21" cn="15" /><a6 a="ELIOT" c="'A Cooking Egg' writer" n="26" cn="16" /><a7 a="LIAR" c="Ananias, for one" n="31" cn="17" /><a8 a="PREY" c="Target in the wild" n="36" cn="18" /><a9 a="ALONE" c="In isolation" n="41" cn="19" /></across>Figure 5. Another XML example.
In the above example, all of the across child nodes are named differently, so it would be cumbersome to getElementsByTagName each one separately. Instead, take advantage of the childNodes collection to return an array of the nodes.
var acrossNodes = xmlhttp.responseXML.getElementsByTagName('across')[0].childNodes;Figure 6. Save all of the across child nodes to an array.
There is more to learn about XMLHttpRequest, but by simply knowing how to use the getElementsByTagName, getAttribute, firstChild and nodeValue methods and the childNodes collection, you’ll have an easy time retrieving all types of data from XML documents.
Before I close this lengthy post, there is one more thing I’d like to mention with regards to XML files. It appears that you can not use Javascript to access local XML files using XMLHttpRequest, you can only access files found on a domain. I am completely perplexed as to why this is and if anyone has knowledge of the reason, or knows a workaround, I’d love to hear from you.
— Ryan