XPath Querying is where you use an XPath query pattern to search a DOM-tree. The string pattern is analogous to a directory path leading to the desired matching element, or elements.
XPath compiles a pattern to a set of rules.
XPath's method match() searches the DOM-tree.
JAST supports only the short-form XPath syntax. The results are returned as lists of Content, the abstract superclass of all kinds of XML nodes. Your program may cast these down to more specific types.
XPath Querying only works on DOM-trees in memory, and not directly on XML files. You will need XMLReader to read the XML file into memory.
XPath Querying is enabled through a number of components in the XPath Search Engine. The only class that concerns the user is XPath, through which all search functions are controlled.
The key components of the XPath Search Engine are:
XPath - denoting an XPath query string, which compiles to a set of rules for matching in a DOM-tree;
XPathRule - the abstract ancestor of a family of matching rules that match along different axes, such as the child-axis, or parent-axis;
XPathCompiler - a compiler that converts an XPath query string into a set of XPathRules.
XPath and all components of the XPath Search Engine are found in the package:
uk.ac.sheffield.jast.xpath
All XPath queries are strings that look somewhat like directory paths, except they navigate a DOM-tree, rather than the directories and files on a disk.
All XPath queries are applied to an XML node, or a list of XML nodes, which is known as the context. This may initially be the whole Document, but may also be an Element, or any List<Content> in Java.
As a starting point, we draw a contrast between:
an absolute path - that always starts the search from the root of the current DOM-tree;
a relative path - that starts the search from the current context node (or nodes).
An example of each of these is given below. We assume that the current context is a Film node in the example file Catalogue.xml.
XPath("/Catalogue/TVShow")
XPath("Director/text()")
The first XPath is an absolute path, indicated by the initial forward slash /. This will navigate from the root Document node and search for all TVShow elements under the Catalogue root element.
The second XPath is a relative path (with no initial forward slash). This will navigate from the context (assume a Film node) to its child Director node, and return the Text content of that node.
Navigating within a DOM-tree is easy using the following syntax:
XPath(".") current node
XPath("..") parent of current
XPath("/.") top Document node
These have the following meanings:
The single dot is the search pattern for the current context node to which you apply the query.
The double dot navigates to the parent of the context node to which you apply the query.
The slash-dot is absolute, so navigates to the root, and returns the root Document node.
Searching for specific Element nodes is easy, using the following syntax:
XPath("Film")
XPath("Film/Director")
XPath("/Catalogue/TVShow")
These respectively have the following meanings:
Find all the Film children of the context node;
Find all the Director grandchildren of the Film children of the context node;
Find the TVShow children of the Catalogue root element of the Document.
The last example specifies an absolute path; the other examples were relative to the context.
More ambitious searching is possible using the wildcard syntax asterisk (or star), which may stand for any Element-node (name unspecified):
XPath("/Catalogue/*")
This XPath query has the meaning:
Find any children elements of the Catalogue root element of the Document.
The double-slash is a powerful search operator, that means "find anywhere" under the context:
XPath("//Film")
XPath("/Catalogue//Director")
XPath("//.")
These XPath queries respectively mean:
Find all the Film nodes anywhere in the whole Document;
Find all Director nodes anywhere under the Catalogue root node.
Find all nodes in the Document.
The double-slash can be used both in an absolute, and relative way. At the start of a path, it is absolute, but within a path, it is relative to the previous node.
Searching for specific Attribute nodes is easy using the following syntax, in which the "@" symbol prefixes the name of an attribute:
XPath("@year")
XPath("Film/@year")
XPath("Catalogue//@rating")
These XPath queries mean the following:
find the year attribute of the context node;
find the year attributes of the Film children of the context node;
find all rating attributes anywhere under the Catalogue child of the context node.
These all return one or more matching results - single values are returned in singleton lists.
It is possible to select general kinds of content, using the special query functions, which end in parentheses (to distinguish them from element names):
XPath("Title/text()")
XPath("/Catalogue/comment()")
XPath("/processing-instruction()")
XPath("/Catalogue/node()")
These XPath queries return:
the Text content of the Title child of the context node;
the Comment node under the root Catalogue element of the Document;
the processing Instruction node under the top level Document node.
any XML Content node under the root Catalogue element of the Document.
It is possible to express a restriction to filter the kinds of node to be returned. A restriction is an expression in square brackets []:
XPath("Film[@year]")
XPath("Film[@year>1976]")
These XPath queries mean:
Find all Film children of the context node that have a year attribute specified.
Find all Film children of the context node, for which the year attribute's value is greater than 1976.
All six inequality expressions are supported:
=, !=, <, >, <=, >=
A restriction may also be placed on different kinds of element searching:
XPath("/Catalogue/*[Director]")
XPath("Film[Director='George Lucas'")
These XPath queries mean:
Find all elements under the Catalogue root node that have a child-node Director;
Find all Film children of the context node that have a child node Director, whose text value is equal to "George Lucas".
This shows that literal string values must be enclosed in single quotation marks, to distinguish this from the double quotation marks around the whole query string.
It is possible to select some nodes based on their absolute position within a larger structure:
XPath("/Catalogue/Film[2]")
XPath("/Catalogue/Film[last()]")
XPath("Film[last()-1]")
These XPath queries return:
the second Film child of the Catalogue root element;
the last Film child of the Catalogue root element;
the last-but-one Film child of the context node.
It is also possible to filter for sets of nodes relative to a given position in a larger structure:
XPath("/Catalogue/Film[position()>2]")
XPath("/Catalogue/Film[position()<5]")
These XPath queries return:
all Film children of the Catalogue root element from index 3..n (where n is the total number of Films);
all Film children of the Catalogue root element from index 1..4 inclusive.
The search results may be incomplete or empty, if the indices do not specify a valid range. Indexing is from 1..n (not from 0..n-1).
It is possible to express limited logical expressions within an XPath query:
XPath("Film | TVShow")
XPath("Film/[@year<1972 or @year>2001]")
XPath("Film/[@rating='U' and @year<1970")
XPath("Film/[not(@year=1976)]")
In these XPath queries:
the vertical bar | (surrounded by space) separates alternative search paths, so this returns all the Film and TVShow children;
the operator or (surrounded by space) combines disjoint restrictions, so this returns any Film either before 1972 or after 2001;
the operator and (surrounded by space) combines conjoint restrictions, so this returns any Film before 1970 whose rating is U;
the function not (enclosing a term in parentheses) negates a restriction, so this returns any Film not made in 1976.
Placing a sequence of restrictions means the same thing as conjoining these restrictions with and.
To execute an XPath query is extremely easy. You create a suitable instance of XPath, and then you ask it to match() against a chosen portion of the DOM-tree. Some examples are:
XPath findFilms =
new XPath("/Catalogue/Film");
List<Content> films =
findFilms.match(document);
This will return all the Films under the root Catalogue, as a List of Content. The XPath findFilms is matched against the top-level Document node. So the context here is a single node.
XPath findYears = new XPath("@year");
List<Content> years =
findYears.match(films);
This will return all the year attributes of all the Films returned in the previous query, as a List of Content. The XPath findYears is matched against the List of Content returned by the previous query. So the context here is a list of nodes.
XPath findNames =
new XPath("//Director/text()");
List<Content> names =
findNames.match(document);
This will return the names of all the Directors found anywhere in the top-level Document. These will be Text nodes, a kind of XML Content.
Because you cannot know in advance what type of XML node an XPath query will return, the result is always a List of Content. This may even contain nodes of mixed types.
Your own program may easily iterate through the returned list and cast the type of individual elements down to a more specific type, if required. The XML Content nodes all contain an integer type identifier, which may be used to check actual types. Please see the JAST documentation for more details.
Any syntax faults in the XPath query string are signalled by the XPathCompiler, which throws SyntaxError errors.
The JAST implementation of XPath supports the W3C abbreviated syntax for most simple XPath patterns.
It supports queries searching the self-axis, the parent-axis, the attribute-axis, the child-axis and the descendants-or-self-axis.
It does not support the preceding-axis, following-axis, preceding-sibling-axis, following-sibling-axis, ancestor-axis, ancestor-or-self-axis or descendant-axis, which have no abbreviated syntax forms.
It supports searching for elements, attributes, text, comments and general nodes.
It supports wildcards standing for the whole names of elements or attributes, but not parts of names.
It supports value-restriction using all six inequality operators.
It supports positional selection and filtering using indices and the last() and position() functions.
It supports alternative paths, and boolean and, or, not applied to restrictions; but not precedence reordering by grouping in parentheses.
It does not support arbitrary arithmetical and string functions, in order to limit the complexity of the XPath processor.