Microsoft XML Core Services (MSXML) 5.0 for Microsoft Office - XPath Developer's Guide

How the DOM Defines the Context for XPath Expressions

The Microsoft® XML Core Services (MSXML) 5.0 for Microsoft Office implementation contains methods that accept an XML Path Language (XPath) string to identify nodes within the XML tree. The selectNodes method returns a node list pointing to each of the selected nodes, as in the following example.

items = xmldoc.selectNodes("invoices/invoice/items/item");

It takes a substantial amount of code to retrieve the <item> nodes by navigating the tree. With the selectNodes method and XPath expressions, nodes can be retrieved through a single line of code.

In most cases, the returned set of nodes are iterated over to perform further manipulations. The following example shows how you can calculate a total price for an <invoice> element.

function invoiceTotal(invoice)
  {
    invoice = invoice.nextNode()
    items = invoice.selectNodes("items/item");
    var sum = 0;
    for (var item = items.nextNode(); item; item = items.nextNode())
    {
      var price = item.selectSingleNode("price").nodeTypedValue;
      var qty = item.selectSingleNode("qty").nodeTypedValue;
      if (qty >= 10)
        price = 0.9*price;
      sum += price * qty;
    }
    return sum;

This example contains two query contexts. The first query is performed from the context of the <invoice> element, and the query string reflects this by beginning with the document element <items>. The for loop repeat through the returned nodes and uses each as a context for further queries. These query strings are relative to <item> elements, and look within them for the <price> and <qty> children. This illustrates that the node on which the selectNodes is performed defines the context for the query.

Performing queries from the document root versus the document element can be confusing. These two nodes are different in the XML tree and therefore require different query strings. The following three statements yield identical results for the sample document, although only the last two are logically equivalent.

items = xmldoc.selectNodes("invoices/invoice");
items = xmldoc.selectNodes("*/invoice");
items = xmldoc.documentElement.selectNodes("invoice");

The selectSingleNode method returns the first node that matches the query, providing a convenient way to return a node directly without extracting it from a NodeList. It is equivalent to the following:

selectNodes(pattern).item(0)

The preceding example could simplify the code by using the selectSingleNode method.

function invoiceTotal(invoice)
{
  invoice = invoice.nextNode()
  items = invoice.selectNodes("items/item");
  var sum = 0;
  for (var item = items.nextNode(); item; item = items.nextNode())
  {
    var price = item.selectSingleNode("price").nodeTypedValue;
    var qty = item.selectSingleNode("qty").nodeTypedValue;
    sum += price * qty;
  }
  return sum;
}

In the preceding example, selectNodes is used to select a set of <item> elements. When only a single node is expected, such as the <price> and <qty> elements, selectSingleNode can be used.

The preceding sample code is part of the Invoice sample. For more information, see Sample XML File for DOM Context.