Function: soap-decode-xs-complex-type

soap-decode-xs-complex-type is a byte-compiled function defined in soap-client.el.gz.

Signature

(soap-decode-xs-complex-type TYPE NODE)

Documentation

Use TYPE, a soap-xs-complex-type, to decode the contents of NODE.

A LISP value is returned based on the contents of NODE and the type-info stored in TYPE.

This is a specialization of soap-decode-type for soap-xs-basic-type objects.

Source Code

;; Defined in /usr/src/emacs/lisp/net/soap-client.el.gz
(defun soap-decode-xs-complex-type (type node)
  "Use TYPE, a `soap-xs-complex-type', to decode the contents of NODE.
A LISP value is returned based on the contents of NODE and the
type-info stored in TYPE.

This is a specialization of `soap-decode-type' for
`soap-xs-basic-type' objects."
  (cl-case (soap-xs-complex-type-indicator type)
    (array
     (let ((result nil)
           (element-type (soap-xs-complex-type-base type)))
       (dolist (node (xml-node-children node))
         (when (consp node)
           (push (soap-decode-type element-type node) result)))
       (nreverse result)))
    ((sequence choice all nil)
     (let ((result nil)
           (base (soap-xs-complex-type-base type)))
       (when base
         (setq result (nreverse (soap-decode-type base node))))
       (catch 'done
         (dolist (element (soap-xs-complex-type-elements type))
           (let* ((instance-count 0)
                  (e-name (soap-xs-element-name element))
                  ;; Heuristic: guess if we need to decode using local
                  ;; namespaces.
                  (use-fq-names (string-match ":" (symbol-name (car node))))
                  (children (if e-name
                                (if use-fq-names
                                    ;; Find relevant children
                                    ;; using local namespaces by
                                    ;; searching for the element's
                                    ;; fully-qualified name.
                                    (soap-xml-get-children-fq
                                     node
                                     (soap-xs-element-get-fq-name
                                      element soap-current-wsdl))
                                  ;; No local namespace resolution
                                  ;; needed so use the element's
                                  ;; name unqualified.
                                  (xml-get-children node (intern e-name)))
                              ;; e-name is nil so a) we don't know which
                              ;; children to operate on, and b) we want to
                              ;; reuse soap-decode-xs-complex-type, which
                              ;; expects a node argument with a complex
                              ;; type; therefore we need to operate on the
                              ;; entire node.  We wrap node in a list so
                              ;; that it will carry through as "node" in the
                              ;; loop below.
                              ;;
                              ;; For example:
                              ;;
                              ;; Element Type:
                              ;; <xs:complexType name="A">
                              ;;  <xs:sequence>
                              ;;   <xs:element name="B" type="t:BType"/>
                              ;;   <xs:choice>
                              ;;    <xs:element name="C" type="xs:string"/>
                              ;;    <xs:element name="D" type="t:DType"/>
                              ;;   </xs:choice>
                              ;;  </xs:sequence>
                              ;; </xs:complexType>
                              ;;
                              ;; Node:
                              ;; <t:A>
                              ;;   <t:B tag="b"/>
                              ;;   <t:C>1</C>
                              ;; </t:A>
                              ;;
                              ;; soap-decode-type will be called below with:
                              ;;
                              ;; element =
                              ;;   <xs:choice>
                              ;;     <xs:element name="C" type="xs:string"/>
                              ;;     <xs:element name="D" type="t:DType"/>
                              ;;   </xs:choice>
                              ;; node =
                              ;;   <t:A>
                              ;;     <t:B tag="b"/>
                              ;;     <t:C>1</C>
                              ;;   </t:A>
                              (list node)))
                  (element-type (soap-xs-element-type element)))
             (dolist (node children)
               (cl-incf instance-count)
               (let* ((attributes
                       (soap-decode-xs-attributes element-type node))
                      ;; Attributes may specify xsi:type override.
                      (element-type
                       (if (soap-xml-get-attribute-or-nil1 node 'xsi:type)
                           (soap-wsdl-get
                            (soap-l2fq
                             (soap-xml-get-attribute-or-nil1 node
                                                             'xsi:type))
                            soap-current-wsdl 'soap-xs-type-p t)
                         element-type))
                      (decoded-child (soap-decode-type element-type node)))
                 (if e-name
                     (push (cons (intern e-name)
                                 (append attributes decoded-child)) result)
                   ;; When e-name is nil we don't want to introduce an extra
                   ;; level of nesting, so we splice the decoding into
                   ;; result.
                   (setq result (append decoded-child result)))))
             (cond ((and (eq (soap-xs-complex-type-indicator type) 'choice)
                         ;; Choices can allow multiple values.
                         (not (soap-xs-complex-type-multiple-p type))
                         (> instance-count 0))
                    ;; This was a choice node, and we decoded one value.
                    (throw 'done t))

                   ;; Do some sanity checking
                   ((and (not (eq (soap-xs-complex-type-indicator type)
                                  'choice))
                         (= instance-count 0)
                         (not (soap-xs-element-optional? element))
                         (and (soap-xs-complex-type-p element-type)
                              (not (soap-xs-complex-type-optional-p
                                    element-type))))
                    (soap-warning "missing non-nillable slot %s" e-name))
                   ((and (> instance-count 1)
                         (not (soap-xs-complex-type-multiple-p type))
                         (not (soap-xs-element-multiple? element))
                         (and (soap-xs-complex-type-p element-type)
                              (not (soap-xs-complex-type-multiple-p
                                    element-type))))
                    (soap-warning "expected single %s slot, found multiple"
                                  e-name))))))
       (nreverse result)))
    (t
     (error "Don't know how to decode complex type: %s"
            (soap-xs-complex-type-indicator type)))))