1 ;;; -*- show-trailing-whitespace: t; indent-tabs: nil -*-
3 ;;; Copyright (c) 2007 David Lichteblau. All rights reserved.
5 ;;; Redistribution and use in source and binary forms, with or without
6 ;;; modification, are permitted provided that the following conditions
9 ;;; * Redistributions of source code must retain the above copyright
10 ;;; notice, this list of conditions and the following disclaimer.
12 ;;; * Redistributions in binary form must reproduce the above
13 ;;; copyright notice, this list of conditions and the following
14 ;;; disclaimer in the documentation and/or other materials
15 ;;; provided with the distribution.
17 ;;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR 'AS IS' AND ANY EXPRESSED
18 ;;; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 ;;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 ;;; ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
21 ;;; DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 ;;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23 ;;; GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 ;;; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 ;;; WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 ;;; NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 ;;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 (in-package :xuriella
)
31 (defun map-namespace-declarations (fn element
)
32 (let ((parent (stp:parent element
)))
33 (maphash (lambda (prefix uri
)
34 (unless (and (typep parent
'stp
:element
)
35 (equal (stp:find-namespace prefix parent
) uri
))
36 (funcall fn prefix uri
)))
37 (cxml-stp-impl::collect-local-namespaces element
))))
39 (defun maybe-wrap-namespaces (child exprs
)
40 (if (typep child
'stp
:element
)
43 (map-namespace-declarations (lambda (prefix uri
)
44 (push (list prefix uri
) bindings
))
46 (stp:with-attributes
((erp "exclude-result-prefixes" *xsl
*))
48 (dolist (prefix (words (or erp
"")))
49 (when (equal prefix
"#default")
51 (push (or (stp:find-namespace prefix child
)
52 (xslt-error "namespace not found: ~A" prefix
))
55 `((xsl:with-namespaces
,bindings
56 (xsl:with-excluded-namespaces
,excluded-uris
61 (defun parse-body (node &optional
(start 0) (param-names '()))
62 (let ((n (stp:count-children-if
#'identity node
)))
65 (let ((child (stp:nth-child i node
)))
66 (maybe-wrap-namespaces
68 (if (namep child
"variable")
69 (stp:with-attributes
(name select
) child
70 (when (and select
(stp:list-children child
))
71 (xslt-error "variable with select and body"))
72 `((let ((,name
,(or select
73 `(progn ,@(parse-body child
)))))
74 (xsl:with-duplicates-check
(,name
)
75 ,@(recurse (1+ i
))))))
76 (cons (parse-instruction child
)
77 (recurse (1+ i
)))))))))
78 (let ((result (recurse start
)))
80 `((xsl:with-duplicates-check
(,@param-names
)
84 (defun parse-param (node)
86 (stp:with-attributes
(name select
) node
88 (xslt-error "name not specified for parameter"))
89 (when (and select
(stp:list-children node
))
90 (xslt-error "param with select and body"))
93 `(progn ,@(parse-body node
))))))
95 (defun parse-instruction (node)
98 (if (equal (stp:namespace-uri node
) *xsl
*)
99 (parse-instruction/xsl-element
100 (or (find-symbol (stp:local-name node
) :xuriella
)
101 (xslt-error "undefined instruction: ~A" (stp:local-name node
)))
103 (parse-instruction/literal-element node
)))
105 `(xsl:text
,(stp:data node
)))))
107 (defun parse-instruction/literal-element
(node)
108 `(xsl:literal-element
109 (,(stp:local-name node
)
110 ,(stp:namespace-uri node
)
111 ,(stp:namespace-prefix node
))
112 ,@(stp:map-attributes
'list
114 `(xsl:literal-attribute
116 ,(stp:namespace-uri a
)
117 ,(stp:namespace-prefix a
))
120 ,@(parse-body node
)))
122 (defmacro define-instruction-parser
(name (node-var) &body body
)
123 `(defmethod parse-instruction/xsl-element
124 ((.name.
(eql ',name
)) ,node-var
)
125 (declare (ignore .name.
))
128 (define-instruction-parser |apply-templates|
(node)
129 (stp:with-attributes
(select mode
) node
130 (multiple-value-bind (decls rest
)
133 for cons on
(stp:list-children node
)
134 for
(child . nil
) = cons
135 while
(namep child
"sort")
136 collect
(parse-sort child
) into decls
137 finally
(return (values decls cons
)))
138 `(xsl:apply-templates
139 (:select
,select
:mode
,mode
)
141 ,@(mapcar (lambda (clause)
142 (unless (namep clause
"with-param")
143 (xslt-error "undefined instruction: ~A"
144 (stp:local-name clause
)))
145 (parse-param clause
))
148 (define-instruction-parser |call-template|
(node)
149 (stp:with-attributes
(name) node
151 ,name
,@(stp:map-children
'list
153 (if (namep clause
"with-param")
155 (xslt-error "undefined instruction: ~A"
156 (stp:local-name clause
))))
159 (define-instruction-parser |if|
(node)
160 (stp:with-attributes
(test) node
162 ,@(parse-body node
))))
164 (define-instruction-parser |choose|
(node)
166 ,@(stp:map-children
'list
169 ((namep clause
"when")
170 (stp:with-attributes
(test) clause
172 ,@(parse-body clause
))))
173 ((namep clause
"otherwise")
174 `(t ,@(parse-body clause
)))
176 (xslt-error "invalid <choose> clause: ~A"
177 (stp:local-name clause
)))))
180 (define-instruction-parser |element|
(node)
181 (stp:with-attributes
(name namespace use-attribute-sets
) node
182 `(xsl:element
(,name
:namespace
,namespace
183 :use-attribute-sets
,use-attribute-sets
)
184 ,@(parse-body node
))))
186 (define-instruction-parser |attribute|
(node)
187 (stp:with-attributes
(name namespace
) node
188 `(xsl:attribute
(,name
:namespace
,namespace
)
189 ,@(parse-body node
))))
191 (define-instruction-parser |text|
(node)
192 `(xsl:text
,(stp:string-value node
)))
194 (define-instruction-parser |comment|
(node)
195 `(xsl:comment
,@(stp:string-value node
)))
197 (define-instruction-parser |processing-instruction|
(node)
198 (stp:with-attributes
(name) node
199 `(xsl:processing-instruction
,name
200 ,@(parse-body node
))))
202 (define-instruction-parser |value-of|
(node)
203 (stp:with-attributes
(select disable-output-escaping
) node
204 (if disable-output-escaping
205 `(xsl:unescaped-value-of
,select
)
206 `(xsl:value-of
,select
))))
208 (define-instruction-parser |copy-of|
(node)
209 (stp:with-attributes
(select) node
210 `(xsl:copy-of
,select
)))
212 (define-instruction-parser |copy|
(node)
213 (stp:with-attributes
(use-attribute-sets) node
214 `(xsl:copy
(:use-attribute-sets
,use-attribute-sets
)
215 ,@(parse-body node
))))
217 (define-instruction-parser |variable|
(node)
218 (xslt-error "unhandled xsl:variable"))
220 (define-instruction-parser |for-each|
(node)
221 (stp:with-attributes
(select) node
222 (multiple-value-bind (decls body-position
)
225 for child in
(stp:list-children node
)
226 while
(namep child
"sort")
227 collect
(parse-sort child
) into decls
228 finally
(return (values decls i
)))
229 `(xsl:for-each
,select
231 ,@(parse-body node body-position
)))))
233 (defun parse-sort (node)
234 (stp:with-attributes
(select lang data-type order case-order
) node
235 `(sort :select
,select
237 :data-type
,data-type
239 :case-order
,case-order
)))
241 (define-instruction-parser |message|
(node)
242 `(xsl:message
,@(parse-body node
)))
244 (define-instruction-parser |terminate|
(node)
245 `(xsl:terminate
,@(parse-body node
)))