Building XPointer Expressions
The most important component of XPointer expressions is the location path, which is a construct used to describe the path that must be followed to arrive at a node within an XML document tree. Location paths are the building blocks of XPointer expressions, which are evaluated to arrive at a specific location within a tree. More specifically, location paths allow you to traverse siblings, ancestors, children, and descendants of nodes, not to mention attributes. Location paths are broken down into two basic typesabsolute paths and general paths.
Absolute location paths point to a specific location within an XML tree, and therefore aren't dependent on context. Following are the different absolute location paths defined in XPointer:
/Locates the root node, which is the parent node for the entire document tree
id(Name)Locates the element with an attribute ID value of
here()Locates the node containing the current XPointer expression
origin()Locates the sub-resource from which the user initiated a link (used with out-of-line links)
The most important absolute location paths are the root and
id() paths. The root path is represented by a forward slash (
/), and is often used at the start of an XPointer expression as the basis for absolute location paths. The
id() location path is used to locate an element with a specific attribute value.
In addition to absolute location paths, XPointer also defines a rich set of relative location paths. Relative location paths are always relative to some node, which is known as the context node for the path. Following are the relative location paths available for use in XPointer expressions:
childLocates child nodes of the context node
descendantLocates nodes within the context node
descendantexcept the context node is also included
parentLocates nodes one level above the context node that contains the context node
ancestorLocates all nodes above the context node that contain the context node
ancestorexcept the context node is also included
preceding-siblingLocates sibling nodes that precede the context node
following-siblingLocates sibling nodes that follow the context node
precedingLocates nodes that precede the context node
followingLocates nodes that follow the context node
selfLocates individual context nodes within a list of context nodes
attributeLocates attributes of the context node
If you're totally confused by all this context node talk, don't worry because it will all make sense in a moment. As confusing as it may seem, the relative location paths in the previous list really are quite useful and are much easier to use than you might think. The next section shows you how to use these location paths to create expressions in XPointer.
Seeing a few examples of XPointer expressions can make all the difference in understanding how XPointer is used to define document fragment identifiers. Following is an example of a simple XPointer expression:
This example uses the child relative location path to locate all of the children of the context node that are of element type
factoid. Let me rephrase it in a different way: The sample expression locates element nodes of type
factoid that are child nodes of the context node. Keep in mind that the context node is the node from which you are issuing the expression, which is a lot like the current path of a file system when you're browsing for files. Also, it's worth clarifying that the XPointer expression
child::factoid simply describes the fragment identifier for a resource and is not a complete resource reference. When used in a complete expression, you would pair this fragment identifier with a URI that is assigned to an
href attribute, like this:
In this example, a URI is specified that references the XML document named
factoids.xml. The XPointer expression is then provided as a fragment identifier, which is separated from the URI by a pound symbol (
#). This is the typical way in which XPointers are used, although expressions can certainly get more complex than this. For example, the following code shows how to use location paths to create a more elaborate expression that carries out a more intricate reference:
This example first locates all child elements that are of type
factoid and then finds the second siblings following each of those element nodes that are of type
legend. To understand how this code works, let's break it down. You begin with the familiar
child::factoid expression, which locates element nodes of type
factoid that are child nodes of the context node. Adding on the
following-sibling::legend location path causes the expression to locate sibling elements of type
legend. Granted, this may seem like a strange use of XPointer, but keep in mind that it is designed as an all-purpose language for addressing the internal structure of XML documents. It's impossible to say how different applications might want to address document parts, which is why XPointer is so flexible.
In addition to location paths, XPointer defines several functions that perform different tasks within XPointer expressions. One class of functions is known as node test functions, which are used to determine the type of a node. Of course, you can use the name of an element to check if a node is of a certain element type, but the node test functions allow you to check and see if a node contains a comment, text, or processor instruction. The following is an example of how to use one of these functions:
This expression results in the location of any processing instructions that are children of the root element. The reason the expression results in children of the root element is because the root element (
/) is specified as the basis for the expression.
As you can see in these few examples, XPointer is a comprehensive yet flexible technology that is capable of doing some pretty interesting things. I'll readily admit that there is more to XPointer than I've touched on here; I mainly wanted to provide a solid overview and demonstrate how basic expressions are created. I encourage you to explore XPointer more on your own and experiment with creating XPointer expressions. However, before you do that you need to learn how XPointer fits into XLink.