Microsoft XML 2.5 SDK


 

How the DOM Defines the Context for XSL Pattern Queries

[This is preliminary documentation and subject to change.]

The Microsoft® Internet Explorer 5 XML implementation contains methods that accept an XSL Pattern string to conveniently 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");

Retrieval of the "item" nodes by walking the tree would take a substantial amount of code. With the selectNodes method and XSL patterns, nodes can be retrieved through a single line of code.

In most cases the returned set of nodes will be iterated over to perform further manipulations. The following example illustrates how you can calculate a total price for an "invoice" element.

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

This example contains two query contexts. The first query is performed from the context of the "invoice" element (invoice), and the query string reflects this by beginning with the document element "items." The for... loop iterates 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 upon which the selectNodes is performed defines the context for the query.

A common source of confusion involves performing queries from the document root versus the document element. These two nodes are different in the XML tree and thus require different query strings. The following three statements will yield identical results for our 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 "selectNodes(pattern).item(0)". The above example could take advantage of selectSingleNode to simplify the code a bit.

function invoiceTotal(invoice)
{
  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 this example, selectNodes is still 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.