Update of /project/cl-soap/cvsroot/cl-soap/src
In directory common-lisp.net:/tmp/cvs-serv26088/src
Modified Files:
wsdl.lisp xsd.lisp
Log Message:
more work on xsd type handling in wsdl-soap-call
more specifically type element multiplicity
added some simple experimental wsdl caching
Date: Thu Sep 22 17:30:00 2005
Author: scaekenberghe
Index: cl-soap/src/wsdl.lisp
diff -u cl-soap/src/wsdl.lisp:1.10 cl-soap/src/wsdl.lisp:1.11
--- cl-soap/src/wsdl.lisp:1.10 Wed Sep 21 19:08:03 2005
+++ cl-soap/src/wsdl.lisp Thu Sep 22 17:29:59 2005
@@ -1,6 +1,6 @@
;;;; -*- mode: lisp -*-
;;;;
-;;;; $Id: wsdl.lisp,v 1.10 2005/09/21 17:08:03 scaekenberghe Exp $
+;;;; $Id: wsdl.lisp,v 1.11 2005/09/22 15:29:59 scaekenberghe Exp $
;;;;
;;;; The basic WSDL protocol: we parse the generic and soap specific parts
;;;;
@@ -342,7 +342,7 @@
(remove-if-not #'(lambda (c) (eql c class)) (get-extensions wsdl-extensions-mixin) :key #'class-of)))
(defmethod get-element-named ((wsdl-document-definitions wsdl-document-definitions) element-name)
- (find-item-named element-name (get-elements (first (get-types wsdl-document-definitions)))))
+ (get-element-named (first (get-types wsdl-document-definitions)) element-name))
;; Describing WSDL
@@ -391,15 +391,22 @@
(get-elements (first (get-types wsdl-document-definitions)))))
(namespace (s-xml:find-namespace (get-target-namespace wsdl-document-definitions))))
(cond ((and (stringp element-type) (xsd-primitive-type-name-p element-type))
- `(,(intern (get-name element) (s-xml:get-package namespace))
- ,(lisp->xsd-primitive (get-name-binding (get-name element) bindings)
- (intern-xsd-type-name element-type))))
+ (let ((value (get-name-binding (get-name element) bindings)))
+ (if value
+ `(,(intern (get-name element) (s-xml:get-package namespace))
+ ,(lisp->xsd-primitive value (intern-xsd-type-name element-type)))
+ (if (zerop (get-min-occurs element))
+ nil
+ (error "Cannot find binding for ~a" (get-name element))))))
((typep element-type 'xsd-complex-type)
(let ((members (get-members element-type))
(member-actual-bindings '()))
(loop :for member :in members :do
- (push (bind-element member bindings wsdl-document-definitions)
- member-actual-bindings))
+ (let* ((sub-bindings (or (get-name-binding (get-name element-type) bindings)
+ bindings))
+ (member-binding (bind-element member sub-bindings wsdl-document-definitions)))
+ (if member-binding
+ (push member-binding member-actual-bindings))))
`(,(intern (get-name element) (s-xml:get-package namespace))
,@(nreverse member-actual-bindings))))
(t (error "Cannot bind element ~s of type ~s" element element-type)))))
@@ -416,7 +423,8 @@
xsi::|type| ,part-type)
,(lisp->xsd-primitive value (intern-xsd-type-name part-type)))
actual-input-parameters)
- (error "No input binding found for ~a:~a" (get-name input-message) (get-name part)))))
+ (unless (zerop (get-min-occurs part-element))
+ (error "No input binding found for ~a:~a" (get-name input-message) (get-name part))))))
(part-element
(push (bind-element part-element input wsdl-document-definitions)
actual-input-parameters))
@@ -450,17 +458,27 @@
(cond ((and (stringp element-type) (xsd-primitive-type-name-p element-type))
(let ((tag-name (intern (get-name element) (s-xml:get-package namespace))))
(if (eql (lxml-get-tag lxml) tag-name)
- (xsd-primitive->lisp (second lxml) (intern-xsd-type-name element-type))
- (error "Expected a <~a> element" tag-name))))
+ (values (xsd-primitive->lisp (second lxml) (intern-xsd-type-name element-type)) t)
+ (if (zerop (get-min-occurs element))
+ (values nil nil)
+ (error "Expected a <~a> element" tag-name)))))
((typep element-type 'xsd-complex-type)
(let ((tag-name (intern (get-name element) (s-xml:get-package namespace)))
(members (get-members element-type)))
(if (eql (lxml-get-tag lxml) tag-name)
- (loop :for member :in members :collect
- (let* ((sub-tag-name (intern (get-name member) (s-xml:get-package namespace)))
- (sub-lxml (lxml-find-tag sub-tag-name (rest lxml))))
- (resolve-element member sub-lxml wsdl-document-definitions)))
- (error "Expected a <~a> element" tag-name))))
+ (let ((resolved-members '()))
+ (loop :for member :in members :do
+ (let* ((sub-tag-name (intern (get-name member) (s-xml:get-package namespace)))
+ (sub-lxml (lxml-find-tag sub-tag-name (rest lxml))))
+ (multiple-value-bind (value required)
+ (resolve-element member sub-lxml wsdl-document-definitions)
+ (when required
+ (push (get-name element) resolved-members)
+ (push value resolved-members)))))
+ (values (nreverse resolved-members) t))
+ (if (zerop (get-min-occurs element))
+ (values nil nil)
+ (error "Expected a <~a> element" tag-name)))))
(t (error "Cannot bind element ~s of type ~s" element element-type)))))
(defun bind-output-parts (result output-message output wsdl-document-definitions)
@@ -517,7 +535,7 @@
:|xmlns|
,input-namespace-uri))
;; we assume there is only one result
- (values (first (bind-output-parts result output-message output wsdl-document-definitions))
+ (values (bind-output-parts result output-message output wsdl-document-definitions)
headers))))
(defun wsdl-soap-rpc-call (wsdl-document-definitions
Index: cl-soap/src/xsd.lisp
diff -u cl-soap/src/xsd.lisp:1.4 cl-soap/src/xsd.lisp:1.5
--- cl-soap/src/xsd.lisp:1.4 Wed Sep 21 19:08:03 2005
+++ cl-soap/src/xsd.lisp Thu Sep 22 17:30:00 2005
@@ -1,6 +1,6 @@
;;;; -*- mode: lisp -*-
;;;;
-;;;; $Id: xsd.lisp,v 1.4 2005/09/21 17:08:03 scaekenberghe Exp $
+;;;; $Id: xsd.lisp,v 1.5 2005/09/22 15:30:00 scaekenberghe Exp $
;;;;
;;;; A partial implementation of the XML Schema Definition standard
;;;;
@@ -25,8 +25,8 @@
(defclass xml-schema-element (children-mixin)
((name :accessor get-name :initarg :name :initform nil)
(type :accessor get-type :initarg :type :initform nil)
- (min-occurs :accessor get-min-occurs :initarg :min-occurs :initform 0)
- (max-occurs :accessor get-max-occurs :initarg :max-occurs :initform :unbounded)))
+ (min-occurs :accessor get-min-occurs :initarg :min-occurs :initform 1)
+ (max-occurs :accessor get-max-occurs :initarg :max-occurs :initform 1)))
(defmethod print-object ((object xml-schema-element) out)
(print-unreadable-object (object out :type t :identity t)
@@ -143,6 +143,9 @@
;;; Interpreting the XSD model
+(defmethod get-element-named ((xml-schema-definition xml-schema-definition) element-name)
+ (find-item-named element-name (get-elements xml-schema-definition)))
+
(defmethod get-type-in-context ((xsd-simple-type xsd-simple-type) elements)
"For now: return the base type of the restriction child of the simple-type, if any"
(declare (ignore elements))
@@ -180,6 +183,122 @@
(typep first-child 'xsd-sequence))
(get-children first-child))))
+;;; Describing XSD (with pre-rendering of XML)
+
+(defun indent (n)
+ (loop :repeat n :do (write-char #\space) (write-char #\space)))
+
+(defmethod describe-multiplicity ((xml-schema-element xml-schema-element))
+ (with-slots (min-occurs max-occurs)
+ xml-schema-element
+ (cond ((and (zerop min-occurs) (eql max-occurs 1)) "optional")
+ ((and (eql min-occurs 1) (eql max-occurs 1)) "required")
+ ((and (eql min-occurs 1) (eql max-occurs :unbounded)) "one or more")
+ ((and (zerop min-occurs) (eql max-occurs :unbounded)) "zero or more")
+ (t (format nil "min:~d-max:~d" min-occurs max-occurs)))))
+
+(defmethod multiplicity-suffix ((xml-schema-element xml-schema-element))
+ (with-slots (min-occurs max-occurs)
+ xml-schema-element
+ (cond ((and (zerop min-occurs) (eql max-occurs 1)) "?")
+ ((and (eql min-occurs 1) (eql max-occurs 1)) "")
+ ((and (eql min-occurs 1) (eql max-occurs :unbounded)) "+")
+ ((and (zerop min-occurs) (eql max-occurs :unbounded)) "*")
+ (t (format nil "~d:~d" min-occurs max-occurs)))))
+
+(defun pre-render-xsd-type (xml-schema-definition type-name level)
+ (let* ((type-element (get-element-named xml-schema-definition type-name))
+ (type (get-element-type xml-schema-definition type-name)))
+ (if (typep type-element 'xsd-complex-type)
+ (let ((members (get-members type-element)))
+ (loop :for member :in members :do
+ (let ((member-name (get-name member))
+ (member-type (get-type member)))
+ (indent level)
+ (if (xsd-primitive-type-name-p member-type)
+ (format t " <~a>~a</~a>~a~%"
+ member-name member-type member-name (multiplicity-suffix member))
+ (progn
+ (format t " <~a>~%" member-name)
+ (pre-render-xsd-type xml-schema-definition member-type (1+ level))
+ (indent level)
+ (format t " </~a>~a~%" member-name (multiplicity-suffix member)))))))
+ (if (xsd-primitive-type-name-p type)
+ (progn
+ (indent level)
+ (format t " ~a~%" type))
+ (error "unexpected type")))))
+
+(defun describe-xsd-type (xml-schema-definition type-name level)
+ (let* ((type-element (get-element-named xml-schema-definition type-name))
+ (type (get-element-type xml-schema-definition type-name)))
+ (if (typep type-element 'xsd-complex-type)
+ (let ((members (get-members type-element)))
+ (loop :for member :in members :do
+ (let ((member-name (get-name member))
+ (member-type (get-type member)))
+ (indent level)
+ (if (xsd-primitive-type-name-p member-type)
+ (format t " Member ~s of primitive type ~s [~a]~%"
+ member-name member-type (describe-multiplicity member))
+ (progn
+ (format t " Member ~s [~a]~%" member-name (describe-multiplicity member))
+ (describe-xsd-type xml-schema-definition member-type (1+ level)))))))
+ (if (xsd-primitive-type-name-p type)
+ (progn
+ (indent level)
+ (format t " primitive type ~a~%" type))
+ (error "unexpected type")))))
+
+(defun describe-xsd-element (xml-schema-definition element level)
+ (let* ((element-name (get-name element))
+ (element-type (get-element-type xml-schema-definition element-name)))
+ (if (xsd-primitive-type-name-p element-type)
+ (progn
+ (indent level)
+ (format t "Element ~s of primitive type ~s [~a]~%"
+ element-name element-type (describe-multiplicity element))
+ (indent level)
+ (format t " <~a>~a</~a>~a~%" element-name element-type element-name (multiplicity-suffix element)))
+ (let ((members (get-members element-type)))
+ (indent level)
+ (format t "Element ~s [~a]~%" element-name (describe-multiplicity element))
+ (loop :for member :in members :do
+ (let ((member-name (get-name member))
+ (member-type (get-type member)))
+ (indent level)
+ (if (xsd-primitive-type-name-p member-type)
+ (format t " Member ~s of primitive type ~s [~a]~%"
+ member-name member-type (describe-multiplicity member))
+ (progn
+ (format t " Member ~s [~a]~%" member-name (describe-multiplicity member))
+ (describe-xsd-type xml-schema-definition member-type (1+ level))))))
+ (indent level)
+ (format t " <~a>~%" element-name)
+ (loop :for member :in members :do
+ (let ((member-name (get-name member))
+ (member-type (get-type member)))
+ (indent level)
+ (if (xsd-primitive-type-name-p member-type)
+ (format t " <~a>~a</~a>~a~%"
+ member-name member-type member-name (multiplicity-suffix member))
+ (progn
+ (format t " <~a>~%" member-name)
+ (pre-render-xsd-type xml-schema-definition member-type (1+ level))
+ (indent level)
+ (format t " </~a>~a~%" member-name (multiplicity-suffix member))))))
+ (indent level)
+ (format t " </~a>~a~%" element-name (multiplicity-suffix element))))))
+
+(defun describe-xsd (xml-schema-definition)
+ "Print a high-level description of the top-level elements in xml-schema-definition"
+ (format t "XML Schema Definition with target-namespace URI ~s~%"
+ (get-target-namespace xml-schema-definition))
+ (loop :for element :in (get-elements xml-schema-definition) :do
+ (when (typep element 'xml-schema-element)
+ (describe-xsd-element xml-schema-definition element 1)))
+ (values))
+
;;; Primitive Types/Values (types are keywords)
(defconstant +known-primitive-type-names+
@@ -196,7 +315,8 @@
"base64Binary" "hexBinary"))
(defun xsd-primitive-type-name-p (name)
- (member (actual-name name) +known-primitive-type-names+ :test #'string-equal))
+ (and (stringp name)
+ (member (actual-name name) +known-primitive-type-names+ :test #'string-equal)))
(defun intern-xsd-type-name (name)
(intern (string-upcase (actual-name name)) :keyword))