einige fehler bei datum und zeit
[cxml-rng.git] / types.lisp
blob35f3b0e5540cbb8436b1c699640804c60095ec0a
1 ;;; -*- show-trailing-whitespace: t; indent-tabs: nil -*-
2 ;;;
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
7 ;;; are met:
8 ;;;
9 ;;; * Redistributions of source code must retain the above copyright
10 ;;; notice, this list of conditions and the following disclaimer.
11 ;;;
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.
16 ;;;
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 :cxml-types)
31 (defstruct (param (:constructor make-param (name value)))
32 "@short{A named data type parameter.}
34 (With the XSD type library, parameters are known as restricting facets.)
35 @see-constructor{make-param}
36 @see{find-type}
37 @see{cxml-rng:pattern-params}
38 @see{cxml-rng:data}
39 @see-slot{param-name}
40 @see-slot{param-value}"
41 name
42 value)
44 (setf (documentation 'make-param 'function)
45 "@arg[name]{paramater name, a string}
46 @arg[value]{paramater value, a string}
47 @return{a @class{param}}
48 Create a data type parameter.
49 @see{param-name}
50 @see{param-value}")
52 (setf (documentation 'param-name 'function)
53 "@arg[instance]{an instance of @class{param}}
54 @return{a string}
55 The data type parameter's name.
56 @see{param-value}")
58 (setf (documentation 'param-value 'function)
59 "@arg[instance]{an instance of @class{param}}
60 @return{a string}
61 The data type parameter's value.
62 @see{param-name}")
64 (defclass data-type () ()
65 (:documentation
66 "@short{The abstract superclass of all types.}
68 Each type belongs to a datatype library, named by a keyword. In each
69 library, the types are named by strings.
71 @see-constructor{find-type}
72 @see-slot{type-name}
73 @see-slot{type-library}
74 @see-slot{type-context-dependent-p}
75 @see{parse}
76 @see{equal-using-type}
77 @see{lessp-using-type}
78 @see{validp}"))
80 (defgeneric find-type (library name params)
81 (:documentation
82 "@arg[library]{datatype library, a keyword symbol}
83 @arg[name]{the type's name, a string}
84 @arg[params]{type parameters, a list of @class{param} instances}
85 @return{an instance of @class{data-type}, or @code{nil}}
86 @short{Look up the type named @em{name} in datatype library @em{library}.}
88 Return a type instance for this type and the additional parameters,
89 or @code{nil} if the type does not exist.
91 Additional parameters (knows as restricting facets in XSD) can be passed
92 to specify or restrict the type for the purposes of @fun{validp}.
94 @see{data-type}"))
96 (defgeneric type-library (type)
97 (:documentation
98 "@arg[type]{an instance of @class{data-type}}
99 @return{library name, a keyword}
100 @short{Return the name of the library this type belongs to.}
102 @see{type-name}
103 @see{type-context-dependent-p}"))
105 (defgeneric type-name (type)
106 (:documentation
107 "@arg[type]{an instance of @class{data-type}}
108 @return{type name, a string}
109 @short{Return the name this type has within its library.}
111 @see{type-library}
112 @see{type-context-dependent-p}"))
114 (defmethod find-type ((library t) name params)
115 (declare (ignore name params))
116 nil)
118 (defgeneric type-context-dependent-p (type)
119 (:documentation
120 "@arg[type]{an instance of @class{data-type}}
121 @return{a boolean}
122 @short{Return true if parsing and validation of values by this type
123 depends on the validation context.}
125 In this case, the optional @code{context} argument to @fun{parse} and
126 @fun{validp} is required, and an error will be signalled if it is missing.
128 @see{validation-context}
129 @see{type-name}
130 @see{type-library}
131 @see{type-context-dependent-p}"))
133 (defmethod type-context-dependent-p ((type data-type))
134 nil)
136 (defgeneric equal-using-type (type u v)
137 (:documentation
138 "@arg[type]{an instance of @class{data-type}}
139 @arg[u]{a parsed value as returned by @fun{parse}}
140 @arg[v]{a parsed value as returned by @fun{parse}}
141 @return{a boolean}
142 @short{Compare the @emph{values} @code{u} and @code{v} using a
143 data-type-dependent equality function.}
145 @see{validp}"))
147 (defgeneric parse (type e &optional context)
148 (:documentation
149 "@arg[type]{an instance of @class{data-type}}
150 @arg[e]{a string}
151 @arg[context]{an instance of @class{validation-context}}
152 @return{an object}
153 @short{Parse string @code{e} and return a representation of its value
154 as defined by the data type.}
156 The @code{context} argument is required if @fun{type-context-dependent-p}
157 is true for @code{type}, and will be ignored otherwise.
159 @see{equal-using-type}
160 @see{validp}"))
162 (defgeneric validp (type e &optional context)
163 (:documentation
164 "@arg[type]{an instance of @class{data-type}}
165 @arg[e]{a string}
166 @arg[context]{an instance of @class{validation-context}}
167 @return{a boolean}
168 @short{Determine whether a string is a valid lexical representation
169 for a type.}
171 The @code{context} argument is required if @fun{type-context-dependent-p}
172 is true for @code{type}, and will be ignored otherwise.
174 @see{parse}
175 @see{equal-using-type}"))
178 ;;; Validation context
180 (defclass validation-context () ()
181 (:documentation
182 "@short{This abstract class defines a protocol allowing data types
183 to query the XML parser about its current state.}
185 Some types are context dependent, as indicated by
186 @fun{type-context-dependent-p}. Those types need access to state
187 computed by the XML parser implicitly, like namespace bindings or
188 the Base URI.
190 User-defined subclasses must implement methods
191 for the functions @fun{context-find-namespace-binding} and
192 @fun{context-find-unparsed-entity}.
194 Two pre-defined validation context implementations are
195 provided, one for use with SAX, the other based on Klacks."))
197 (defgeneric context-find-namespace-binding (context prefix)
198 (:documentation
199 "@arg[context]{an instance of @class{validation-context}}
200 @arg[prefix]{name prefix, a string}
201 @return{the namespace URI as a string, or NIL}
202 @short{This function resolves a namespace prefix to a namespace URI in the
203 current context.}
204 All currently declared namespaces
205 are taken into account, including those declared directly on the
206 current element."))
208 (defgeneric context-find-unparsed-entity (context name)
209 (:documentation
210 "@arg[context]{an instance of @class{validation-context}}
211 @arg[name]{entity name, a string}
212 @return{@code{nil}, or a list of public id, system id, and notation name}
213 This function looks for an unparsed entity in the current context."))
215 (defclass klacks-validation-context (validation-context)
216 ((source :initarg :source :accessor context-source))
217 (:documentation
218 "A validation-context implementation that queries
219 a klacks source for information about the parser's current state.
220 @see-constructor{make-klacks-validation-context}"))
222 (defun make-klacks-validation-context (source)
223 "@arg[source]{a @a[http://common-lisp.net/project/cxml/klacks.html]{
224 klacks source}}
225 @return{a @class{klacks-validation-context}}
226 Create a validation-context that will query the given klacks source for
227 the current parser context."
228 (make-instance 'klacks-validation-context :source source))
230 (defmethod context-find-namespace-binding
231 ((context klacks-validation-context) prefix)
232 (klacks:find-namespace-binding prefix (context-source context)))
234 ;; zzz nicht schoen.
235 (defmethod context-find-unparsed-entity
236 ((context klacks-validation-context) name)
237 (or (dolist (x (slot-value (context-source context)
238 'cxml::external-declarations))
239 (when (and (eq (car x) 'sax:unparsed-entity-declaration)
240 (equal (cadr x) name))
241 (return t)))
242 (dolist (x (slot-value (context-source context)
243 'cxml::internal-declarations))
244 (when (and (eq (car x) 'sax:unparsed-entity-declaration)
245 (equal (cadr x) name))
246 (return t)))))
248 (defclass sax-validation-context-mixin (validation-context)
249 ((stack :initform nil :accessor context-stack)
250 (unparsed-entities :initform (make-hash-table :test 'equal)
251 :accessor unparsed-entities))
252 (:documentation
253 "@short{A class that implements validation-context as a mixin for
254 user-defined SAX handler classes.}
256 The mixin will record namespace information
257 automatically, and the user's SAX handler can simply be passed as a
258 validation context to data type functions."))
260 (defmethod sax:start-prefix-mapping
261 ((handler sax-validation-context-mixin) prefix uri)
262 (push (cons prefix uri) (context-stack handler)))
264 (defmethod sax:end-prefix-mapping
265 ((handler sax-validation-context-mixin) prefix)
266 (setf (context-stack handler)
267 (remove prefix
268 (context-stack handler)
269 :count 1
270 :key #'car
271 :test #'equal)))
273 (defmethod sax:unparsed-entity-declaration
274 ((context sax-validation-context-mixin)
275 name public-id system-id notation-name)
276 (setf (gethash name (unparsed-entities context))
277 (list public-id system-id notation-name)))
279 (defmethod context-find-namespace-binding
280 ((context sax-validation-context-mixin) prefix)
281 (cdr (assoc prefix (context-stack context) :test #'equal)))
283 (defmethod context-find-unparsed-entity
284 ((context sax-validation-context-mixin) name)
285 (gethash name (unparsed-entities context)))
288 ;;; Relax NG built-in type library
290 (defclass rng-type (data-type) ()
291 (:documentation
292 "@short{The class of Relax NG built-in types.}
293 Relax NG defines two built-in data type: string and token.
295 The Relax NG type library is named @code{:||}."))
297 (defmethod print-object ((object rng-type) stream)
298 (print-unreadable-object (object stream :type t :identity nil)))
300 (defclass string-type (rng-type) ()
301 (:documentation
302 "@short{The Relax NG 'string' type.}
303 This data type allows arbitrary strings and interprets them as-is.
305 For this type, @fun{parse} will return any string unchanged, and
306 @fun{equal-using-type} compares strings using @code{equal}."))
308 (defclass token-type (rng-type) ()
309 (:documentation
310 "@short{The Relax NG 'token' type.}
311 This data type allows arbitrary strings and normalizes all whitespaces.
313 For this type, @fun{parse} will return the string with leading and
314 trailing whitespace removed, and remaining sequences of spaces
315 compressed down to one space character each.
317 A method for @fun{equal-using-type} compares strings using @code{equal}."))
319 (defmethod type-library ((type rng-type))
320 :||)
322 (defvar *string-data-type* (make-instance 'string-type))
323 (defvar *token-data-type* (make-instance 'token-type))
325 (defmethod find-type ((library (eql :||)) name params)
326 (cond
327 ((eq name :probe) t)
328 (params :error)
329 ((equal name "string") *string-data-type*)
330 ((equal name "token") *token-data-type*)
331 (t nil)))
333 (defmethod equal-using-type ((type rng-type) u v)
334 (equal u v))
336 (defmethod validp ((type rng-type) e &optional context)
337 (declare (ignore e context))
340 (defmethod type-name ((type string-type)) "string")
341 (defmethod type-name ((type token-type)) "token")
343 (defmethod parse ((type string-type) e &optional context)
344 (declare (ignore context))
347 (defmethod parse ((type token-type) e &optional context)
348 (declare (ignore context))
349 (normalize-whitespace e))
351 (eval-when (:compile-toplevel :load-toplevel :execute)
352 (defparameter *whitespace*
353 (format nil "~C~C~C~C"
354 (code-char 9)
355 (code-char 32)
356 (code-char 13)
357 (code-char 10))))
359 (defun normalize-whitespace (str)
360 (cl-ppcre:regex-replace-all #.(format nil "[~A]+" *whitespace*)
361 (string-trim *whitespace* str)
362 " "))
364 (defun replace-whitespace (str)
365 (cl-ppcre:regex-replace-all #.(format nil "[~A]" *whitespace*)
367 " "))
370 ;;; XML Schema Part 2: Datatypes Second Edition
372 (defparameter *xsd-types* (make-hash-table :test 'equal))
374 (defmacro defxsd
375 ((class-name type-name) (&rest supers) (&rest slots) &rest args)
376 `(progn
377 (setf (gethash ,type-name *xsd-types*) ',class-name)
378 (defclass ,class-name ,supers
379 ((type-name :initform ,type-name
380 :reader type-name
381 :allocation :class)
382 ,@slots)
383 ,@args)))
385 (defclass xsd-type (data-type)
386 ((patterns :initform nil :initarg :patterns :reader patterns))
387 (:documentation
388 "@short{The class of XML Schema built-in types.}
390 Subclasses of xsd-type provide the built-in types of
391 @a[http://www.w3.org/TR/xmlschema-2/]{
392 XML Schema Part 2: Datatypes Second Edition}
393 as specified in @a[http://relaxng.org/xsd-20010907.html]{Guidelines for
394 using W3C XML Schema Datatypes with RELAX NG}.
396 The XSD type library
397 is named @code{:|http://www.w3.org/2001/XMLSchema-datatypes|}."))
399 (defmethod print-object ((object xsd-type) stream)
400 (print-unreadable-object (object stream :type t :identity nil)
401 (describe-facets object stream)))
403 (defgeneric describe-facets (object stream)
404 (:method-combination progn))
406 (defmethod describe-facets progn ((object xsd-type) stream)
407 (format stream "~{ :pattern ~A~}" (patterns object)))
409 (defmethod type-library ((type xsd-type))
410 :|http://www.w3.org/2001/XMLSchema-datatypes|)
412 (defun zip (keys values)
413 (loop for key in keys for value in values collect key collect value))
415 (defgeneric parse-parameter (class-name type-name param-name value))
417 (defun parse-parameters (type-class params)
418 (let ((patterns '())
419 (args '()))
420 (dolist (param params (values t patterns args))
421 (let ((name (param-name param))
422 (value (param-value param)))
423 (if (equal name "pattern")
424 (push value patterns)
425 (multiple-value-bind (key required-class)
426 (case (find-symbol (param-name param) :keyword)
427 (:|length| (values :exact-length 'length-mixin))
428 (:|maxLength| (values :max-length 'length-mixin))
429 (:|minLength| (values :min-length 'length-mixin))
430 (:|minInclusive| (values :min-inclusive 'ordering-mixin))
431 (:|maxInclusive| (values :max-inclusive 'ordering-mixin))
432 (:|minExclusive| (values :min-exclusive 'ordering-mixin))
433 (:|maxExclusive| (values :max-exclusive 'ordering-mixin))
434 (:|totalDigits| (values :total-digits 'decimal-type))
435 (:|fractionDigits| (values :fraction-digits 'decimal-type))
436 (t (return nil)))
437 (unless (subtypep type-class required-class)
438 (return nil))
439 (when (loop
440 for (k nil) on args by #'cddr
441 thereis (eq key k))
442 (return nil))
443 (push (parse-parameter required-class
444 type-class
446 (normalize-whitespace value))
447 args)
448 (push key args)))))))
450 (defmethod find-type
451 ((library (eql :|http://www.w3.org/2001/XMLSchema-datatypes|)) name params)
452 (if (eq name :probe)
454 (let ((class (gethash name *xsd-types*)))
455 (if class
456 (multiple-value-bind (ok patterns other-args)
457 (parse-parameters class params)
458 (if ok
459 (apply #'make-instance
460 class
461 :patterns patterns
462 other-args)
463 :error))
464 nil))))
466 (defgeneric parse/xsd (type e context))
468 (defgeneric validp/xsd (type v context)
469 (:method-combination and))
471 (defmethod validp/xsd and ((type xsd-type) v context)
472 (declare (ignore context))
473 ;; zzz
474 #+(or)
475 (every (lambda (pattern)
476 (cl-ppcre:all-matches pattern v))
477 (patterns type))
480 (defmethod validp ((type xsd-type) e &optional context)
481 (not (eq :error (parse/xsd type e context))))
483 (defmethod parse ((type xsd-type) e &optional context)
484 (let ((result (parse/xsd type e context)))
485 (when (eq result :error)
486 (error "not valid for data type ~A: ~S" type e))
487 result))
489 ;; Handle the whiteSpace "facet" before the subclass sees it.
490 ;; If parsing succeded, check other facets by asking validp/xsd.
491 (defmethod parse/xsd :around ((type xsd-type) e context)
492 (let ((result (call-next-method type
493 (munge-whitespace type e)
494 context)))
495 (if (or (eq result :error) (validp/xsd type result context))
496 result
497 :error)))
499 (defgeneric munge-whitespace (type e))
501 (defmethod munge-whitespace ((type xsd-type) e)
502 (normalize-whitespace e))
505 ;;; ordering-mixin
507 (defclass ordering-mixin ()
508 ((min-exclusive :initform nil
509 :initarg :min-exclusive
510 :accessor min-exclusive)
511 (max-exclusive :initform nil
512 :initarg :max-exclusive
513 :accessor max-exclusive)
514 (min-inclusive :initform nil
515 :initarg :min-inclusive
516 :accessor min-inclusive)
517 (max-inclusive :initform nil
518 :initarg :max-inclusive
519 :accessor max-inclusive)))
521 (defmethod describe-facets progn ((object ordering-mixin) stream)
522 (dolist (slot '(min-exclusive max-exclusive min-inclusive max-inclusive))
523 (let ((value (slot-value object slot)))
524 (when value
525 (format stream " ~A ~A"
526 (intern (symbol-name slot) :keyword)
527 value)))))
529 (defmethod parse-parameter
530 ((class-name (eql 'ordering-mixin)) type-name (param t) value)
531 (parse (make-instance type-name) value nil))
533 (defgeneric lessp-using-type (type u v)
534 (:documentation
535 "@arg[type]{an ordered @class{data-type}}
536 @arg[u]{a parsed value as returned by @fun{parse}}
537 @arg[v]{a parsed value as returned by @fun{parse}}
538 @return{a boolean}
539 @short{Compare the @emph{values} @code{u} and @code{v} using a
540 data-type-dependent partial ordering.}
542 A method for this function is provided only by types that have a
543 natural partial ordering. The ordering is described in the
544 documentation for the type.
546 @see{equal-using-type}"))
548 (defun <-using-type (type u v)
549 (lessp-using-type type u v))
551 (defun <=-using-type (type u v)
552 (or (lessp-using-type type u v) (equal-using-type type u v)))
554 ;; it's only a partial ordering, so in general this is not the opposite of <=
555 (defun >-using-type (type u v)
556 (lessp-using-type type v u))
558 ;; it's only a partial ordering, so in general this is not the opposite of <
559 (defun >=-using-type (type u v)
560 (or (lessp-using-type type v u) (equal-using-type type v u)))
562 (defmethod validp/xsd and ((type ordering-mixin) v context)
563 (declare (ignore context))
564 (with-slots (min-exclusive max-exclusive min-inclusive max-inclusive) type
565 (and (or (null min-exclusive) (>-using-type type v min-exclusive))
566 (or (null max-exclusive) (<-using-type type v max-exclusive))
567 (or (null min-inclusive) (>=-using-type type v min-inclusive))
568 (or (null max-inclusive) (<=-using-type type v max-inclusive)))))
571 ;;; length-mixin
573 (defclass length-mixin ()
574 ((exact-length :initform nil :initarg :exact-length :accessor exact-length)
575 (min-length :initform nil :initarg :min-length :accessor min-length)
576 (max-length :initform nil :initarg :max-length :accessor max-length)))
578 (defmethod describe-facets progn ((object length-mixin) stream)
579 (dolist (slot '(exact-length min-length max-length))
580 (let ((value (slot-value object slot)))
581 (when value
582 (format stream " ~A ~A"
583 (intern (symbol-name slot) :keyword)
584 value)))))
586 (defmethod parse-parameter
587 ((class-name (eql 'length-mixin)) (type-name t) (param t) value)
588 (parse (make-instance 'non-negative-integer-type) value nil))
590 ;; extra-hack fuer die "Laenge" eines QName...
591 (defgeneric length-using-type (type u))
592 (defmethod length-using-type ((type length-mixin) e) (length e))
594 (defmethod validp/xsd and ((type length-mixin) v context)
595 (declare (ignore context))
596 (with-slots (exact-length min-length max-length) type
597 (or (not (or exact-length min-length max-length))
598 (let ((l (length-using-type type v)))
599 (and (or (null exact-length) (eql l exact-length))
600 (or (null min-length) (>= l min-length))
601 (or (null max-length) (<= l max-length)))))))
604 ;;; enumeration-type
606 (defclass enumeration-type (xsd-type length-mixin)
607 ((word-type :reader word-type)))
609 (defmethod initialize-instance :after ((type enumeration-type) &key)
610 (setf (min-length type) (max* 1 (min-length type))))
612 (defmethod parse/xsd ((type enumeration-type) e context)
613 (let ((wt (word-type type)))
614 (loop
615 for word in (cl-ppcre:split " " e)
616 for v = (parse wt word context)
617 collect v
618 when (eq v :error) do (return :error))))
622 ;;;; Primitive types
624 ;;; duration
626 (defxsd (duration-type "duration") (xsd-type ordering-mixin) ())
628 (defmethod equal-using-type ((type duration-type) u v)
629 (equal u v))
631 ;; zzz das ist vielleicht ein bisschen zu woertlich implementiert
632 (defmethod lessp-using-type ((type duration-type) u v)
633 (let ((dt (make-instance 'date-time-type)))
634 (every (lambda (str)
635 (let ((s (parse dt str nil)))
636 (lessp-using-type dt
637 (datetime+duration s u)
638 (datetime+duration s v))))
639 '("1696-09-01T00:00:00Z"
640 "1697-02-01T00:00:00Z"
641 "1903-03-01T00:00:00Z"
642 "1903-07-01T00:00:00Z"))))
644 (defun datetime+duration (s d)
645 (destructuring-bind (syear smonth sday shour sminute ssecond szone) s
646 (destructuring-bind (dyear dmonth dday dhour dminute dsecond) d
647 (labels ((floor3 (a low high)
648 (multiple-value-bind (u v)
649 (floor (- a low) (- high low))
650 (values u (+ low v))))
651 (maximum-day-in-month-for (yearvalue monthvalue)
652 (multiple-value-bind (m y)
653 (floor3 monthvalue 1 13)
654 (day-limit m (+ yearvalue y)))))
655 (multiple-value-bind (carry emonth) (floor3 (+ smonth dmonth) 1 13)
656 (let ((eyear (+ syear dyear carry))
657 (ezone szone))
658 (multiple-value-bind (carry esecond) (floor (+ ssecond dsecond) 60)
659 (multiple-value-bind (carry eminute)
660 (floor (+ sminute dminute carry) 60)
661 (multiple-value-bind (carry ehour)
662 (floor (+ shour dhour carry) 24)
663 (let* ((mdimf (maximum-day-in-month-for eyear emonth))
664 (tmpdays (max 1 (min sday mdimf)))
665 (eday (+ tmpdays dday carry)))
666 (loop
667 (let* ((mdimf (maximum-day-in-month-for eyear emonth))
668 (carry
669 (cond
670 ((< eday 1)
671 (setf eday (+ eday mdimf))
673 ((> eday mdimf)
674 (setf eday (- eday mdimf))
677 (return))))
678 (tmp (+ emonth carry)))
679 (multiple-value-bind (y m)
680 (floor3 tmp 1 13)
681 (setf emonth m)
682 (incf eyear y))))
683 (list eyear emonth eday ehour eminute esecond
684 ezone)))))))))))
686 (defun scan-to-strings (&rest args)
687 (coerce (nth-value 1 (apply #'cl-ppcre:scan-to-strings args)) 'list))
689 (defmethod parse/xsd ((type duration-type) e context)
690 (declare (ignore context))
691 (destructuring-bind (&optional minusp y m d tp h min s)
692 (scan-to-strings "(?x)
693 ^(-)? # minus
694 P(?:(\\d+)Y)? # years
695 (?:(\\d+)M)? # months
696 (?:(\\d+)D)? # days
697 (T # (time)
698 (?:(\\d+)H)? # hours
699 (?:(\\d+)M)? # minutes
700 (?:(\\d+(?:[.]\\d+)?)S)? # seconds
701 )?$"
703 (if (and (or y m d h min s)
704 (or (null tp) (or h min s)))
705 (let ((f (if minusp -1 1)))
706 (flet ((int (str)
707 (and str (* f (parse-integer str)))))
708 (list (int y) (int m) (int d) (int h) (int min)
709 (and s (* f (parse-number:parse-number s))))))
710 :error)))
713 ;;; dateTime
715 (defclass time-ordering-mixin (ordering-mixin) ())
717 (defxsd (date-time-type "dateTime") (xsd-type time-ordering-mixin) ())
719 (defmethod equal-using-type ((type time-ordering-mixin) u v)
720 (equal u v))
722 ;; add zone-offset as a duration (if any), but keep a boolean in the
723 ;; zone-offset field indicating whether there was a time-zone
724 (defun normalize-date-time (u)
725 (destructuring-bind (year month day hour minute second zone-offset) u
726 (let ((v (list year month day hour minute second (and zone-offset t))))
727 (if zone-offset
728 (multiple-value-bind (h m)
729 (truncate zone-offset)
730 (datetime+timezone v h (* m 100)))
731 v))))
733 (defun datetime+timezone (d h m)
734 (datetime+duration d (list 0 0 0 h m 0)))
736 (defmethod lessp-using-type ((type time-ordering-mixin) p q)
737 (destructuring-bind (pyear pmonth pday phour pminute psecond pzone)
738 (normalize-date-time p)
739 (destructuring-bind (qyear qmonth qday qhour qminute qsecond qzone)
740 (normalize-date-time q)
741 (cond
742 ((and pzone (not qzone))
743 (lessp-using-type type p (datetime+timezone q 14 0)))
744 ((and (not pzone) qzone)
745 (lessp-using-type type (datetime+timezone p -14 0) q))
747 ;; zzz hier sollen wir <> liefern bei Feldern, die in genau einer
748 ;; der Zeiten fehlen. Wir stellen aber fehlende Felder derzeit
749 ;; defaulted dar, koennen diese Situation also nicht feststellen.
750 ;; Einen Unterschied sollte das nur machen, wenn Werte verschiedener
751 ;; Datentypen miteinander verglichen werden. Das bieten wir einfach
752 ;; nicht an.
753 (loop
754 for a in (list pyear pmonth pday phour pminute psecond)
755 for b in (list qyear qmonth qday qhour qminute qsecond)
757 (when (< a b)
758 (return t))
759 (when (> a b)
760 (return nil))))))))
762 (defun day-limit (m y)
763 (cond
764 ((and (eql m 2)
765 (or (zerop (mod y 400))
766 (and (zerop (mod y 4))
767 (not (zerop (mod y 100))))))
769 ((eql m 2) 28)
770 ((oddp y) 31)
771 (t 30)))
773 (defmethod parse-time (minusp y m d h min s tz tz-sign tz-h tz-m
774 &key (start 0) end)
775 (declare (ignore start end)) ;zzz
776 ;; parse into numbers
777 (flet ((int (str)
778 (and str (parse-integer str)))
779 (num (str)
780 (and str (parse-number:parse-number str))))
781 (setf (values y m d h min s tz-h tz-m)
782 (values (* (int y) (if minusp -1 1))
783 (int m) (int d) (int h) (int min)
784 (num s)
785 (int tz-h) (int tz-m))))
786 (let ((day-limit (day-limit m y)))
787 ;; check ranges
788 (cond
789 ((and y m d h min s
790 (plusp y)
791 (<= 1 m 12)
792 (<= 1 d day-limit)
793 (<= 0 h 24)
794 (<= 0 min 59)
795 ;; zzz sind leap seconds immer erlaubt?
796 (<= 0 s 60))
797 ;; 24:00:00 must be canonicalized
798 (when (and (eql h 24) (zerop min) (zerop s))
799 (incf h)
800 (incf d)
801 (when (> d day-limit)
802 (setf d 1)
803 (incf m)
804 (when (> m 12)
805 (incf y))))
806 (let ((tz-offset
807 (when tz-h
808 (* (if (equal tz-sign "-") -1 1)
809 (+ tz-h (/ tz-m 100))))))
810 (list (* y (if minusp -1 1)) m d h min s tz-offset)
811 ;; (subseq ... start end)
814 :error))))
816 (defmethod parse/xsd ((type date-time-type) e context)
817 (declare (ignore context))
818 (destructuring-bind (&optional minusp y m d h min s tz tz-sign tz-h tz-m)
819 (scan-to-strings "(?x)
820 ^(-)? # opt. minus
821 ((?:[1-9]\\d*)?\\d{4}) # year
822 -(\\d\\d) # month
823 -(\\d\\d) # day
824 T # (time)
825 (\\d\\d) # hour
826 :(\\d\\d) # minute
827 :(\\d+(?:[.]\\d+)?) # second
828 (([+-])(\\d\\d):(\\d\\d)|Z)? # opt timezone
831 (parse-time minusp y m d h min s tz tz-sign tz-h tz-m)))
834 ;;; time
836 (defxsd (time-type "time") (xsd-type time-ordering-mixin) ())
838 (defmethod parse/xsd ((type time-type) e context)
839 (declare (ignore context))
840 (destructuring-bind (&optional h min s tz tz-sign tz-h tz-m)
841 (scan-to-strings "(?x)
842 ^(\\d\\d) # hour
843 :(\\d\\d) # minute
844 :(\\d+(?:[.]\\d+)?) # second
845 (([+-])(\\d\\d):(\\d\\d)|Z)? # opt timezone
848 (parse-time nil "1" "1" "1" h min s tz tz-sign tz-h tz-m
849 :start 3)))
852 ;;; date
854 (defxsd (date-type "date") (xsd-type time-ordering-mixin) ())
856 (defmethod parse/xsd ((type date-type) e context)
857 (declare (ignore context))
858 (destructuring-bind (&optional minusp y m d tz tz-sign tz-h tz-m)
859 (scan-to-strings "(?x)
860 ^(-)? # opt. minus
861 ((?:[1-9]\\d*)?\\d{4}) # year
862 -(\\d\\d) # month
863 -(\\d\\d) # day
864 (([+-])(\\d\\d):(\\d\\d)|Z)? # opt timezone
867 (parse-time minusp y m d "0" "0" "0" tz tz-sign tz-h tz-m
868 :end 3)))
871 ;;; gYearMonth
873 (defxsd (year-month-type "gYearMonth") (xsd-type time-ordering-mixin) ())
875 (defmethod parse/xsd ((type year-month-type) e context)
876 (declare (ignore context))
877 (destructuring-bind (&optional minusp y m)
878 (scan-to-strings "(?x)
879 ^(-)? # opt. minus
880 ((?:[1-9]\\d*)?\\d{4}) # year
881 -(\\d\\d) # month
884 (parse-time minusp y m "1" "0" "0" "0" nil nil nil nil
885 :end 2)))
888 ;;; gYear
890 (defxsd (year-type "gYear") (xsd-type time-ordering-mixin) ())
892 (defmethod parse/xsd ((type year-type) e context)
893 (declare (ignore context))
894 (destructuring-bind (&optional minusp y tz tz-sign tz-h tz-m)
895 (scan-to-strings "(?x)
896 ^(-)? # opt. minus
897 ((?:[1-9]\\d*)?\\d{4}) # year
898 (([+-])(\\d\\d):(\\d\\d)|Z)? # opt timezone
901 (parse-time minusp y "1" "1" "0" "0" "0" tz tz-sign tz-h tz-m
902 :end 1)))
905 ;;; gMonthDay
907 (defxsd (month-day-type "gMonthDay") (xsd-type time-ordering-mixin) ())
909 (defmethod parse/xsd ((type month-day-type) e context)
910 (declare (ignore context))
911 (destructuring-bind (&optional m d tz tz-sign tz-h tz-m)
912 (scan-to-strings "(?x)
913 ^--(\\d\\d) # month
914 -(\\d\\d) # day
915 (([+-])(\\d\\d):(\\d\\d)|Z)? # opt timezone
918 (parse-time nil "1" m d "0" "0" "0" tz tz-sign tz-h tz-m
919 :start 1 :end 3)))
922 ;;; gDay
924 (defxsd (day-type "gDay") (xsd-type time-ordering-mixin) ())
926 (defmethod parse/xsd ((type day-type) e context)
927 (declare (ignore context))
928 (destructuring-bind (&optional d tz tz-sign tz-h tz-m)
929 (scan-to-strings "(?x)
930 ---(\\d\\d) # day
931 (([+-])(\\d\\d):(\\d\\d)|Z)? # opt timezone
934 (parse-time nil "1" "1" d "0" "0" "0" tz tz-sign tz-h tz-m
935 :start 3 :end 4)))
938 ;;; gMonth
940 (defxsd (month-type "gMonth") (xsd-type time-ordering-mixin) ())
942 (defmethod parse/xsd ((type month-type) e context)
943 (declare (ignore context))
944 (destructuring-bind (&optional m tz tz-sign tz-h tz-m)
945 (scan-to-strings "(?x)
946 ^--(\\d\\d) # month
947 (([+-])(\\d\\d):(\\d\\d)|Z)? # opt timezone
950 (parse-time nil "1" m "1" "0" "0" "0" tz tz-sign tz-h tz-m
951 :start 2 :end 3)))
954 ;;; boolean
956 (defxsd (boolean-type "boolean") (xsd-type) ())
958 (defmethod parse/xsd ((type boolean-type) e context)
959 (declare (ignore context))
960 (case (find-symbol e :keyword)
961 ((:|true| :|1|) t)
962 ((:|false| :|0|) nil)))
965 ;;; base64Binary
967 (defxsd (base64-binary-type "base64Binary") (xsd-type length-mixin) ())
969 (defmethod equal-using-type ((type base64-binary-type) u v)
970 (equalp u v))
972 (defmethod parse/xsd ((type base64-binary-type) e context)
973 (declare (ignore context))
974 (if (cl-ppcre:all-matches
975 "(?x)
976 ^(([A-Za-z0-9+/][ ]?[A-Za-z0-9+/][ ]?[A-Za-z0-9+/]
977 [ ]?[A-Za-z0-9+/][ ]?)*
978 (([A-Za-z0-9+/][ ]?[A-Za-z0-9+/][ ]?[A-Za-z0-9+/][ ]?[A-Za-z0-9+/])
979 | ([A-Za-z0-9+/][ ]?[A-Za-z0-9+/][ ]?[AEIMQUYcgkosw048][ ]?=)
980 | ([A-Za-z0-9+/][ ]?[AQgw][ ]?=[ ]?=)))?$"
982 (handler-case
983 (cl-base64:base64-string-to-usb8-array e)
984 (warning (c)
985 (error "unexpected failure in Base64 decoding: ~A" c)))
986 :error))
989 ;;; hexBinary
991 (defxsd (hex-binary-type "hexBinary") (xsd-type length-mixin) ())
993 (defmethod equal-using-type ((type hex-binary-type) u v)
994 (equalp u v))
996 (defmethod parse/xsd ((type hex-binary-type) e context)
997 (declare (ignore context))
998 (if (evenp (length e))
999 (let ((result
1000 (make-array (/ (length e) 2) :element-type '(unsigned-byte 8))))
1001 (loop
1002 for i from 0 below (length e) by 2
1003 for j from 0
1005 (setf (elt result j)
1006 (handler-case
1007 (parse-integer e :start i :end (+ i 2) :radix 16)
1008 (error ()
1009 (return :error))))
1010 finally (return result)))
1011 :error))
1014 ;;; float
1016 (defxsd (float-type "float") (xsd-type ordering-mixin) ())
1018 (defmethod equal-using-type ((type float-type) u v)
1019 #+(or sbcl allegro) (= u v)
1020 #-(or sbcl allegro) (float= u v))
1022 (defmethod lessp-using-type ((type float-type) u v)
1023 #+(or sbcl allegro) (< u v)
1024 #-(or sbcl allegro) (float< u v))
1026 ;; this one is more complex than would seem necessary, because too-large
1027 ;; and too-small values must be rounded to infinity rather than erroring out
1028 (defun parse-float (e min max +inf -inf nan)
1029 (cond
1030 ((equal e "INF") +inf)
1031 ((equal e "-INF") -inf)
1032 ((equal e "Nan") nan)
1034 (destructuring-bind (&optional a b)
1035 (scan-to-strings "^([^eE]+)(?:[eE]([^eE]+))?$" e)
1036 (if a
1037 (let* ((mantissa (parse/xsd (make-instance 'decimal-type) a nil))
1038 (exponent
1039 (when b
1040 (parse/xsd (make-instance 'integer-type) b nil))))
1041 (if (or (eq mantissa :error) (eq exponent :error))
1042 :error
1043 (let ((ratio (* mantissa (expt 10 (or exponent 1)))))
1044 (cond
1045 ((< ratio min) -inf)
1046 ((> ratio max) +inf)
1047 (t (float ratio min))))))
1048 :error)))))
1050 ;; zzz nehme hier an, dass single-float in IEEE single float ist.
1051 ;; Das stimmt unter LispWorks bestimmt wieder nicht.
1052 (defmethod parse/xsd ((type float-type) e context)
1053 (declare (ignore context))
1054 (parse-float e
1055 most-negative-single-float
1056 most-positive-single-float
1057 single-float-positive-infinity
1058 single-float-negative-infinity
1059 single-float-nan))
1062 ;;; decimal
1064 (defxsd (decimal-type "decimal") (xsd-type ordering-mixin)
1065 ((fraction-digits :initform nil
1066 :initarg :fraction-digits
1067 :accessor fraction-digits)
1068 (total-digits :initform nil
1069 :initarg :total-digits
1070 :accessor total-digits)))
1072 (defmethod describe-facets progn ((object decimal-type) stream)
1073 (dolist (slot '(fraction-digits total-digits))
1074 (let ((value (slot-value object slot)))
1075 (when value
1076 (format stream " ~A ~A"
1077 (intern (symbol-name slot) :keyword)
1078 value)))))
1080 (defmethod parse-parameter
1081 ((class-name (eql 'decimal-type))
1082 (type-name t)
1083 (param (eql :fraction-digits))
1084 value)
1085 (parse (make-instance 'non-negative-integer-type) value nil))
1087 (defmethod parse-parameter
1088 ((class-name (eql 'decimal-type))
1089 (type-name t)
1090 (param (eql :total-digits))
1091 value)
1092 (parse (make-instance 'positive-integer-type) value nil))
1094 (defmethod lessp-using-type ((type decimal-type) u v)
1095 (< u v))
1097 (defmethod equal-using-type ((type decimal-type) u v)
1098 (= u v))
1100 (defmethod validp/xsd and ((type decimal-type) v context)
1101 (declare (ignore context))
1102 (with-slots (fraction-digits total-digits) type
1103 (and (or (null fraction-digits)
1104 (let* ((betrag (abs v))
1105 (fraction (- betrag (truncate betrag)))
1106 (scaled (* fraction (expt 10 fraction-digits))))
1107 (zerop (mod scaled 1))))
1108 (or (null total-digits)
1109 (let ((scaled (abs v)))
1110 (loop
1111 until (zerop (mod scaled 1))
1112 do (setf scaled (* scaled 10)))
1113 (< scaled (expt 10 total-digits)))))))
1115 (defmethod parse/xsd ((type decimal-type) e context)
1116 (declare (ignore context))
1117 (destructuring-bind (&optional a b)
1118 (scan-to-strings "^([+-]?\\d*)(?:[.](\\d+))?$" e)
1119 (if (plusp (+ (length a) (length b)))
1120 (+ (if (plusp (length a))
1121 (parse-integer a)
1123 (if (plusp (length b))
1124 (/ (parse-integer b) (expt 10 (length b)))
1126 :error)))
1129 ;;; double
1131 (defxsd (double-type "double") (xsd-type ordering-mixin) ())
1133 (defmethod equal-using-type ((type double-type) u v)
1134 #+(or sbcl allegro) (= u v)
1135 #-(or sbcl allegro) (float= u v))
1137 (defmethod lessp-using-type ((type double-type) u v)
1138 #+(or sbcl allegro) (< u v)
1139 #-(or sbcl allegro) (float< u v))
1141 ;; zzz nehme hier an, dass double-float in IEEE double float ist.
1142 ;; Auch das ist nicht garantiert.
1143 (defmethod parse/xsd ((type double-type) e context)
1144 (declare (ignore context))
1145 (parse-float e
1146 most-negative-double-float
1147 most-positive-double-float
1148 double-float-positive-infinity
1149 double-float-negative-infinity
1150 double-float-nan))
1153 ;;; AnyURi
1155 (defxsd (any-uri-type "anyURI") (xsd-type length-mixin) ())
1157 (defmethod equal-using-type ((type any-uri-type) u v)
1158 (equal u v))
1160 (defmethod parse/xsd ((type any-uri-type) e context)
1161 (cxml-rng::escape-uri e))
1164 ;;; QName
1165 ;;; NOTATION
1167 (defclass qname-like (xsd-type length-mixin) ())
1169 (defxsd (qname-type "QName") (qname-like) ())
1170 (defxsd (notation-type "NOTATION") (qname-like) ())
1172 (defstruct (qname (:constructor make-qname (uri lname length)))
1174 lname
1175 length)
1177 (defmethod length-using-type ((type qname-like) e)
1178 (qname-length e))
1180 (defmethod equal-using-type ((type qname-like) u v)
1181 (and (equal (qname-uri u) (qname-uri v))
1182 (equal (qname-lname u) (qname-lname v))))
1184 (defun namep (str)
1185 (and (not (zerop (length str)))
1186 (cxml::name-start-rune-p (elt str 0))
1187 (every #'cxml::name-rune-p str)))
1189 (defmethod parse/xsd ((type qname-like) e context)
1190 (handler-case
1191 (if (namep e)
1192 (multiple-value-bind (prefix local-name) (cxml::split-qname e)
1193 (let ((uri (when prefix
1194 (context-find-namespace-binding context prefix))))
1195 (if (and prefix (not uri))
1196 :error
1197 (make-qname uri local-name (length e)))))
1198 :error)
1199 (cxml:well-formedness-violation ()
1200 :error)))
1203 ;;; string
1205 (defxsd (xsd-string-type "string") (xsd-type length-mixin) ())
1207 (defmethod equal-using-type ((type xsd-string-type) u v)
1208 (equal u v))
1210 (defmethod munge-whitespace ((type xsd-string-type) e)
1213 (defmethod parse/xsd ((type xsd-string-type) e context)
1217 ;;;;
1218 ;;;; Derived types
1219 ;;;;
1221 ;;; normalizedString
1223 (defxsd (normalized-string-type "normalizedString") (xsd-string-type) ())
1225 (defmethod munge-whitespace ((type normalized-string-type) e)
1226 (replace-whitespace e))
1229 ;;; token
1231 (defxsd (xsd-token-type "token") (normalized-string-type) ())
1233 (defmethod munge-whitespace ((type xsd-token-type) e)
1234 (normalize-whitespace e))
1237 ;;; language
1239 (defxsd (language-type "language") (xsd-token-type)
1240 ((patterns :initform '("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*"))))
1243 ;;; Name
1245 (defxsd (name-type "Name") (xsd-token-type)
1246 ((patterns :initform '("\\i\\c*"))))
1249 ;;; NCName
1251 (defxsd (ncname-type "NCName") (name-type)
1252 ((patterns :initform '("[\\i-[:]][\\c-[:]]*"))))
1254 (defmethod equal-using-type ((type ncname-type) u v)
1255 (equal u v))
1257 (defun nc-name-p (str)
1258 (and (namep str) (cxml::nc-name-p str)))
1260 (defmethod parse/xsd ((type ncname-type) e context)
1261 ;; zzz mit pattern machen
1262 (if (nc-name-p e)
1264 :error))
1266 ;;; ID
1268 (defxsd (id-type "ID") (ncname-type) ())
1271 ;;; IDREF
1273 (defxsd (idref-type "IDREF") (id-type) ())
1276 ;;; IDREFS
1278 (defxsd (idrefs-type "IDREFS") (enumeration-type)
1279 ((word-type :initform (make-instance 'idref-type))))
1282 ;;; ENTITY
1284 (defxsd (entity-type "ENTITY") (ncname-type) ())
1286 (defmethod parse/xsd ((type entity-type) e context)
1287 (if (context-find-unparsed-entity context e)
1289 :error))
1292 ;;; ENTITIES
1294 (defxsd (entities-type "ENTITIES") (enumeration-type)
1295 ((word-type :initform (make-instance 'entity-type))))
1298 ;;; NMTOKEN
1300 (defxsd (nmtoken-type "NMTOKEN") (xsd-token-type)
1301 ((patterns :initform '("\\c+"))))
1304 ;;; NMTOKENS
1306 (defxsd (nmtokens-type "NMTOKENS") (enumeration-type)
1307 ((word-type :initform (make-instance 'nmtoken-type))))
1310 ;;; integer
1312 (defxsd (integer-type "integer") (decimal-type) ())
1314 ;; period is forbidden, so there's no point in letting decimal handle parsing
1315 ;; fixme: sind fuehrende nullen nun erlaubt oder nicht? die spec sagt ja,
1316 ;; das pattern im schema nicht.
1317 (defmethod parse/xsd ((type integer-type) e context)
1318 (declare (ignore context))
1319 (if (cl-ppcre:all-matches "^[+-]?(?:[1-9]\\d*|0)$" e)
1320 (parse-number:parse-number e)
1321 :error))
1324 ;;; nonPositiveInteger
1326 (defxsd (non-positive-integer-type "nonPositiveInteger") (integer-type) ())
1328 (defun min* (a b)
1329 (cond
1330 ((null a) b)
1331 ((null b) a)
1332 (t (min a b))))
1334 (defun max* (a b)
1335 (cond
1336 ((null a) b)
1337 ((null b) a)
1338 (t (max a b))))
1340 (defmethod initialize-instance :after ((type non-positive-integer-type) &key)
1341 (setf (max-inclusive type)
1342 (min* 0 (max-inclusive type))))
1345 ;;; nonPositiveInteger
1347 (defxsd (negative-integer-type "negativeInteger") (non-positive-integer-type)
1350 (defmethod initialize-instance :after ((type negative-integer-type) &key)
1351 (setf (max-inclusive type)
1352 (min* -1 (max-inclusive type))))
1355 ;;; long
1357 (defxsd (long-type "long") (integer-type) ())
1359 (defmethod initialize-instance :after ((type long-type) &key)
1360 (setf (max-inclusive type) (min* 9223372036854775807 (max-inclusive type)))
1361 (setf (min-inclusive type) (max* -9223372036854775808 (min-inclusive type))))
1364 ;;; int
1366 (defxsd (int-type "int") (long-type) ())
1368 (defmethod initialize-instance :after ((type int-type) &key)
1369 (setf (max-inclusive type) (min* 2147483647 (max-inclusive type)))
1370 (setf (min-inclusive type) (max* -2147483648 (min-inclusive type))))
1373 ;;; short
1375 (defxsd (short-type "short") (int-type) ())
1377 (defmethod initialize-instance :after ((type short-type) &key)
1378 (setf (max-inclusive type) (min* 32767 (max-inclusive type)))
1379 (setf (min-inclusive type) (max* -32768 (min-inclusive type))))
1382 ;;; byte
1384 (defxsd (byte-type "byte") (short-type) ())
1386 (defmethod initialize-instance :after ((type byte-type) &key)
1387 (setf (max-inclusive type) (min* 127 (max-inclusive type)))
1388 (setf (min-inclusive type) (max* -128 (min-inclusive type))))
1391 ;;; nonNegativeInteger
1393 (defxsd (non-negative-integer-type "nonNegativeInteger") (integer-type) ())
1395 (defmethod initialize-instance :after ((type non-negative-integer-type) &key)
1396 (setf (min-inclusive type) (max* 0 (min-inclusive type))))
1399 ;;; unsignedLong
1401 (defxsd (unsigned-long-type "unsignedLong") (non-negative-integer-type) ())
1403 (defmethod initialize-instance :after ((type unsigned-long-type) &key)
1404 (setf (max-inclusive type) (min* 18446744073709551615 (max-inclusive type))))
1407 ;;; unsignedInt
1409 (defxsd (unsigned-int-type "unsignedInt") (unsigned-long-type) ())
1411 (defmethod initialize-instance :after ((type unsigned-int-type) &key)
1412 (setf (max-inclusive type) (min* 4294967295 (max-inclusive type))))
1415 ;;; unsignedShort
1417 (defxsd (unsigned-short-type "unsignedShort") (unsigned-int-type) ())
1419 (defmethod initialize-instance :after ((type unsigned-short-type) &key)
1420 (setf (max-inclusive type) (min* 65535 (max-inclusive type))))
1423 ;;; unsignedByte
1425 (defxsd (unsigned-byte-type "unsignedByte") (unsigned-short-type) ())
1427 (defmethod initialize-instance :after ((type unsigned-byte-type) &key)
1428 (setf (max-inclusive type) (min* 255 (max-inclusive type))))
1431 ;;; positiveInteger
1433 (defxsd (positive-integer-type "positiveInteger") (non-negative-integer-type)
1436 (defmethod initialize-instance :after ((type positive-integer-type) &key)
1437 (setf (min-inclusive type) (max* 1 (min-inclusive type))))