1 ;;; -*- show-trailing-whitespace: t; indent-tabs: nil -*-
3 ;;; Copyright (c) 2007 Ivan Shvedunov. All rights reserved.
4 ;;; Copyright (c) 2007 David Lichteblau. 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.
31 (in-package :cxml-stp-impl
)
33 (defun vector->pipe
(vector &optional
(start 0))
34 (if (>= start
(length vector
))
36 (xpath::make-pipe
(elt vector start
)
37 (vector->pipe vector
(1+ start
)))))
40 ;;;; XPath protocol implementation for STP
42 ;;;; FIXME: xpath-protocol:child-pipe destructively normalizes the STP tree!
44 (define-default-method xpath-protocol
:local-name
((node stp
:node
))
47 (define-default-method xpath-protocol
:namespace-prefix
((node stp
:node
))
48 (namespace-prefix node
))
50 (define-default-method xpath-protocol
:parent-node
((node stp
:node
))
53 (define-default-method xpath-protocol
:namespace-uri
((node stp
:node
))
56 (define-default-method xpath-protocol
:qualified-name
((node stp
:node
))
57 (qualified-name node
))
59 (define-default-method xpath-protocol
:base-uri
((node stp
:element
))
62 (define-default-method xpath-protocol
:base-uri
((node stp
:document
))
65 (define-default-method xpath-protocol
:base-uri
((node stp
:node
))
68 (define-default-method xpath-protocol
:child-pipe
((node stp
:node
))
71 (define-default-method xpath-protocol
:child-pipe
((node stp
:document
))
72 (filter-children (alexandria:of-type
'(not document-type
)) node
))
74 (define-default-method xpath-protocol
:child-pipe
((node stp
:element
))
75 (normalize-text-nodes! node
)
76 (vector->pipe
(%children node
)))
78 (define-default-method xpath-protocol
:attribute-pipe
((node stp
:node
))
81 (define-default-method xpath-protocol
:attribute-pipe
((node stp
:element
))
82 (list-attributes node
))
84 (define-default-method xpath-protocol
:namespace-pipe
((node stp
:node
))
85 (when (stp:parent node
)
86 (xpath-protocol:namespace-pipe
(stp:parent node
))))
88 (defstruct (stp-namespace
89 (:constructor make-stp-namespace
(parent prefix uri
)))
94 (define-default-method xpath-protocol
:node-equal
95 ((a stp-namespace
) (b stp-namespace
))
96 (and (eq (stp-namespace-parent a
) (stp-namespace-parent b
))
97 (equal (stp-namespace-prefix a
) (stp-namespace-prefix b
))))
99 (define-default-method xpath-protocol
:hash-key
100 ((node stp-namespace
))
101 (cons (stp-namespace-parent node
) (stp-namespace-prefix node
)))
103 (define-default-method xpath-protocol
:base-uri
((node stp-namespace
))
106 (define-default-method xpath-protocol
:node-p
((node stp-namespace
))
109 (define-default-method xpath-protocol
:child-pipe
((node stp-namespace
)) nil
)
110 (define-default-method xpath-protocol
:attribute-pipe
((node stp-namespace
)) nil
)
111 (define-default-method xpath-protocol
:namespace-pipe
((node stp-namespace
)) nil
)
113 (define-default-method xpath-protocol
:parent-node
((node stp-namespace
))
114 (stp-namespace-parent node
))
115 (define-default-method xpath-protocol
:local-name
((node stp-namespace
))
116 (stp-namespace-prefix node
))
117 (define-default-method xpath-protocol
:qualified-name
((node stp-namespace
))
118 (stp-namespace-prefix node
))
119 (define-default-method xpath-protocol
:namespace-uri
((node stp-namespace
))
122 (define-default-method xpath-protocol
:namespace-pipe
123 ((original-node stp
:element
))
124 (let ((node original-node
)
125 (table (make-hash-table :test
'equal
))
127 (labels ((yield (prefix uri
)
128 (unless (gethash prefix table
)
129 (let ((nsnode (make-stp-namespace original-node prefix uri
)))
130 (setf (gethash prefix table
) nsnode
)
131 (push nsnode current
))))
134 (cons (pop current
) #'iterate
)
140 (let ((parent (stp:parent node
)))
141 (map-extra-namespaces #'yield node
)
142 (unless (and (zerop (length (%namespace-prefix node
)))
143 (zerop (length (%namespace-uri node
)))
144 (or (typep parent
'stp
:document
)
147 (stp:find-namespace
"" parent
)))))
148 (yield (%namespace-prefix node
)
149 (%namespace-uri node
)))
150 (dolist (a (%attributes node
))
151 (when (plusp (length (namespace-prefix a
)))
152 (yield (namespace-prefix a
) (namespace-uri a
))))
156 (yield "xml" "http://www.w3.org/XML/1998/namespace")
157 #+nil
(yield "xmlns" "http://www.w3.org/2000/xmlns/")
162 (define-default-method xpath-protocol
:node-text
((node node
))
165 (define-default-method xpath-protocol
:node-text
((node stp-namespace
))
166 (stp-namespace-uri node
))
168 (define-default-method xpath-protocol
:node-p
((node node
))
171 (define-default-method xpath-protocol
:node-type-p
((node node
) type
)
172 (declare (ignore type
))
175 (define-default-method xpath-protocol
:node-type-p
((node stp-namespace
) type
)
176 (declare (ignore type
))
179 (macrolet ((deftypemapping (class keyword
)
180 `(define-default-method xpath-protocol
:node-type-p
181 ((node ,class
) (type (eql ,keyword
)))
183 (deftypemapping document
:document
)
184 (deftypemapping comment
:comment
)
185 (deftypemapping processing-instruction
:processing-instruction
)
186 (deftypemapping text
:text
)
187 (deftypemapping attribute
:attribute
)
188 (deftypemapping element
:element
)
189 (deftypemapping stp-namespace
:namespace
))
191 (defun normalize-text-nodes! (node)
192 (when (typep node
'stp
:parent-node
)
193 (let ((children (%children node
)))
194 (when (and children
(loop
195 for child across children
197 for b
= (typep child
'text
)
200 (zerop (length (stp:data child
)))))))
203 (stp:do-children
(child node
)
205 ((not (typep child
'stp
:text
))
208 (apply #'concatenate
'string
(nreverse previous
)))
210 (setf (%parent
(car results
)) node
)
212 (push child results
))
214 (push (stp:data child
) previous
))
215 ((zerop (length (stp:data child
))))
217 (setf previous
(list (stp:data child
))))))
220 (apply #'concatenate
'string
(nreverse previous
)))
222 (setf (%parent
(car results
)) node
))
223 (setf (cxml-stp-impl::%children node
)
224 (let ((n (length results
)))
227 :initial-contents
(nreverse results
)))))))))
229 (define-default-method xpath-protocol
:get-element-by-id
((node stp
:node
) id
)
230 (let* ((document (stp:document node
))
231 (dtd (when (stp:document-type document
)
232 (stp:dtd
(stp:document-type document
)))))
236 (when (typep node
'stp
:element
)
238 (cxml::find-element
(stp:qualified-name node
) dtd
)))
240 (dolist (attdef (cxml::elmdef-attributes elmdef
))
241 (when (eq :ID
(cxml::attdef-type attdef
))
242 (let* ((name (cxml::attdef-name attdef
))
243 (value (stp:attribute-value node name
)))
244 (when (and value
(equal value id
))
245 (return node
))))))))))
246 (find-recursively-if #'test document
))))))
248 (define-default-method xpath-protocol
:unparsed-entity-uri
249 ((node stp
:node
) name
)
250 (let ((doctype (stp:document-type
(stp:document node
))))
252 (let ((dtd (stp:dtd doctype
)))
254 (let ((entdef (cdr (gethash name
(cxml::dtd-gentities dtd
)))))
255 (when (typep entdef
'cxml
::external-entdef
)
256 (let ((uri (cxml::extid-system
(cxml::entdef-extid entdef
))))
258 (puri:render-uri uri nil
))))))))))
260 (define-default-method xpath-protocol
:local-name
((node stp
:text
)) "")
262 (define-default-method xpath-protocol
:namespace-prefix
((node stp
:text
)) "")
264 (define-default-method xpath-protocol
:namespace-uri
((node stp
:text
)) "")
266 (define-default-method xpath-protocol
:qualified-name
((node stp
:text
)) "")
268 (define-default-method xpath-protocol
:local-name
((node stp
:comment
)) "")
270 (define-default-method xpath-protocol
:namespace-prefix
((node stp
:comment
)) "")
272 (define-default-method xpath-protocol
:namespace-uri
((node stp
:comment
)) "")
274 (define-default-method xpath-protocol
:qualified-name
278 (define-default-method xpath-protocol
:namespace-prefix
279 ((node stp
:processing-instruction
))
282 (define-default-method xpath-protocol
:local-name
283 ((node stp
:processing-instruction
))
286 (define-default-method xpath-protocol
:qualified-name
287 ((node stp
:processing-instruction
))
290 (define-default-method xpath-protocol
:namespace-uri
291 ((node stp
:processing-instruction
))
294 (define-default-method xpath-protocol
:namespace-uri
295 ((node stp
:document
))
298 (define-default-method xpath-protocol
:namespace-prefix
((node stp
:document
))
301 (define-default-method xpath-protocol
:qualified-name
((node stp
:document
)) "")
303 (define-default-method xpath-protocol
:local-name
((node stp
:document
)) "")
305 (define-default-method xpath-protocol
:processing-instruction-target
309 (define-default-method xpath-protocol
:processing-instruction-target
310 ((node stp
:processing-instruction
))
313 (defun run-xpath-tests ()
314 (let ((xpath::*dom-builder
* (stp:make-builder
))
315 (xpath::*document-element
* #'stp
:document-element
))
316 (xpath::run-all-tests
)))