root/trunk/bknr/datastore/src/xml-impex/xml-export.lisp

Revision 2530, 5.8 kB (checked in by hhubner, 11 months ago)

refactor, remove warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to author date id revision
Line 
1 (in-package :bknr.impex)
2
3 (defmethod slot-serialize-value ((slot xml-effective-slot-definition) value)
4   (with-slots (serializer object-to-id) slot
5     (when object-to-id
6       (setf value (funcall object-to-id value)))
7     (when serializer
8       (setf value (funcall serializer value)))))
9
10 (defvar *objects-written*)
11
12 (defmacro with-xml-export* ((&key output indentation canonical) &body body)
13   `(let ((*objects-written* (make-hash-table :test #'equal))
14          (cxml::*current-element* nil)
15          (cxml::*sink* (cxml:make-character-stream-sink ,output
16                                                         :indentation ,indentation :canonical ,canonical)))
17      ,@body))
18
19 (defmacro with-xml-export (nil &body body)
20   `(with-xml-export* (:output *standard-output* :indentation 1 :canonical nil)
21      ,@body))
22
23 (defun write-object-reference (class object unique-id-slot-name name)
24   (let ((slotdef (find unique-id-slot-name (class-slots class) :key #'slot-definition-name)))
25     (unless (xml-effective-slot-definition-attribute slotdef)
26       (error "Slot ~A is not defined as :attribute slot and cannot be used as unique-id slot for class ~A" unique-id-slot-name (class-name class)))
27     (sax:start-element cxml::*sink* nil nil name
28                        (list (sax:make-attribute :qname (cxml::string-rod (xml-effective-slot-definition-attribute slotdef))
29                                                  :value (cxml::string-rod (slot-serialize-value slotdef (slot-value object unique-id-slot-name))))))
30     (sax:end-element cxml::*sink* nil nil name)))
31
32 (defgeneric write-to-xml (object &key)
33   (:documentation "Write OBJECT to XML stream")
34
35   (:method ((object (eql nil)) &key))
36
37   (:method ((object list) &key (name (error "Can not serialize list to XML without an element name~%")))
38     (sax:start-element cxml::*sink* nil nil (cxml::string-rod name) nil)
39     (dolist (obj object)
40       (write-to-xml obj))
41     (sax:end-element cxml::*sink* nil nil (cxml::string-rod name)))
42
43   (:method ((object string) &key (name (error "Can not serialize string ~A to XML without an element name." object)))
44     (sax:start-element cxml::*sink* nil nil (cxml::string-rod name) nil)
45     (sax:characters cxml::*sink* (cxml::string-rod object))
46     (sax:end-element cxml::*sink* nil nil (cxml::string-rod name)))
47
48   (:method ((object standard-object) &key)
49     (cxml:with-element (string-downcase (class-name (class-of object)))
50       (dolist (slot (class-slots (class-of object)))
51         (cxml:with-element (string-downcase (symbol-name (slot-definition-name slot)))
52           (let ((value (slot-value object (slot-definition-name slot))))
53             (when value
54               (cxml:text (handler-case
55                              (cxml::utf8-string-to-rod (princ-to-string value))
56                            (error (e)
57                              (declare (ignore e))
58                              (cxml::utf8-string-to-rod "[unprintable]"))))))))))
59
60   (:method ((object xml-class) &key name)
61     (xml-object-check-validity object)
62     (let* ((class (class-of object))
63            (qname (cxml::string-rod (or name (xml-class-element class)))))
64      
65       ;; If this object has been serialized to the XML stream,
66       ;; write a reference to the object and return.
67
68       (with-slots (unique-id-slot) class
69         (when unique-id-slot
70           (if (gethash (slot-value object (first unique-id-slot)) *objects-written*)
71               (progn
72                 (write-object-reference class object (first unique-id-slot) qname)
73                 (return-from write-to-xml))
74               (setf (gethash (slot-value object (first unique-id-slot)) *objects-written*) t))))
75
76       ;; Object has not been written to the XML file or no
77       ;; unique-id-slot is defined for this class.
78
79       (let* ((attr-slots (xml-class-attribute-slots class))
80              (elt-slots (xml-class-element-slots class))
81              (body-slot (xml-class-body-slot class))
82              ;; attributes
83              (attributes (loop for slot in attr-slots
84                                for name = (slot-definition-name slot)
85                                for attdef = (cxml::string-rod (xml-effective-slot-definition-attribute slot))
86                                when (and (slot-boundp object name)
87                                          (slot-value object name))
88                                collect (sax:make-attribute
89                                         :qname attdef
90                                         :value
91                                         (cxml::string-rod
92                                          (slot-serialize-value slot (slot-value object name)))))))
93         (sax:start-element cxml::*sink* nil nil qname attributes)
94
95         ;; elements
96         (dolist (slot elt-slots)
97           (let ((name (slot-definition-name slot))
98                 (element-name (xml-effective-slot-definition-element slot)))
99             (when (slot-boundp object name)
100               (if (consp (slot-value object name))
101                   (dolist (child (slot-value object name))
102                     (if (typep (class-of child) 'xml-class)
103                         (write-to-xml child)
104                         (write-to-xml (slot-serialize-value slot child) :name element-name)))
105                   (let ((child (slot-value object name)))
106                     (if (typep (class-of child) 'xml-class)
107                         (write-to-xml child)
108                         (write-to-xml (slot-serialize-value slot child) :name element-name)))))))
109
110         ;; body slot
111         (when body-slot
112           (let ((name (slot-definition-name body-slot)))
113             (when (slot-boundp object name)
114               (sax:characters
115                cxml::*sink*
116                (cxml::string-rod
117                 (funcall (xml-effective-slot-definition-serializer body-slot)
118                          (slot-value object name)))))))
119        
120         (sax:end-element cxml::*sink* nil nil qname)))))
Note: See TracBrowser for help on using the browser.