| Description | Hierarchy | Fields | Methods | Properties |
type TXQueryEngine = class(TObject)
This is the XPath/XQuery-engine
You can use this class to evaluate a XPath/XQuery-expression on a certain document tree.
For example, TXQueryEngine.evaluateStaticXPath2('expression', nil) returns the value of the evaluation of expression.
Syntax of a XQuery / XPath / Pseudo-XPath-Expression
This XQuery engine currently supports XPath 2.0, XQuery 1.0 and JSONiq, with some extensions and minor deviations.
Some very basic, standard XPath examples, for people who do not have seen XPath before:
"something" or "something"
This returns the string 'something'.
$var
This returns the value of the variable var.
a + b
This returns the numerical sum of a and b
Instead of +, you can also use one of operators -, *, div, idiv, =, !=, <, >, <=, =>, to, or, and, eq, ne, lt, gt, le, ge
1245.567
This returns the number 1245.567
concat("a","b","c")
This concatenates the strings a,b and c.
There are many more functions than concat, you can look them up in a XPath reference
(1,2,3)
This returns a sequence (1,2,3).
Sequences can not be nested.
(1,2,3)[. mod 2 = 1]
This returns the sequence (1,3) of all odd numbers.
@attrib
This is the value of the attribute attrib of the current tag
text()
This returns a sequence of all direct text node children of the current tag (see below)
comment()
This returns a sequence of all direct comment children of the current tag
xyz
This returns a sequence of all direct children of the current tag whose node name is xyz
.//xyz
This returns a sequence of all children of the current tag whose node name is xyz
abc/def
This returns a sequence of all children of the current tag whose name is def and whose parent has the name abc and is a direct child of the current tag
abc//def
This returns a sequence of all children of the current tag whose name is def and whose parent has the name abc
/html
This returns a the html root tag
/html//text()
This returns all text nodes in the current html document
/html//.[condition]/text()
This returns all text nodes in the current html document whose parent satisfies condition
for $x in seq return $x + 1
This adds 1 to all elements in the sequence seq
some $x in seq satisfies condition
This returns true iff one element of seq satisfies condition
every $x in seq satisfies condition
This returns true iff every element of seq satisfies condition
if (condition) then $x else $y
This returns $x if condition is true, and $y otherwise
Differences between this implementation and standard XPath/XQuery (most differences can be turned off with the respective option or the field in the default StaticContext):
Extended syntax:
x"something{$var}{1+2+3}..."
If a string is prefixed with an x, all expressions within {..}-parenthesis are evaluated and concattenated to the raw text, similarily to the value of a xquery direct attribute constructor. (option: extended-strings)
var:=value
This assigns the value value to the global variable var and returns value
So you can e.g. write ((a := 2) + 3) and get 5 and a variable a with the value 2
All string comparisons are case insensitive, and "clever", e.g. '9xy' = '9XY' < '10XY' < 'xy',
unless you use collations.
The default type system is weaker typed, most values are automatically converted if necessary, e.g. "1" + 2 returns 3.
(option: strict-type-checking)
If a namespace prefix is unknown, the namespace is resolved using the current context item.
This basically allows you to do namespace prefix only matching. (option: use-local-namespaces)
JSON-objects: JSON/JSONiq objects are supported. (option: json)
Arrays can be created with [a,b,c]
Like a sequence they store a list of values, and can be nested with each other and within sequences.
Object can be created with {"foobar": 123, "hallo": "world!", ...}
They stores a set of values as associative map. The values can be accessed similar to a function call, e.g.: {"name": value, ...}("name").
This implementation also provides an alternative property syntax, where these properties can be accessed with the usual OOP property dot syntax, i.e. {"name": 123}.name will evaluate to 123 (can be changed with the option property-dot-notation).
If an object is assigned to a variable, you can append the dot to the variable name, e.g. let $obj := {"name": 123} return $obj.name. (drawback: variable names are not allowed to contains dots, if this extension is enabled)
Objects are immutable, but the properties of objects that are global variables can seemingly be changed with $obj.property := newvalue. This creates a new object with name $obj that has all the properties of the old objects plus the changed properties.
Objects can be assigned to each other (e.g. obj1 := {}, obj2 := {}, obj2.prop := 123, obj1.sub := obj2 ).
Then obj1.sub.prop = 123, but changing obj1.sub.prop won't change obj2.prop (i.e. the objects are always copied, there are no pointers).
An alternative, older object creation syntax is the object-function (see below).
At default all values are allowed as object properties. If the option pure-json-objects is enabled, property values are converted to pure JSON types. (empty sequence => null, sequences => array, nodes => string)
The additional module xquery_json implements all JSONiq functions, except JSONiq update and roundtrip-serialization.
Using it also activates the JSONiq literal mode, in which true, false, null evaluate to true(), false(), jn:null(). (option: json-literals).
Element tests based on types of the xml are not supported (since it can not read schemas )
Regex remarks:
The usual s/i/m/x-flags are allowed, and you can also use '-g' to disable greedy matching.
$0 and $& can be used as substitute for the whole regex, and $i or ${i} is substituted with the i-th submatch, for any integer i. Therefore $12 is match 12, while ${1}2 is match 1 followed by digit 2
Most of them can be disabled with 'declare option pxp:respective-option "off"' (that there are syntax modifying options is another extension)
New functions:
deep-text()
This is the concatenated plain text of the every tag inside the current text. You can also pass a separator like deep-text(' ') to separate text of different nodes.
extract($string as xs:string, $regex as xs:string [, $match as xs:integer,[$flags as xs:string]])
This applies the regex $regex to $string and returns only the matching part. If the $match argument is used, only the $match-th submatch will be returned
(This functions used to be called filter, but was renamed to due to XQuery 3)
eval($query as xs:string)
This evaluates $query as a XQuery-expression.
css($css as xs:string)
This evaluates the $css string as a css selector.
parse-date($input as xs:string, $format as xs:string)
Reads a date/time from string with the given format. $format is a standard Pascal format, using ymdhnsz (e.g. "yyyy-mm-dd"), not a XQuery 3.0 picture string.
parse-time(input as xs:string, $format as xs:string)
Reads a date/time from string with the given format. $format is a standard Pascal format (see above)
parse-datetime($input as xs:string, $format as xs:string)
Reads a date/time from string with the given format. $format is a standard Pascal format (see above)
inner-xml($node as node())
Returns the inner xml of a node as string (like innerHTML in javascript)
outer-xml($node as node())
Returns the outer xml of a node as string (= inner-xml plus the opening/closing tag of the node itself)
inner-html($node as node())
Returns the inner html of a node as string (like inner-xml, but valid html)
outer-html($node as node())
Returns the outer html of a node as string (like outer-xml, but valid html)
form($form as node()*[, $override as item()*])
This creates the request corresponding to a html form. The request includes the value of all input/select/textarea descendants of the $form parameter.
You can use the $override parameter to give a sequence of values replacing the default values of the form elements.
A value is either a string, e.g. "name=value&name2=..." which has to be url encoded and is splitted at the &-separators to override each parameter separately. (so the order of the name=value pairs is changed to the order of the input elements in the form)
Or a JSON-like object {"name": "value", ...}, in which the properties must not be url encodeded (i.e. the form method url encodes each property) and in which each property overrides the corresponding parameter.
It returns a JSON object with these properties:
url: The url the form should be send to (includes the encoded data for a GET request)
method: POST or GET
post: Url encoded post data (in future versions it might be multipart-encoded, if enctype is set correspondingly)
is-nth($i as xs:integer, $a as xs:integer, $b as xs:integer)
Returns true iff the equation i = a * n + b can be solved by an non-negative integer n. (This is used to implement the css functions like nth-child )
var := object()
This creates an object with name $var. Default values can be passed as sequence of name/value pairs.
A alternative syntax is {}
get-property($obj as object(), $name as xs:string)
Returns the property with the given name of an object. Since this is just a normal function, it can also be used, if the object.property syntax has been disabled
Deprecated, now the JSONiq syntax $obj($name) should be used. This function may be removed in later versions.
join($sequence as xs:item()*[, $seperator as xs:string])
This is the same as string-join, but without type checking. If seperator is omitted it becomes " ".
match($template as item(), $node as node()+)
Performs pattern matching between the template and the nodes, and returns a list or an object of matched values.
E.g. match(<a>{{.}}</a>, <x><a>FOO</a><a>BAR</a></x>) returns <a>FOO</a>, and match(<a>*{{.}}</a>, <x><a>FOO</a><a>BAR</a></x>) returns (<a>FOO</a>, <a>BAR</a>)
It is also possible to use named variables in the template, in which case an object is returned, e.g: match(<x><a>{{first:=.}}</a><a>{{second:=.}}</a></x>, <x><a>FOO</a><a>BAR</a></x>) returns an object with two properties first and bar, containing <a>FOO</a> and <a>BAR</a> respectively. These properties can be accessed like match(<x><a>{{first:=.}}</a><a>{{second:=.}}</a></x>, <x><a>FOO</a><a>BAR</a></x>).first
Multiple values assigned to the same variable are merged into a single sequence, e.g. match(<x><a>{{res:=.}}</a><a>{{res:=.}}</a></x>, <x><a>FOO</a><a>BAR</a></x>) returns an object with a single property res with value (<a>FOO</a>, <a>BAR</a>)
If unnamed and named variables are mixed, the unnamed variables are treated like variables with the name _result.
The template can be a node or a string. Written as string the example above would be match("<a>{.}</a>", <x><a>FOO</a><a>BAR</a></x>).
You can pass multiple templates and nodes, in which case each template is applied to each node, and the result of all matching calls is returned in a single sequence.
If the template can not be matched, an error is raised.
see THtmlTemplateParser for the full template reference. (This function is not actually declared in xquery.pas, but in extendedhtmlparser.pas, so it is only available if latter unit is included in any uses clause. )
json($source as xs:string)
Reads a json object/value from a string and converts it to an object/value (see object extension above).
If the string is an url the json is loaded from there (i.e. be aware of possible security issues when using it. jn:parse-json from xquery_json / JSONiq will only parse it)
Only available if the xquery_json unit is included in an uses clause.
serialize-json($object as item()* )
Converts an xq value to a json string.
Only available if the xquery_json unit is included in an uses clause.
All above functions belong to the namespace "http://www.benibela.de/2012/pxp/extensions", which is at default bound to the prefixes "pxp" and "". This namespace also contains a copy of all standard XPath function
You can look at the unit tests in the tests directory to see many (> 3000) examples.
Using the class in FPC
The easiest way to evaluate a XQuery/XPath-expression is to call the class methods like TXQueryEngine.evaluateStaticXPath2('expression', nil) or TXQueryEngine.evaluateStaticXPath2('expression', nil).toInt64 which returns the value of the expression, converted to the corresponding type.
If you want to process a html/xml document, you have to pass the root TTreeNode (obtained by TTreeParser) instead of nil.
If you call TXQueryEngine.evaluateStaticXPath2('expression', nil) without a following toType-call, you obtain the result as an IXQValue. (see IXQValue on how to use it)
With a toType-call it is converted in the corresponding type, e.g. toInt64 returns a int64, toString a string, toNode a TTreeNode or toDecimal an extended.
You can also create a TXQueryEngine instance and then call parseXPath2('expression') and evaluateXPath2().
This is not as easy, but you have more options:
For the basic you can set separate root (/) (with the property RootElement) and parent elements (./) (with the property ParentElement), or you can read and define variables in the expression, or change other behaviours.
Compatibility to previous version
The following breaking changes occured to make it more standard compatible:
Language changes:
Variables are no longer replaced inside "-strings. Instead x"-strings were added. All old uses of "$var;" therefore have to be replaced by x"{$var}"
All string comparisons are now (non-localized ascii) case-insensitive, not only equal comparisons (as always mentioned in the documentation)
Variables defined by a PXPath expression inside an PXPath eval call are exported to the outside
== is no longer allowed as alias to =
the function deepNodeText is now called deep-text
regex flag s defaults to off
API changes to previous versions:
everything has been renamed, pseudoxpath.pas => xquery.pas, TPseudoXPathParser => TXQueryEngine, TPXPValue => IXQValue
The TPXPValue class has been replaced by an interface => memory deallocation has become implicit and .free must not be called.
=> functions like toString and asString become identically and latter has been removed. Similarly functions like getValueAsString() are not needed anymore and have been removed as well
TPXPValue is now a class with subclasses instead of a case record
Some things have been renamed, the new names should be obvious
The evaluate functions return now a TPXPValue instead of a string, since they may return a typed value or sequence.
![]() |
procedure clear; |
![]() |
function parseXPath2(s:string; sharedContext: TXQStaticContext = nil): IXQuery; |
![]() |
function parseXQuery1(s:string; sharedContext: TXQStaticContext = nil): IXQuery; |
![]() |
function parseCSS3(s:string): IXQuery; |
![]() |
function evaluate(tree:TTreeNode = nil): IXQValue; |
![]() |
constructor create; |
![]() |
destructor Destroy; override; |
![]() |
function evaluateXPath2(expression: string; tree:TTreeNode = nil): IXQValue; |
![]() |
function evaluateXQuery1(expression: string; tree:TTreeNode = nil): IXQValue; |
![]() |
function evaluateCSS3(expression: string; tree:TTreeNode = nil): IXQValue; |
![]() |
class function evaluateStaticXPath2(expression: string; tree:TTreeNode = nil): IXQValue; |
![]() |
class function evaluateStaticCSS3(expression: string; tree:TTreeNode = nil): IXQValue; |
![]() |
procedure registerModule(module: IXQuery); |
![]() |
function findModule(const namespaceURL: string): TXQuery; |
![]() |
class function findNativeModule(const ns: string): TXQNativeModule; |
![]() |
class procedure registerCollation(const collation: TXQCollation); |
![]() |
class function getCollation(id:string; base: string): TXQCollation; |
![]() |
class procedure registerNativeModule(const module: TXQNativeModule); |
![]() |
property LastQuery: IXQuery read FLastQuery; |
![]() |
RootElement: TTreeNode; |
|
Root element | |
![]() |
ParentElement: TTreeNode; |
|
Set this to the element you want as current. The XPath expressions will be evaluated relative to this, so e.g. | |
![]() |
TextElement: TTreeNode; |
|
Use this to override the text node returned by text(). This is useful if you have an element <a>xx<b/>yy</a>. If TextNode is nil text() will return xx, but you can set it to yy. However, ./text() will always return xx. | |
![]() |
CurrentDateTime: TDateTime; |
|
Current time | |
![]() |
ImplicitTimezone: TDateTime; |
|
Local timezone (nan = unknown, 0 = utc). | |
![]() |
StaticContext: TXQStaticContext; |
|
XQuery static context, defining various default values. | |
![]() |
VariableChangelog: TXQVariableChangeLog; |
|
All global variables that have been set (if a variable was overriden, it stores the old and new value) | |
![]() |
OnEvaluateVariable: TXQEvaluateVariableEvent; |
|
Event called if a variable has to be read. (Defaults to @VariableChangelog.evaluateVariable, but can be changed) | |
![]() |
OnDefineVariable: TXQDefineVariableEvent; |
|
Event called if a variable is set (Defaults to @VariableChangelog.defineVariable, but can be changed) | |
![]() |
OnDeclareExternalVariable: TXQDeclareExternalVariableEvent; |
|
Event called to import a variable that is declared as "declare variable ... external" in a XQuery expression | |
![]() |
OnDeclareExternalFunction: TXQDeclareExternalFunctionEvent; |
|
Event called to import a function that is declared as "declare function ... external" in a XQuery expression. | |
![]() |
OnImportModule: TXQImportModuleEvent; |
|
Event called to import a XQuery module that has not previously be defined | |
![]() |
OnTrace: TXQTraceEvent; |
|
Event called by fn:trace | |
![]() |
OnCollection: TXQEvaluateVariableEvent; |
|
Event called by fn:collection | |
![]() |
OnParseDoc: TXQParseDocEvent; |
|
Event called by fn:doc (if nil, a default xml parser is used) | |
![]() |
AllowExtendedStrings: boolean; |
|
If strings with x-prefixes are allowed, like x"foo{$variable}bar" to embed xquery expressions in strings | |
![]() |
AllowJSON: boolean; |
|
If {"foo": bar} and [..] can be used to create json objects/arrays (default false, unless xquery_json was loaded, then it is true) | |
![]() |
AllowJSONLiterals: boolean; |
|
If true/false/null literals are treated like true()/false()/jn:null() (default true! However, this option is ignored and handled as false, if allowJSON is false). | |
![]() |
GlobalNamespaces: TNamespaceList; |
|
Globally defined namespaces | |
![]() |
AutomaticallyRegisterParsedModules: boolean; |
![]() |
procedure clear; |
|
Clears all data. | |
![]() |
function parseXPath2(s:string; sharedContext: TXQStaticContext = nil): IXQuery; |
|
Parses a new XPath 2.0 expression and stores it in tokenized form. | |
![]() |
function parseXQuery1(s:string; sharedContext: TXQStaticContext = nil): IXQuery; |
|
Parses a new XQuery expression and stores it in tokenized form. | |
![]() |
function parseCSS3(s:string): IXQuery; |
|
Parses a new CSS 3.0 Selector expression and stores it in tokenized form. | |
![]() |
function evaluate(tree:TTreeNode = nil): IXQValue; |
|
Evaluates a previously parsed query and returns its value as TXQValue | |
![]() |
constructor create; |
![]() |
destructor Destroy; override; |
![]() |
function evaluateXPath2(expression: string; tree:TTreeNode = nil): IXQValue; |
|
Evaluates an XPath 2.0 expression with a certain tree element as current node. | |
![]() |
function evaluateXQuery1(expression: string; tree:TTreeNode = nil): IXQValue; |
|
Evaluates an XQuery 1.0 expression with a certain tree element as current node. | |
![]() |
function evaluateCSS3(expression: string; tree:TTreeNode = nil): IXQValue; |
|
Evaluates an CSS 3 Selector expression with a certain tree element as current node. | |
![]() |
class function evaluateStaticXPath2(expression: string; tree:TTreeNode = nil): IXQValue; |
|
Evaluates an expression with a certain tree element as current node. | |
![]() |
class function evaluateStaticCSS3(expression: string; tree:TTreeNode = nil): IXQValue; |
|
Evaluates an expression with a certain tree element as current node. | |
![]() |
procedure registerModule(module: IXQuery); |
|
Registers an XQuery module. A XQuery module is created by parsing (not evaluating) a XQuery expression that contains a "module" declaration | |
![]() |
function findModule(const namespaceURL: string): TXQuery; |
|
Finds a certain registered XQuery module | |
![]() |
class function findNativeModule(const ns: string): TXQNativeModule; |
|
Finds a native module. | |
![]() |
class procedure registerCollation(const collation: TXQCollation); |
|
Registers a collation for custom string comparisons | |
![]() |
class function getCollation(id:string; base: string): TXQCollation; |
|
Returns the collation for an url id | |
![]() |
class procedure registerNativeModule(const module: TXQNativeModule); |
![]() |
property LastQuery: IXQuery read FLastQuery; |
|
Last parsed query | |