/suds/mx/appender.py

https://github.com/geo-data/medin-rdbms-tool
Python | 310 lines | 137 code | 48 blank | 125 comment | 19 complexity | 01e27435642562fdd98458f14fd8cfd5 MD5 | raw file
  1. # This program is free software; you can redistribute it and/or modify
  2. # it under the terms of the (LGPL) GNU Lesser General Public License as
  3. # published by the Free Software Foundation; either version 3 of the
  4. # License, or (at your option) any later version.
  5. #
  6. # This program is distributed in the hope that it will be useful,
  7. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  9. # GNU Library Lesser General Public License for more details at
  10. # ( http://www.gnu.org/licenses/lgpl.html ).
  11. #
  12. # You should have received a copy of the GNU Lesser General Public License
  13. # along with this program; if not, write to the Free Software
  14. # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  15. # written by: Jeff Ortel ( jortel@redhat.com )
  16. """
  17. Provides appender classes for I{marshalling}.
  18. """
  19. from logging import getLogger
  20. from suds import *
  21. from suds.mx import *
  22. from suds.sudsobject import footprint
  23. from suds.sudsobject import Object, Property
  24. from suds.sax.element import Element
  25. from suds.sax.text import Text
  26. from copy import deepcopy
  27. log = getLogger(__name__)
  28. class Matcher:
  29. """
  30. Appender matcher.
  31. @ivar cls: A class object.
  32. @type cls: I{classobj}
  33. """
  34. def __init__(self, cls):
  35. """
  36. @param cls: A class object.
  37. @type cls: I{classobj}
  38. """
  39. self.cls = cls
  40. def __eq__(self, x):
  41. if self.cls is None:
  42. return ( x is None )
  43. else:
  44. return isinstance(x, self.cls)
  45. class ContentAppender:
  46. """
  47. Appender used to add content to marshalled objects.
  48. @ivar default: The default appender.
  49. @type default: L{Appender}
  50. @ivar appenders: A I{table} of appenders mapped by class.
  51. @type appenders: I{table}
  52. """
  53. def __init__(self, marshaller):
  54. """
  55. @param marshaller: A marshaller.
  56. @type marshaller: L{suds.mx.core.Core}
  57. """
  58. self.default = PrimativeAppender(marshaller)
  59. self.appenders = (
  60. (Matcher(None),
  61. NoneAppender(marshaller)),
  62. (Matcher(null),
  63. NoneAppender(marshaller)),
  64. (Matcher(Property),
  65. PropertyAppender(marshaller)),
  66. (Matcher(Object),
  67. ObjectAppender(marshaller)),
  68. (Matcher(Element),
  69. ElementAppender(marshaller)),
  70. (Matcher(Text),
  71. TextAppender(marshaller)),
  72. (Matcher(list),
  73. ListAppender(marshaller)),
  74. (Matcher(tuple),
  75. ListAppender(marshaller)),
  76. (Matcher(dict),
  77. DictAppender(marshaller)),
  78. )
  79. def append(self, parent, content):
  80. """
  81. Select an appender and append the content to parent.
  82. @param parent: A parent node.
  83. @type parent: L{Element}
  84. @param content: The content to append.
  85. @type content: L{Content}
  86. """
  87. appender = self.default
  88. for a in self.appenders:
  89. if a[0] == content.value:
  90. appender = a[1]
  91. break
  92. appender.append(parent, content)
  93. class Appender:
  94. """
  95. An appender used by the marshaller to append content.
  96. @ivar marshaller: A marshaller.
  97. @type marshaller: L{suds.mx.core.Core}
  98. """
  99. def __init__(self, marshaller):
  100. """
  101. @param marshaller: A marshaller.
  102. @type marshaller: L{suds.mx.core.Core}
  103. """
  104. self.marshaller = marshaller
  105. def node(self, content):
  106. """
  107. Create and return an XML node that is qualified
  108. using the I{type}. Also, make sure all referenced namespace
  109. prefixes are declared.
  110. @param content: The content for which proccessing has ended.
  111. @type content: L{Object}
  112. @return: A new node.
  113. @rtype: L{Element}
  114. """
  115. return self.marshaller.node(content)
  116. def setnil(self, node, content):
  117. """
  118. Set the value of the I{node} to nill.
  119. @param node: A I{nil} node.
  120. @type node: L{Element}
  121. @param content: The content for which proccessing has ended.
  122. @type content: L{Object}
  123. """
  124. self.marshaller.setnil(node, content)
  125. def setdefault(self, node, content):
  126. """
  127. Set the value of the I{node} to a default value.
  128. @param node: A I{nil} node.
  129. @type node: L{Element}
  130. @param content: The content for which proccessing has ended.
  131. @type content: L{Object}
  132. @return: The default.
  133. """
  134. return self.marshaller.setdefault(node, content)
  135. def optional(self, content):
  136. """
  137. Get whether the specified content is optional.
  138. @param content: The content which to check.
  139. @type content: L{Content}
  140. """
  141. return self.marshaller.optional(content)
  142. def suspend(self, content):
  143. """
  144. Notify I{marshaller} that appending this content has suspended.
  145. @param content: The content for which proccessing has been suspended.
  146. @type content: L{Object}
  147. """
  148. self.marshaller.suspend(content)
  149. def resume(self, content):
  150. """
  151. Notify I{marshaller} that appending this content has resumed.
  152. @param content: The content for which proccessing has been resumed.
  153. @type content: L{Object}
  154. """
  155. self.marshaller.resume(content)
  156. def append(self, parent, content):
  157. """
  158. Append the specified L{content} to the I{parent}.
  159. @param content: The content to append.
  160. @type content: L{Object}
  161. """
  162. self.marshaller.append(parent, content)
  163. class PrimativeAppender(Appender):
  164. """
  165. An appender for python I{primative} types.
  166. """
  167. def append(self, parent, content):
  168. if content.tag.startswith('_'):
  169. attr = content.tag[1:]
  170. value = tostr(content.value)
  171. if value is not None and len(value):
  172. parent.set(attr, value)
  173. else:
  174. child = self.node(content)
  175. child.setText(tostr(content.value))
  176. parent.append(child)
  177. class NoneAppender(Appender):
  178. """
  179. An appender for I{None} values.
  180. """
  181. def append(self, parent, content):
  182. child = self.node(content)
  183. default = self.setdefault(child, content)
  184. if default is None:
  185. self.setnil(child, content)
  186. parent.append(child)
  187. class PropertyAppender(Appender):
  188. """
  189. A L{Property} appender.
  190. """
  191. def append(self, parent, content):
  192. p = content.value
  193. child = self.node(content)
  194. child.setText(p.get())
  195. parent.append(child)
  196. for item in p.items():
  197. cont = Content(tag=item[0], value=item[1])
  198. Appender.append(self, child, cont)
  199. class ObjectAppender(Appender):
  200. """
  201. An L{Object} appender.
  202. """
  203. def append(self, parent, content):
  204. object = content.value
  205. if self.optional(content) and footprint(object) == 0:
  206. return
  207. child = self.node(content)
  208. parent.append(child)
  209. for item in object:
  210. cont = Content(tag=item[0], value=item[1])
  211. Appender.append(self, child, cont)
  212. class DictAppender(Appender):
  213. """
  214. An python I{dict} appender.
  215. """
  216. def append(self, parent, content):
  217. d = content.value
  218. if self.optional(content) and len(d) == 0:
  219. return
  220. child = self.node(content)
  221. parent.append(child)
  222. for item in d.items():
  223. cont = Content(tag=item[0], value=item[1])
  224. Appender.append(self, child, cont)
  225. class ElementWrapper(Element):
  226. """
  227. Element wrapper.
  228. """
  229. def __init__(self, content):
  230. Element.__init__(self, content.name, content.parent)
  231. self.__content = content
  232. def str(self, indent=0):
  233. return self.__content.str(indent)
  234. class ElementAppender(Appender):
  235. """
  236. An appender for I{Element} types.
  237. """
  238. def append(self, parent, content):
  239. if content.tag.startswith('_'):
  240. raise Exception('raw XML not valid as attribute value')
  241. child = ElementWrapper(content.value)
  242. parent.append(child)
  243. class ListAppender(Appender):
  244. """
  245. A list/tuple appender.
  246. """
  247. def append(self, parent, content):
  248. collection = content.value
  249. if len(collection):
  250. self.suspend(content)
  251. for item in collection:
  252. cont = Content(tag=content.tag, value=item)
  253. Appender.append(self, parent, cont)
  254. self.resume(content)
  255. class TextAppender(Appender):
  256. """
  257. An appender for I{Text} values.
  258. """
  259. def append(self, parent, content):
  260. child = self.node(content)
  261. child.setText(content.value)
  262. parent.append(child)