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