Compatible Doclog docs for library(xpath).
This commit is contained in:
323
src/lib/xpath.pl
323
src/lib/xpath.pl
@@ -100,214 +100,215 @@
|
|||||||
:- use_module(library(dcgs)).
|
:- use_module(library(dcgs)).
|
||||||
:- use_module(library(si)).
|
:- use_module(library(si)).
|
||||||
|
|
||||||
/** <module> Select nodes in an XML DOM
|
/** Select nodes in an XML DOM
|
||||||
|
|
||||||
The library xpath.pl provides predicates to select nodes from 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
|
tree as produced by `library(sgml)` based on descriptions inspired by the
|
||||||
XPath language.
|
[XPath language](http://www.w3.org/TR/xpath).
|
||||||
|
|
||||||
The predicate xpath/3 selects a sub-structure of the DOM
|
The predicate `xpath/3` selects a sub-structure of the DOM
|
||||||
non-deterministically based on an XPath-like specification. Not all
|
non-deterministically based on an XPath-like specification. Not all
|
||||||
selectors of XPath are implemented, but the ability to mix xpath/3 calls
|
selectors of XPath are implemented, but the ability to mix `xpath/3` calls
|
||||||
with arbitrary Prolog code provides a powerful tool for extracting
|
with arbitrary Prolog code provides a powerful tool for extracting
|
||||||
information from XML parse-trees.
|
information from XML parse-trees.
|
||||||
|
|
||||||
@see http://www.w3.org/TR/xpath
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
element_name(element(Name,_,_), Name).
|
element_name(element(Name,_,_), Name).
|
||||||
element_attributes(element(_,Attributes,_), Attributes).
|
element_attributes(element(_,Attributes,_), Attributes).
|
||||||
element_content(element(_,_,Content), Content).
|
element_content(element(_,_,Content), Content).
|
||||||
|
|
||||||
%! xpath_chk(+DOM, +Spec, ?Content) is semidet.
|
%% xpath_chk(+DOM, +Spec, ?Content) is semidet.
|
||||||
%
|
%
|
||||||
% Semi-deterministic version of xpath/3.
|
% Semi-deterministic version of `xpath/3`.
|
||||||
|
|
||||||
xpath_chk(DOM, Spec, Content) :-
|
xpath_chk(DOM, Spec, Content) :-
|
||||||
xpath(DOM, Spec, Content),
|
xpath(DOM, Spec, Content),
|
||||||
!.
|
!.
|
||||||
|
|
||||||
%! xpath(+DOM, +Spec, ?Content) is nondet.
|
%% xpath(+DOM, +Spec, ?Content) is nondet.
|
||||||
%
|
%
|
||||||
% Match an element in a DOM structure. The syntax is inspired by
|
% Match an element in a DOM structure. The syntax is inspired by
|
||||||
% XPath, using () rather than [] to select inside an element.
|
% XPath, using () rather than [] to select inside an element.
|
||||||
% First we can construct paths using / and //:
|
% First we can construct paths using / and //:
|
||||||
%
|
%
|
||||||
% $ =|//|=Term :
|
% - *//Term*
|
||||||
% Select any node in the DOM matching 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
|
% - */Term*
|
||||||
% the element name. The element name '*' refers to any element.
|
% Match the root against Term.
|
||||||
% 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) :
|
% - *Term*
|
||||||
% True if the element is the Index-th child of its parent,
|
% Select the immediate children of the root matching Term.
|
||||||
% 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 equals `IntExpr`.
|
|
||||||
% $ Integer :
|
|
||||||
% The N-th element with the given name, with 1 denoting the
|
|
||||||
% first element. Same as index(Integer).
|
|
||||||
% $ =last= :
|
|
||||||
% The last element with the given name. Same as
|
|
||||||
% index(last).
|
|
||||||
% $ =last= - IntExpr :
|
|
||||||
% The IntExpr-th element before the last.
|
|
||||||
% Same as index(last-IntExpr).
|
|
||||||
%
|
%
|
||||||
% Defined function argument values are:
|
% 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:
|
||||||
%
|
%
|
||||||
% $ =self= :
|
% - *`index(?Index)`*
|
||||||
% Evaluate to the entire element
|
% True if the element is the Index-th child of its parent,
|
||||||
% $ =content= :
|
% where 1 denotes the first child. Index can be one of:
|
||||||
% 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= :
|
|
||||||
% As =text=, but uses normalize_space/2 to normalise
|
|
||||||
% white-space in the output
|
|
||||||
% $ =number= :
|
|
||||||
% 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
|
% - *`Var`*
|
||||||
% Translate the value into a number using
|
% `Var` is unified with the index of the matched element.
|
||||||
% xsd_number_chars/2.
|
% - *`last`*
|
||||||
% - integer
|
% True for the last element.
|
||||||
% As `number`, but subsequently transform the value
|
% - *`last - IntExpr`*
|
||||||
% into an integer using the round/1 function.
|
% True for the last-minus-nth element. For example,
|
||||||
% - float
|
% `last-1` is the element directly preceding the last one.
|
||||||
% As `number`, but subsequently transform the value
|
% - *`IntExpr`*
|
||||||
% into a float using the float/1 function.
|
% True for the element whose index equals `IntExpr`.
|
||||||
% - lower
|
% - *`Integer`*
|
||||||
% Translate the value to lower case, preserving
|
% The N-th element with the given name, with 1 denoting the
|
||||||
% the type.
|
% first element. Same as `index(Integer)`.
|
||||||
% - upper
|
% - *`last`*
|
||||||
% Translate the value to upper case, preserving
|
% The last element with the given name. Same as
|
||||||
% the type.
|
% `index(last)`.
|
||||||
|
% - *`last - IntExpr`*
|
||||||
|
% The IntExpr-th element before the last.
|
||||||
|
% Same as `index(last-IntExpr)`.
|
||||||
%
|
%
|
||||||
% In addition, the argument-list can be _conditions_:
|
% Defined function argument values are:
|
||||||
%
|
%
|
||||||
% $ Left = Right :
|
% - *`self`*
|
||||||
% Succeeds if the left-hand unifies with the right-hand.
|
% Evaluate to the entire element
|
||||||
% If the left-hand side is a function, this is evaluated.
|
% - *`content`*
|
||||||
% The right-hand side is _never_ evaluated, and thus the
|
% Evaluate to the content of the element (a list)
|
||||||
% condition `content = content` defines that the content
|
% - *`text`*
|
||||||
% of the element is the atom `content`.
|
% Evaluates to all text from the sub-tree, represented
|
||||||
% The functions `lower_case` and `upper_case` can be applied
|
% as a list of characters.
|
||||||
% to Right (see example below).
|
% - *`text(atom)`*
|
||||||
% $ contains(Haystack, Needle) :
|
% Evaluates to all text from the sub-tree as an atom.
|
||||||
% Succeeds if Needle is a sub-list of Haystack.
|
% - *`normalize_space`*
|
||||||
% $ XPath :
|
% As `text`, but uses `normalize_space/2` to normalise
|
||||||
% Succeeds if XPath matches in the currently selected
|
% white-space in the output
|
||||||
% sub-DOM. For example, the following expression finds
|
% - *`number`*
|
||||||
% an =h3= element inside a =div= element, where the =div=
|
% Extract an integer or float from the value. Ignores
|
||||||
% element itself contains an =h2= child with a =strong=
|
% leading and trailing white-space
|
||||||
% child.
|
% - *`@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`*
|
||||||
% //div(h2/strong)/h3
|
% Translate the value into a number using
|
||||||
% ==
|
% `xsd_number_chars/2`.
|
||||||
|
% - *`integer`*
|
||||||
|
% As `number`, but subsequently transform the value
|
||||||
|
% into an integer using the `round/1` function.
|
||||||
|
% - *`float`*
|
||||||
|
% As `number`, but subsequently transform the value
|
||||||
|
% into a float using the `float/1` function.
|
||||||
|
% - *`lower`*
|
||||||
|
% Translate the value to lower case, preserving
|
||||||
|
% the type.
|
||||||
|
% - *`upper`*
|
||||||
|
% Translate the value to upper case, preserving
|
||||||
|
% the type.
|
||||||
%
|
%
|
||||||
% This is equivalent to the conjunction of XPath goals below.
|
% In addition, the argument-list can be _conditions_:
|
||||||
%
|
%
|
||||||
% ==
|
% - *`Left = Right`*
|
||||||
% ...,
|
% Succeeds if the left-hand unifies with the right-hand.
|
||||||
% xpath(DOM, //(div), Div),
|
% If the left-hand side is a function, this is evaluated.
|
||||||
% xpath(Div, h2/strong, _),
|
% The right-hand side is _never_ evaluated, and thus the
|
||||||
% xpath(Div, h3, Result)
|
% condition `content = content` defines that the content
|
||||||
% ==
|
% of the element is the atom `content`.
|
||||||
|
% The functions `lower_case` and `upper_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
|
||||||
|
% an `h3` element inside a `div` element, where the `div`
|
||||||
|
% element itself contains an `h2` child with a `strong`
|
||||||
|
% child.
|
||||||
%
|
%
|
||||||
% **Examples**:
|
% ```
|
||||||
|
% //div(h2/strong)/h3
|
||||||
|
% ```
|
||||||
%
|
%
|
||||||
% Match each table-row in DOM:
|
% This is equivalent to the conjunction of XPath goals below.
|
||||||
%
|
%
|
||||||
% ==
|
% ```
|
||||||
% xpath(DOM, //tr, TR)
|
% ...,
|
||||||
% ==
|
% xpath(DOM, //(div), Div),
|
||||||
|
% xpath(Div, h2/strong, _),
|
||||||
|
% xpath(Div, h3, Result)
|
||||||
|
% ```
|
||||||
%
|
%
|
||||||
% Match the last cell of each tablerow in DOM. This example
|
% #### Examples
|
||||||
% 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:
|
|
||||||
%
|
%
|
||||||
% ==
|
% Match each table-row in DOM:
|
||||||
% xpath(DOM, //tr, TR),
|
|
||||||
% xpath(TR, /td(last), TD)
|
|
||||||
% ==
|
|
||||||
%
|
%
|
||||||
% Match each =href= attribute in an <a> element
|
% ```
|
||||||
|
% xpath(DOM, //tr, TR)
|
||||||
|
% ```
|
||||||
%
|
%
|
||||||
% ==
|
% Match the last cell of each tablerow in DOM. This example
|
||||||
% xpath(DOM, //a(@href), HREF)
|
% 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:
|
||||||
%
|
%
|
||||||
% 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
|
% xpath(DOM, //tr, TR),
|
||||||
% is the price (a number). The following predicate matches the
|
% xpath(TR, /td(last), TD)
|
||||||
% name, URL and price:
|
% ```
|
||||||
%
|
%
|
||||||
% ==
|
% Match each `href` attribute in an `<a>` element
|
||||||
% 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 =|<book genre=...>|=
|
% xpath(DOM, //a(@href), HREF)
|
||||||
|
% ```
|
||||||
%
|
%
|
||||||
% ==
|
% Suppose we have a table containing rows where each first column
|
||||||
% thriller(DOM, Book) :-
|
% is the name of a product with a link to details and the second
|
||||||
% xpath(DOM, //book(@genre=thiller), Book).
|
% is the price (a number). The following predicate matches the
|
||||||
% ==
|
% name, URL and price:
|
||||||
%
|
%
|
||||||
% Match the elements =|<table align="center">|= _and_ =|<table
|
% ```
|
||||||
% align="CENTER">|=:
|
% 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).
|
||||||
|
% ```
|
||||||
%
|
%
|
||||||
% ```prolog
|
% Suppose we want to select books with genre="thriller" from a
|
||||||
% //table(@align(lower) = center)
|
% tree containing elements `<book genre=...>`
|
||||||
% ```
|
|
||||||
%
|
%
|
||||||
% Get the `width` and `height` of a `div` element as a number,
|
% ```
|
||||||
% and the `div` node itself:
|
% thriller(DOM, Book) :-
|
||||||
|
% xpath(DOM, //book(@genre=thiller), Book).
|
||||||
|
% ```
|
||||||
%
|
%
|
||||||
% ==
|
% Match the elements `<table align="center">` _and_ `<table
|
||||||
% xpath(DOM, //div(@width(number)=W, @height(number)=H), Div)
|
% align="CENTER">`:
|
||||||
% ==
|
|
||||||
%
|
%
|
||||||
% Note that `div` is an infix operator, so parentheses must be
|
% ```
|
||||||
% used in cases like the following:
|
% //table(@align(lower) = center)
|
||||||
|
% ```
|
||||||
%
|
%
|
||||||
% ==
|
% Get the `width` and `height` of a `div` element as a number,
|
||||||
% xpath(DOM, //(div), Div)
|
% 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)
|
||||||
|
% ```
|
||||||
|
|
||||||
xpath(DOM, Spec, Content) :-
|
xpath(DOM, Spec, Content) :-
|
||||||
in_dom(Spec, DOM, Content).
|
in_dom(Spec, DOM, Content).
|
||||||
|
|||||||
Reference in New Issue
Block a user