JavaScript XML Cheat Sheet

Recently I was working on some complicated JavaScript to nest unordered lists and list items to match an Atom feed's XML structure. I had to spend an entire day researching JavaScript's XML parsing capabilities because there is no place on the Internet where this information is gathered to my satisfaction. I created a JavaScript cheat sheet on XML for my notes. I thought I would share it with you in order to get some feedback for improving my notes. Let me know if you know of a JavaScript library that eases the pain of working with XML in JavaScript. jQuery is somewhat useful for this if you use its DOM selectors on an XML document instead of the web page document. var entryNode = $('entry',xmlDoc).eq(5);

Load XML

You can load XML from a file on the web server or from a remote source via XMLHttpRequest. The code below shows the number of child nodes below the root element.

   1: (document).ready(function(){ 
   2:     // Load XML from a file on the web server
   3:     if (window.ActiveXObject) {
   4:         var xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
   5:         xmlDoc.async = false;
   6:         xmlDoc.load("xml/video-comments.xml");
   7:     }
   8:     else {
   9:         var mXHR = new XMLHttpRequest();
  10:         mXHR.open("GET", "xml/video-comments.xml", false);
  11:         mXHR.send(null);
  12:         xmlDoc = mXHR.responseXML;
  13:     }
  14:     var root = xmlDoc.documentElement;
  15:     $("#response").append(root.childNodes.length);
  16: }); 

NOTE: Firefox, Opera, and Safari counts any whitespace as text nodes so their node counts may be higher.

getElementsByTagName

You can get an array of elements by tag name which returns all occurrences even when the elements are nested within each other.

   1: var root = xmlDoc.documentElement;
   2: var nodelist = root.getElementsByTagName('entry');
   3: $("#response").append("Entry Nodes: " + nodelist.length);

You can also use a wildcard character to get all elements with a tag name:

   1: var root = xmlDoc.documentElement;
   2: var nodelist = root.getElementsByTagName('*');
   3: $("#response").append("<b>All tags count: </b>" + nodelist.length);

Find A Child Node By Tag Name

Internet Explorer has a text property for a node while the other browsers use textContent:

   1: var root = xmlDoc.documentElement;
   2: var nodelist = root.getElementsByTagName('entry');
   3: var strID = "";
   4: // loop through the sixth node's children
   5: for (var i = 0; i < nodelist[5].childNodes.length; i++) {
   6:     var child = nodelist[5].childNodes[i];
   7:     // find the child node by tag name
   8:     if (child.tagName == "id") {
   9:         // IE supports the text property
  10:         if (window.ActiveXObject) {
  11:             strID = child.text
  12:         }
  13:         // Other browsers use textContent
  14:         else {
  15:             strID = child.textContent;
  16:         }
  17:     }
  18: }

Internet Explorer's Xml Property

Internet Explorer has an xml property for a node but the other browsers do not.

   1: var root = xmlDoc.documentElement;
   2: var nodelist = root.getElementsByTagName('entry');
   3: var strID = "";
   4: // loop through the sixth node's children
   5: for (var i = 0; i < nodelist[5].childNodes.length; i++) {
   6:     var child = nodelist[5].childNodes[i];
   7:     // find the child node by tag name
   8:     if (child.tagName == "id") {
   9:         // IE supports the xml property
  10:         if (window.ActiveXObject) {
  11:             strID = child.xml
  12:         }
  13:     }
  14: }
  15: $("#response").append("<b>5th Entry Element: </b>" + htmlentities(strID));

NOTE: The xml namespace will be added to the xml tag.

Get The First Child Element

Remember that the other browsers may count whitespace as a child node:

   1: var root = xmlDoc.documentElement;
   2: var nodelist = root.getElementsByTagName('entry');
   3: var strText = "";
   4: // Get the first child of a node in IE 
   5: if (window.ActiveXObject) {
   6:     child = nodelist[5].firstChild;
   7:     strText = child.text;
   8: }
   9: // In other browsers the first child would be whitespace so get the next sibling
  10: else {
  11:     child = nodelist[5].childNodes[0].nextSibling;
  12:     strText = child.textContent;
  13: }
  14: $("#response").append("<b>6th Node's First Child: </b>" + strText);

Get The Last Child Element

Remember that the other browsers may count whitespace as a child node:

   1: var root = xmlDoc.documentElement;
   2: var nodelist = root.getElementsByTagName('entry');
   3: var strText = "";
   4: // Get the last child of a node in IE 
   5: if (window.ActiveXObject) {
   6:     child = nodelist[5].lastChild;
   7:     strText = child.text;
   8: }
   9: // In other browsers the last child would be whitespace so get the previous sibling
  10: else {
  11:     child = nodelist[5].lastChild.previousSibling;
  12:     strText = child.textContent;
  13: }
  14: $("#response").append("<b>6th Node's Last Child: </b>" + strText);

Get The Parent Node

   1: var root = xmlDoc.documentElement;
   2: var nodelist = root.getElementsByTagName('entry');
   3: var strText = "";
   4: child = nodelist[5].parentNode;
   5: strText = child.tagName;
   6: $("#response").append("<b>6th Node's Parent Tag Name: </b>" + strText);

Node Types

nodeType returns the type of the node; 1 is an element node, 2 is an attribute and 3 is text.

   1: var root = xmlDoc.documentElement;
   2: var nodelist = root.getElementsByTagName('entry');
   3: // node type 1 = element
   4: var type = nodelist[7].nodeType;
   5: $("#response").append("<b>Node Type: </b>" + type + "<br>");
   6: // node type 2 = attribute
   7: var type = nodelist[7].childNodes[5].attributes[0].nodeType;
   8: $("#response").append("<b>Node Type: </b>" + type + "<br>");
   9: // node type 3 = text
  10: var type = nodelist[7].childNodes[0].nodeType;
  11: $("#response").append("<b>Node Type: </b>" + type + "<br>")

Get An Attribute Of An Element

   1: var root = xmlDoc.documentElement;
   2: var nodelist = root.getElementsByTagName('entry');
   3: // get an attribute
   4: if (window.ActiveXObject) {
   5:     var attr = nodelist[7].childNodes[3].getAttribute("type");
   6: }
   7: // In other browsers whitespace counts as child nodes
   8: else {
   9:     var attr = nodelist[7].childNodes[5].getAttribute("type");
  10: }
  11: $("#response").append("<b>Attribute: </b>" + attr);

XPath

The main interface to using XPath is the evaluate function of the document object.

The evaluate function takes a total of five parameters:

  • xpathExpression: A string containing the XPath expression to be evaluated.
  • contextNode: A node in the document against which the xpathExpression should be evaluated, including any and all of its child nodes. The document node is the most commonly used.
  • namespaceResolver: A function that will be passed any namespace prefixes contained within xpathExpression which returns a string representing the namespace URI associated with that prefix. This enables conversion between the prefixes used in the XPath expressions and the possibly different prefixes used in the document. The function can be either:
    Created by using the createNSResolver method of a XPathEvaluator object. You should use this virtually all of the time.
    null, which can be used for HTML documents or when no namespace prefixes are used. Note that, if the xpathExpression contains a namespace prefix, this will result in a DOMException being thrown with the code NAMESPACE_ERR.
    A custom user-defined function.
  • resultType: A constant that specifies the desired result type to be returned as a result of the evaluation. The most commonly passed constant is XPathResult.ANY_TYPE which will return the results of the XPath expression as the most natural type.
  • result: If an existing XPathResult object is specified, it will be reused to return the results. Specifying null will create a new XPathResult object.
   1: var root = xmlDoc.documentElement;
   2: var nsResolver = xmlDoc.createNSResolver(xmlDoc.ownerDocument == null ? xmlDoc.documentElement : xmlDoc.ownerDocument.documentElement);
   3: var xpathResult = xmlDoc.evaluate('count(//*)', xmlDoc, nsResolver, XPathResult.ANY_TYPE, null);
   4: $("#response").append("<b>Number of Nodes: </b>" + xpathResult.numberValue + "<br>");
   5: // @ Selects attributes
   6: var xpathResult = xmlDoc.evaluate('count(//*/@*)', xmlDoc, nsResolver, XPathResult.ANY_TYPE, null);
   7: $("#response").append("<b>Number of Nodes: </b>" + xpathResult.numberValue + "<br>");
   8: // . Selects the current node
   9: var xpathResult = xmlDoc.evaluate('count(.)', xmlDoc, nsResolver, XPathResult.ANY_TYPE, null);
  10: $("#response").append("<b>Number of Nodes: </b>" + xpathResult.numberValue + "<br>");
  11: // / Selects from the root node
  12: var xpathResult = xmlDoc.evaluate('count(/)', xmlDoc, nsResolver, XPathResult.ANY_TYPE, null);
  13: $("#response").append("<b>Number of Nodes: </b>" + xpathResult.numberValue + "<br>");
  14: // Predicates are always embedded in square brackets.
  15: var xpathResult = xmlDoc.evaluate('count(//*[1])', xmlDoc, nsResolver, XPathResult.ANY_TYPE, null);
  16: $("#response").append("<b>Number of Nodes: </b>" + xpathResult.numberValue + "<br>");
  17: // node() Matches any node of any kind 
  18: var xpathResult = xmlDoc.evaluate('count(//node())', xmlDoc, nsResolver, XPathResult.ANY_TYPE, null);
  19: $("#response").append("<b>Number of Nodes: </b>" + xpathResult.numberValue + "<br>");
  20: // NUMBER_TYPE = 1
  21: // A result containing a single number. This is useful for example, in an XPath expression using the count() function.
  22: $("#response").append("<b>Result Type: </b>" + xpathResult.resultType + "<br>");
  23: // //*[2] Selects every second child node of all the nodes
  24: var xpathResult = xmlDoc.evaluate('//*[2]', xmlDoc, nsResolver, XPathResult.ANY_TYPE, null);
  25: // UNORDERED_NODE_ITERATOR_TYPE = 4
  26: // A result node-set containing all the nodes matching the expression. 
  27: // The nodes may not necessarily be in the same order that they appear in the document.
  28: $("#response").append("<b>Result Type: </b>" + xpathResult.resultType + "<br>");
  29: var result = xpathResult.iterateNext();
  30: while (result) {
  31:     $("#response").append("<b>Child Node: </b>" + result.tagName + "<br>");
  32:     result = xpathResult.iterateNext();
  33: }

NOTE: This is not supported in Internet Explorer. There isn't much sample code to be found using this method and it gave me a lot of trouble. These are the only XPaths that worked for me.

Select Nodes

You can only use the functions selectNodes or selectSingleNode in Internet Explorer:

   1: var root = xmlDoc.documentElement;
   2: $("#response").append("<b>Feed Title: </b>" + xmlDoc.selectSingleNode("/feed/title").text + "<br>");
   3: // Items
   4: var entries = xmlDoc.selectNodes("/feed/entry");
   5: for (var i = 0; i < entries.length; i++) {
   6:     $("#response").append("<b>Entry ID: </b>" + entries[i].selectSingleNode("./id").text + "<br>");
   7: }

Client Side XSL Transformations

   1: <script type="text/javascript">
   2:     // Load XML 
   3:     var xml = new ActiveXObject("Microsoft.XMLDOM")
   4:     xml.async = false
   5:     xml.load("file.xml")
   6:     // Load XSL
   7:     var xsl = new ActiveXObject("Microsoft.XMLDOM")
   8:     xsl.async = false
   9:     xsl.load("file.xsl")
  10:     // Transform
  11:     document.write(xml.transformNode(xsl))
  12: </script>

9 Comments

Comments have been disabled for this content.