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:VarVaris unified with the index of the matched element.lastTrue for the last element.last - IntExprTrue for the last-minus-nth element. For example,last-1is the element directly preceding the last one.IntExprTrue for the element whose index equalsIntExpr.
IntegerThe N-th element with the given name, with 1 denoting the first element. Same asindex(Integer).lastThe last element with the given name. Same asindex(last).last - IntExprThe IntExpr-th element before the last. Same asindex(last-IntExpr).
Defined function argument values are:
selfEvaluate to the entire elementcontentEvaluate to the content of the element (a list)textEvaluates 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_spaceAstext, but usesnormalize_space/2to normalise white-space in the outputnumberExtract an integer or float from the value. Ignores leading and trailing white-space@AttributeEvaluates 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:numberTranslate the value into a number usingxsd_number_chars/2.integerAsnumber, but subsequently transform the value into an integer using theround/1function.floatAsnumber, but subsequently transform the value into a float using thefloat/1function.lowerTranslate the value to lower case, preserving the type.upperTranslate the value to upper case, preserving the type.
In addition, the argument-list can be conditions:
Left = RightSucceeds 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 = contentdefines that the content of the element is the atomcontent. The functionslower_caseandupper_casecan be applied to Right (see example below).contains(Haystack, Needle)Succeeds if Needle is a sub-list of Haystack.XPathSucceeds if XPath matches in the currently selected sub-DOM. For example, the following expression finds anh3element inside adivelement, where thedivelement itself contains anh2child with astrongchild.//div(h2/strong)/h3This 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)
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).and
//table(@align(lower) = center)Get the 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)Note that div is an infix operator, so parentheses must be used in cases like the following:
xpath(DOM, //(div), Div)