Module xpath
:- use_module(library(xpath)).
Select nodes in an XML DOM
The library xpath.pl provides predicates to select nodes from an XML DOM tree as produced by library(sgml)
based on descriptions inspired by the XPath language.
The predicate xpath/3
selects a sub-structure of the DOM non-deterministically based on an XPath-like specification. Not all selectors of XPath are implemented, but the ability to mix xpath/3
calls with arbitrary Prolog code provides a powerful tool for extracting information from XML parse-trees.
xpath_chk(+DOM, +Spec, ?Content) is semidet.
Semi-deterministic version of xpath/3
.
xpath(+DOM, +Spec, ?Content) is nondet.
Match an element in a DOM structure. The syntax is inspired by XPath, using () rather than [] to select inside an element. First we can construct paths using / and //:
//Term Select any node in the DOM matching term.
/Term Match the root against Term.
Term Select the immediate children of the root matching Term.
The Terms above are of type callable. The functor specifies the element name. The element name *
refers to any element. The name self refers to the top-element itself and is often used for processing matches of an earlier xpath/3
query. A term NS:Term refers to an XML name in the namespace NS. Optional arguments specify additional constraints and functions. The arguments are processed from left to right. Defined conditional argument values are:
index(?Index)
True if the element is the Index-th child of its parent, where 1 denotes the first child. Index can be one of:Var
Var
is unified with the index of the matched element.last
True for the last element.last - IntExpr
True for the last-minus-nth element. For example,last-1
is the element directly preceding the last one.IntExpr
True for the element whose index equalsIntExpr
.
Integer
The N-th element with the given name, with 1 denoting the first element. Same asindex(Integer)
.last
The last element with the given name. Same asindex(last)
.last - IntExpr
The IntExpr-th element before the last. Same asindex(last-IntExpr)
.
Defined function argument values are:
self
Evaluate to the entire elementcontent
Evaluate to the content of the element (a list)text
Evaluates to all text from the sub-tree, represented as a list of characters.text(atom)
Evaluates to all text from the sub-tree as an atom.normalize_space
Astext
, but usesnormalize_space/2
to normalise white-space in the outputnumber
Extract an integer or float from the value. Ignores leading and trailing white-space@Attribute
Evaluates to the value of the given attribute. Attribute can be a compound term. In this case the functor name denotes the element and arguments perform transformations on the attribute value. Defined transformations are:number
Translate the value into a number usingxsd_number_chars/2
.integer
Asnumber
, but subsequently transform the value into an integer using theround/1
function.float
Asnumber
, but subsequently transform the value into a float using thefloat/1
function.lower
Translate the value to lower case, preserving the type.upper
Translate the value to upper case, preserving the type.
In addition, the argument-list can be conditions:
Left = Right
Succeeds if the left-hand unifies with the right-hand. If the left-hand side is a function, this is evaluated. The right-hand side is never evaluated, and thus the conditioncontent = content
defines that the content of the element is the atomcontent
. The functionslower_case
andupper_case
can be applied to Right (see example below).contains(Haystack, Needle)
Succeeds if Needle is a sub-list of Haystack.XPath
Succeeds if XPath matches in the currently selected sub-DOM. For example, the following expression finds anh3
element inside adiv
element, where thediv
element itself contains anh2
child with astrong
child.//div(h2/strong)/h3
This is equivalent to the conjunction of XPath goals below.
..., xpath(DOM, //(div), Div), xpath(Div, h2/strong, _), xpath(Div, h3, Result)
Examples
Match each table-row in DOM:
xpath(DOM, //tr, TR)
Match the last cell of each tablerow in DOM. This example illustrates that a result can be the input of subsequent xpath/3
queries. Using multiple queries on the intermediate TR term guarantee that all results come from the same table-row:
xpath(DOM, //tr, TR),
xpath(TR, /td(last), TD)
Match each href
attribute in an element
xpath(DOM, //a(@href), HREF)
Suppose we have a table containing rows where each first column is the name of a product with a link to details and the second is the price (a number). The following predicate matches the name, URL and price:
product(DOM, Name, URL, Price) :-
xpath(DOM, //tr, TR),
xpath(TR, td(1), C1),
xpath(C1, /self(normalize_space), Name),
xpath(C1, a(@href), URL),
xpath(TR, td(2, number), Price).
Suppose we want to select books with genre="thriller" from a tree containing elements
thriller(DOM, Book) :-
xpath(DOM, //book(@genre=thiller), Book).
Match the elements Get the Note that and
:
//table(@align(lower) = center)
width
and height
of a div
element as a number, and the div
node itself:
xpath(DOM, //div(@width(number)=W, @height(number)=H), Div)
div
is an infix operator, so parentheses must be used in cases like the following:
xpath(DOM, //(div), Div)