>From 1fc011f3c8d25c3a14db2d7f5e9ecb6627bc9102 Mon Sep 17 00:00:00 2001 From: rekado Date: Wed, 31 Dec 2014 16:48:32 +0100 Subject: [PATCH] doc: Add SXPath documentation from sources * doc/ref/sxml.texi (SXPath): Add procedure documentation from sources. --- doc/ref/sxml.texi | 295 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 261 insertions(+), 34 deletions(-) diff --git a/doc/ref/sxml.texi b/doc/ref/sxml.texi index 75867f3..2f9cd8d 100644 --- a/doc/ref/sxml.texi +++ b/doc/ref/sxml.texi @@ -250,8 +250,8 @@ internal and external parsed entities, user-controlled handling of whitespace, and validation. This module therefore is intended to be a framework, a set of ``Lego blocks'' you can use to build a parser following any discipline and performing validation to any degree. As an -example of the parser construction, this file includes a semi-validating -SXML parser. +example of the parser construction, the source file includes a +semi-validating SXML parser. SSAX has a ``sequential'' feel of SAX yet a ``functional style'' of DOM. Like a SAX parser, the framework scans the document only once and @@ -725,95 +725,322 @@ location path is a relative path applied to the root node. Similarly to XPath, SXPath defines full and abbreviated notations for location paths. In both cases, the abbreviated notation can be mechanically expanded into the full form by simple rewriting rules. In -case of SXPath the corresponding rules are given as comments to a sxpath -function, below. The regression test suite at the end of this file shows -a representative sample of SXPaths in both notations, juxtaposed with -the corresponding XPath expressions. Most of the samples are borrowed +case of SXPath the corresponding rules are given in the documentation of +the @code{sxpath} procedure. @xref{sxpath-procedure-docs,,SXPath +procedure documentation}. + +The regression test suite at the end of the file SXPATH-old.scm shows a +representative sample of SXPaths in both notations, juxtaposed with the +corresponding XPath expressions. Most of the samples are borrowed literally from the XPath specification, while the others are adjusted -for our running example, tree1. +for our running example, @code{tree1}. + + address@hidden Basic converters and applicators + +A converter is a function mapping a nodeset (or a single node) to another +nodeset. Its type can be represented like this: + address@hidden + type Converter = Node|Nodeset -> Nodeset address@hidden smallexample + +A converter can also play the role of a predicate: in that case, if a +converter, applied to a node or a nodeset, yields a non-empty nodeset, +the converter-predicate is deemed satisfied. Likewise, an empty nodeset +is equivalent to @code{#f} in denoting failure. address@hidden Usage @deffn {Scheme Procedure} nodeset? x +Return @code{#t} if @var{x} is a nodeset. @end deffn @deffn {Scheme Procedure} node-typeof? crit +This function implements a 'Node test' as defined in Sec. 2.3 of XPath +document. A node test is one of the components of a location step. It +is also a converter-predicate in SXPath. + +The function @code{node-typeof?} takes a type criterion and returns a +function, which, when applied to a node, will tell if the node satisfies +the test. + +The criterion @var{crit} is a symbol, one of the following: + address@hidden @code address@hidden id +tests if the node has the right name (id) + address@hidden @@ +tests if the node is an + address@hidden * +tests if the node is an + address@hidden *text* +tests if the node is a text node + address@hidden *PI* +tests if the node is a PI (processing instruction) node + address@hidden *any* address@hidden for any type of node address@hidden table @end deffn @deffn {Scheme Procedure} node-eq? other +A curried equivalence converter predicate that takes a node @var{other} +and returns a function that takes another node. The two nodes are +compared using @code{eq?}. @end deffn @deffn {Scheme Procedure} node-equal? other +A curried equivalence converter predicate that takes a node @var{other} +and returns a function that takes another node. The two nodes are +compared using @code{equal?}. @end deffn @deffn {Scheme Procedure} node-pos n +Select the @var{n}'th element of a nodeset and return as a singular +nodeset. If the @var{n}'th element does not exist, return an empty +nodeset. If @var{n} is a negative number the node is picked from the +tail of the list. + address@hidden +((node-pos 1) nodeset) ; return the the head of the nodeset (if exists) +((node-pos 2) nodeset) ; return the node after that (if exists) +((node-pos -1) nodeset) ; selects the last node of a non-empty nodeset +((node-pos -2) nodeset) ; selects the last but one node, if exists. address@hidden example @end deffn @deffn {Scheme Procedure} filter pred? address@hidden - -- Scheme Procedure: filter pred list - Return all the elements of 2nd arg LIST that satisfy predicate - PRED. The list is not disordered - elements that appear in the - result list occur in the same order as they occur in the argument - list. The returned list may share a common tail with the argument - list. The dynamic order in which the various applications of pred - are made is not specified. - - (filter even? '(0 7 8 8 43 -4)) => (0 8 8 -4) - - address@hidden verbatim +A filter applicator, which introduces a filtering context. The argument +converter @var{pred?} is considered a predicate, with either @code{#f} +or @code{nil} meaning failure. @end deffn @deffn {Scheme Procedure} take-until pred? address@hidden + take-until:: Converter -> Converter, or + take-until:: Pred -> Node|Nodeset -> Nodeset address@hidden smallexample + +Given a converter-predicate @var{pred?} and a nodeset, apply the +predicate to each element of the nodeset, until the predicate yields +anything but @code{#f} or @code{nil}. Return the elements of the input +nodeset that have been processed until that moment (that is, which fail +the predicate). + address@hidden is a variation of the @code{filter} above: address@hidden passes elements of an ordered input set up to (but not +including) the first element that satisfies the predicate. The nodeset +returned by @code{((take-until (not pred)) nset)} is a subset -- to be +more precise, a prefix -- of the nodeset returned by @code{((filter +pred) nset)}. @end deffn @deffn {Scheme Procedure} take-after pred? address@hidden + take-after:: Converter -> Converter, or + take-after:: Pred -> Node|Nodeset -> Nodeset address@hidden smallexample + +Given a converter-predicate @var{pred?} and a nodeset, apply the +predicate to each element of the nodeset, until the predicate yields +anything but @code{#f} or @code{nil}. Return the elements of the input +nodeset that have not been processed: that is, return the elements of +the input nodeset that follow the first element that satisfied the +predicate. + address@hidden along with @code{take-until} partition an input +nodeset into three parts: the first element that satisfies a predicate, +all preceding elements and all following elements. @end deffn @deffn {Scheme Procedure} map-union proc lst +Apply @var{proc} to each element of @var{lst} and return the list of results. +If @var{proc} returns a nodeset, splice it into the result + +From another point of view, @code{map-union} is a function address@hidden>Converter}, which places an argument-converter in a joining +context. @end deffn @deffn {Scheme Procedure} node-reverse node-or-nodeset address@hidden + node-reverse :: Converter, or + node-reverse:: Node|Nodeset -> Nodeset address@hidden smallexample + +Reverses the order of nodes in the nodeset. This basic converter is +needed to implement a reverse document order (see the XPath +Recommendation). @end deffn @deffn {Scheme Procedure} node-trace title address@hidden + node-trace:: String -> Converter address@hidden smallexample + address@hidden(node-trace title)} is an identity converter. In addition it +prints out the node or nodeset it is applied to, prefixed with the address@hidden This converter is very useful for debugging. @end deffn address@hidden Converter combinators + +Combinators are higher-order functions that transmogrify a converter or +glue a sequence of converters into a single, non-trivial converter. The +goal is to arrive at converters that correspond to XPath location paths. + +From a different point of view, a combinator is a fixed, named address@hidden of applying converters. Given below is a complete set of +such patterns that together implement XPath location path specification. +As it turns out, all these combinators can be built from a small number +of basic blocks: regular functional composition, @code{map-union} and address@hidden applicators, and the nodeset union. + @deffn {Scheme Procedure} select-kids test-pred? address@hidden takes a converter (or a predicate) as an argument and +returns another converter. The resulting converter applied to a nodeset +returns an ordered subset of its children that satisfy the predicate address@hidden @end deffn @deffn {Scheme Procedure} node-self pred? address@hidden - -- Scheme Procedure: filter pred list - Return all the elements of 2nd arg LIST that satisfy predicate - PRED. The list is not disordered - elements that appear in the - result list occur in the same order as they occur in the argument - list. The returned list may share a common tail with the argument - list. The dynamic order in which the various applications of pred - are made is not specified. - - (filter even? '(0 7 8 8 43 -4)) => (0 8 8 -4) - - address@hidden verbatim +Similar to @code{select-kids} except that the predicate @var{pred?} is +applied to the node itself rather than to its children. The resulting +nodeset will contain either one component, or will be empty if the node +failed the predicate. @end deffn @deffn {Scheme Procedure} node-join . selectors address@hidden + node-join:: [LocPath] -> Node|Nodeset -> Nodeset, or + node-join:: [Converter] -> Converter address@hidden smallexample + +Join the sequence of location steps or paths as described above. @end deffn @deffn {Scheme Procedure} node-reduce . converters address@hidden + node-reduce:: [LocPath] -> Node|Nodeset -> Nodeset, or + node-reduce:: [Converter] -> Converter address@hidden smallexample + +A regular functional composition of converters. From a different point +of view, @code{((apply node-reduce converters) nodeset)} is equivalent +to @code{(foldl apply nodeset converters)}, i.e., folding, or reducing, +a list of converters with the nodeset as a seed. @end deffn @deffn {Scheme Procedure} node-or . converters address@hidden + node-or:: [Converter] -> Converter address@hidden smallexample + +This combinator applies all converters to a given node and produces the +union of their results. This combinator corresponds to a union +(@code{|} operation) for XPath location paths. @end deffn @deffn {Scheme Procedure} node-closure test-pred? address@hidden + node-closure:: Converter -> Converter address@hidden smallexample + +Select all @emph{descendants} of a node that satisfy a +converter-predicate @var{test-pred?}. This combinator is similar to address@hidden but applies to grand... children as well. This +combinator implements the @code{descendant::} XPath axis. Conceptually, +this combinator can be expressed as + address@hidden +(define (node-closure f) + (node-or + (select-kids f) + (node-reduce (select-kids (node-typeof? '*)) (node-closure f)))) address@hidden smallexample + +This definition, as written, looks somewhat like a fixpoint, and it will +run forever. It is obvious however that sooner or later address@hidden(select-kids (node-typeof? '*))} will return an empty nodeset. At +this point further iterations will no longer affect the result and can +be stopped. @end deffn @deffn {Scheme Procedure} node-parent rootnode address@hidden + node-parent:: RootNode -> Converter address@hidden smallexample + address@hidden(node-parent rootnode)} yields a converter that returns a parent +of a node it is applied to. If applied to a nodeset, it returns the +list of parents of nodes in the nodeset. The @var{rootnode} does not +have to be the root node of the whole SXML tree -- it may be a root node +of a branch of interest. + +Given the notation of Philip Wadler's paper on semantics of XSLT, + address@hidden + parent(x) = { y | y=subnode*(root), x=subnode(y) } address@hidden verbatim + +Therefore, @code{node-parent} is not the fundamental converter: it can +be expressed through the existing ones. Yet @code{node-parent} is a +rather convenient converter. It corresponds to a @code{parent::} axis +of SXPath. Note that the @code{parent::} axis can be used with an +attribute node as well. @end deffn address@hidden @deffn {Scheme Procedure} sxpath path +Evaluate an abbreviated SXPath. + address@hidden + sxpath:: AbbrPath -> Converter, or + sxpath:: AbbrPath -> Node|Nodeset -> Nodeset address@hidden smallexample + address@hidden is a list. It is translated to the full SXPath according to +the following rewriting rules: + address@hidden +(sxpath '()) address@hidden (node-join) + +(sxpath '(path-component ...)) address@hidden (node-join (sxpath1 path-component) (sxpath '(...))) + +(sxpath1 '//) address@hidden (node-or + (node-self (node-typeof? '*any*)) + (node-closure (node-typeof? '*any*))) + +(sxpath1 '(equal? x)) address@hidden (select-kids (node-equal? x)) + +(sxpath1 '(eq? x)) address@hidden (select-kids (node-eq? x)) + +(sxpath1 ?symbol) address@hidden (select-kids (node-typeof? ?symbol) + +(sxpath1 procedure) address@hidden procedure + +(sxpath1 '(?symbol ...)) address@hidden (sxpath1 '((?symbol) ...)) + +(sxpath1 '(path reducer ...)) address@hidden (node-reduce (sxpath path) (sxpathr reducer) ...) + +(sxpathr number) address@hidden (node-pos number) + +(sxpathr path-filter) address@hidden (filter (sxpath path-filter)) address@hidden example @end deffn @node sxml ssax input-parse -- 2.1.0