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 ofName
-
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:
-
child
Locates child nodes of the context node -
descendant
Locates nodes within the context node -
descendant-or-self
Same asdescendant
except the context node is also included -
parent
Locates nodes one level above the context node that contains the context node -
ancestor
Locates all nodes above the context node that contain the context node -
ancestor-or-self
Same asancestor
except the context node is also included -
preceding-sibling
Locates sibling nodes that precede the context node -
following-sibling
Locates sibling nodes that follow the context node -
preceding
Locates nodes that precede the context node -
following
Locates nodes that follow the context node -
self
Locates individual context nodes within a list of context nodes -
attribute
Locates 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.
Creating XPointers
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:
child::factoid
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:
href="http://www.stalefishlabs.com/factoids.xml#child::factoid"
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:
child::factoid/following-sibling::legend
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:
/child::processing-instruction()
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.