1 ;;; -*- show-trailing-whitespace: t; indent-tabs: nil -*-
3 ;;; Copyright (c) 2007,2008 David Lichteblau, Ivan Shvedunov.
4 ;;; All rights reserved.
6 ;;; Redistribution and use in source and binary forms, with or without
7 ;;; modification, are permitted provided that the following conditions
10 ;;; * Redistributions of source code must retain the above copyright
11 ;;; notice, this list of conditions and the following disclaimer.
13 ;;; * Redistributions in binary form must reproduce the above
14 ;;; copyright notice, this list of conditions and the following
15 ;;; disclaimer in the documentation and/or other materials
16 ;;; provided with the distribution.
18 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
19 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 (in-package :xuriella
)
32 (define-instruction xsl
:number
(args env
)
33 (destructuring-bind (&key level count from value format lang letter-value
34 grouping-separator grouping-size
)
36 (let ((count (and count
(compile-pattern count env
)))
37 (from (and from
(compile-pattern from env
)))
38 (value (and value
(compile-xpath value env
)))
39 (format (compile-avt (or format
"1") env
))
40 (lang (compile-avt (or lang
"") env
))
41 (letter-value (compile-avt (or letter-value
"foo") env
))
43 (and grouping-separator
(compile-avt grouping-separator env
)))
44 (grouping-size (and grouping-size
(compile-avt grouping-size env
))))
46 (let ((value (when value
47 (round (xpath:number-value
48 (funcall value ctx
)))))
49 (format (funcall format ctx
))
50 (lang (funcall lang ctx
))
51 (letter-value (funcall letter-value ctx
))
52 (grouping-separator (when grouping-separator
53 (funcall grouping-separator ctx
)))
54 (grouping-size (when grouping-size
55 (funcall grouping-size ctx
))))
59 (compute-number-list (or level
"single")
60 (xpath::context-node ctx
)
69 (defun compile-pattern (str env
)
72 (:path
(:ancestor-or-self
:node
) ,@(cdr (parse-pattern str
))))
75 (defun pattern-thunk-matches-p (pattern-thunk node
)
77 (xpath:all-nodes
(funcall pattern-thunk
(xpath:make-context node
)))))
79 (defun ancestors-using-count-and-from (node count from
)
82 (funcall (xpath::axis-function
:ancestor-or-self
) node
))))
83 (remove-if-not (lambda (ancestor)
84 (pattern-thunk-matches-p count ancestor
))
88 when
(pattern-thunk-matches-p from a
)
94 (defun node-position-among-siblings (node count
)
96 (count-if (lambda (sibling)
97 (pattern-thunk-matches-p count sibling
))
99 (funcall (xpath::axis-function
:preceding-sibling
) node
)))))
101 (defun compute-number-list (level node count from
)
104 (let ((qname (xpath-protocol:qualified-name node
)))
106 (let ((node (xpath:context-node ctx
)))
108 (if (equal (xpath-protocol:qualified-name node
) qname
)
112 ((equal level
"single")
113 (let ((ancestor (car (ancestors-using-count-and-from node count from
))))
115 (list (node-position-among-siblings ancestor count
))
117 ((equal level
"multiple")
118 (mapcar (lambda (ancestor)
119 (node-position-among-siblings ancestor count
))
121 (ancestors-using-count-and-from node count from
))))
123 (destructuring-bind (root)
124 (xpath::force
(funcall (xpath::axis-function
:root
) node
))
125 (let ((nodes (xpath::force
(funcall (xpath::axis-function
:descendant-or-self
) root
))))
128 for
(current . rest
) on nodes
129 until
(pattern-thunk-matches-p from current
)
130 finally
(setf nodes rest
)))
134 while
(pattern-thunk-matches-p count node
)
137 (xslt-error "invalid number level: ~A" level
))))
139 (defun format-number-list
140 (list format lang letter-value grouping-separator grouping-size
)
141 (declare (ignore lang letter-value
))
142 (if (equal format
"1")
143 (format nil
"~{~D~^.~}" list
)
144 (error "sorry, format-number-list not implemented yet")))