1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 """
18 Provides base classes for XML->object I{unmarshalling}.
19 """
20
21 from logging import getLogger
22 from suds import *
23 from suds.umx import *
24 from suds.umx.attrlist import AttrList
25 from suds.sax.text import Text
26 from suds.sudsobject import Factory, merge
27
28
29 log = getLogger(__name__)
30
31 reserved = { 'class':'cls', 'def':'dfn', }
32
34 """
35 The abstract XML I{node} unmarshaller. This class provides the
36 I{core} unmarshalling functionality.
37 """
38
40 """
41 Process an object graph representation of the xml I{node}.
42 @param content: The current content being unmarshalled.
43 @type content: L{Content}
44 @return: A suds object.
45 @rtype: L{Object}
46 """
47 self.reset()
48 return self.append(content)
49
51 """
52 Process the specified node and convert the XML document into
53 a I{suds} L{object}.
54 @param content: The current content being unmarshalled.
55 @type content: L{Content}
56 @return: A I{append-result} tuple as: (L{Object}, I{value})
57 @rtype: I{append-result}
58 @note: This is not the proper entry point.
59 @see: L{process()}
60 """
61 self.start(content)
62 self.append_attributes(content)
63 self.append_children(content)
64 self.append_text(content)
65 self.end(content)
66 return self.postprocess(content)
67
68 - def postprocess(self, content):
69 """
70 Perform final processing of the resulting data structure as follows:
71 - Mixed values (children and text) will have a result of the I{content.node}.
72 - Simi-simple values (attributes, no-children and text) will have a result of a
73 property object.
74 - Simple values (no-attributes, no-children with text nodes) will have a string
75 result equal to the value of the content.node.getText().
76 @param content: The current content being unmarshalled.
77 @type content: L{Content}
78 @return: The post-processed result.
79 @rtype: I{any}
80 """
81 node = content.node
82 if len(node.children) and node.hasText():
83 return node
84 attributes = AttrList(node.attributes)
85 if attributes.rlen() and \
86 not len(node.children) and \
87 node.hasText():
88 p = Factory.property(node.name, node.getText())
89 return merge(content.data, p)
90 if len(content.data):
91 return content.data
92 lang = attributes.lang()
93 if content.node.isnil():
94 return None
95 if not len(node.children) and content.text is None:
96 if self.nillable(content):
97 return None
98 else:
99 return Text('', lang=lang)
100 if isinstance(content.text, basestring):
101 return Text(content.text, lang=lang)
102 else:
103 return content.text
104
106 """
107 Append attribute nodes into L{Content.data}.
108 Attributes in the I{schema} or I{xml} namespaces are skipped.
109 @param content: The current content being unmarshalled.
110 @type content: L{Content}
111 """
112 attributes = AttrList(content.node.attributes)
113 for attr in attributes.real():
114 name = attr.name
115 value = attr.value
116 self.append_attribute(name, value, content)
117
119 """
120 Append an attribute name/value into L{Content.data}.
121 @param name: The attribute name
122 @type name: basestring
123 @param value: The attribute's value
124 @type value: basestring
125 @param content: The current content being unmarshalled.
126 @type content: L{Content}
127 """
128 key = name
129 key = '_%s' % reserved.get(key, key)
130 setattr(content.data, key, value)
131
133 """
134 Append child nodes into L{Content.data}
135 @param content: The current content being unmarshalled.
136 @type content: L{Content}
137 """
138 for child in content.node:
139 cont = Content(child)
140 cval = self.append(cont)
141 key = reserved.get(child.name, child.name)
142 if key in content.data:
143 v = getattr(content.data, key)
144 if isinstance(v, list):
145 v.append(cval)
146 else:
147 setattr(content.data, key, [v, cval])
148 continue
149 if self.unbounded(cont):
150 if cval is None:
151 setattr(content.data, key, [])
152 else:
153 setattr(content.data, key, [cval,])
154 else:
155 setattr(content.data, key, cval)
156
157 - def append_text(self, content):
158 """
159 Append text nodes into L{Content.data}
160 @param content: The current content being unmarshalled.
161 @type content: L{Content}
162 """
163 if content.node.hasText():
164 content.text = content.node.getText()
165
168
169 - def start(self, content):
170 """
171 Processing on I{node} has started. Build and return
172 the proper object.
173 @param content: The current content being unmarshalled.
174 @type content: L{Content}
175 @return: A subclass of Object.
176 @rtype: L{Object}
177 """
178 content.data = Factory.object(content.node.name)
179
180 - def end(self, content):
181 """
182 Processing on I{node} has ended.
183 @param content: The current content being unmarshalled.
184 @type content: L{Content}
185 """
186 pass
187
189 """
190 Get whether the content is bounded (not a list).
191 @param content: The current content being unmarshalled.
192 @type content: L{Content}
193 @return: True if bounded, else False
194 @rtype: boolean
195 '"""
196 return ( not self.unbounded(content) )
197
199 """
200 Get whether the object is unbounded (a list).
201 @param content: The current content being unmarshalled.
202 @type content: L{Content}
203 @return: True if unbounded, else False
204 @rtype: boolean
205 '"""
206 return False
207
209 """
210 Get whether the object is nillable.
211 @param content: The current content being unmarshalled.
212 @type content: L{Content}
213 @return: True if nillable, else False
214 @rtype: boolean
215 '"""
216 return False
217