You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

168 lines
5.9 KiB

4 years ago
  1. # Copyright (c) 2010 Mitch Garnaat http://garnaat.org/
  2. # Copyright (c) 2010, Eucalyptus Systems, Inc.
  3. #
  4. # Permission is hereby granted, free of charge, to any person obtaining a
  5. # copy of this software and associated documentation files (the
  6. # "Software"), to deal in the Software without restriction, including
  7. # without limitation the rights to use, copy, modify, merge, publish, dis-
  8. # tribute, sublicense, and/or sell copies of the Software, and to permit
  9. # persons to whom the Software is furnished to do so, subject to the fol-
  10. # lowing conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included
  13. # in all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  16. # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
  17. # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
  18. # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  19. # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  21. # IN THE SOFTWARE.
  22. import xml.sax
  23. from boto import utils
  24. class XmlHandler(xml.sax.ContentHandler):
  25. def __init__(self, root_node, connection):
  26. self.connection = connection
  27. self.nodes = [('root', root_node)]
  28. self.current_text = ''
  29. def startElement(self, name, attrs):
  30. self.current_text = ''
  31. t = self.nodes[-1][1].startElement(name, attrs, self.connection)
  32. if t is not None:
  33. if isinstance(t, tuple):
  34. self.nodes.append(t)
  35. else:
  36. self.nodes.append((name, t))
  37. def endElement(self, name):
  38. self.nodes[-1][1].endElement(name, self.current_text, self.connection)
  39. if self.nodes[-1][0] == name:
  40. self.nodes.pop()
  41. self.current_text = ''
  42. def characters(self, content):
  43. self.current_text += content
  44. def parse(self, s):
  45. if not isinstance(s, bytes):
  46. s = s.encode('utf-8')
  47. xml.sax.parseString(s, self)
  48. class Element(dict):
  49. def __init__(self, connection=None, element_name=None,
  50. stack=None, parent=None, list_marker=('Set',),
  51. item_marker=('member', 'item'),
  52. pythonize_name=False):
  53. dict.__init__(self)
  54. self.connection = connection
  55. self.element_name = element_name
  56. self.list_marker = utils.mklist(list_marker)
  57. self.item_marker = utils.mklist(item_marker)
  58. if stack is None:
  59. self.stack = []
  60. else:
  61. self.stack = stack
  62. self.pythonize_name = pythonize_name
  63. self.parent = parent
  64. def __getattr__(self, key):
  65. if key in self:
  66. return self[key]
  67. for k in self:
  68. e = self[k]
  69. if isinstance(e, Element):
  70. try:
  71. return getattr(e, key)
  72. except AttributeError:
  73. pass
  74. raise AttributeError
  75. def get_name(self, name):
  76. if self.pythonize_name:
  77. name = utils.pythonize_name(name)
  78. return name
  79. def startElement(self, name, attrs, connection):
  80. self.stack.append(name)
  81. for lm in self.list_marker:
  82. if name.endswith(lm):
  83. l = ListElement(self.connection, name, self.list_marker,
  84. self.item_marker, self.pythonize_name)
  85. self[self.get_name(name)] = l
  86. return l
  87. if len(self.stack) > 0:
  88. element_name = self.stack[-1]
  89. e = Element(self.connection, element_name, self.stack, self,
  90. self.list_marker, self.item_marker,
  91. self.pythonize_name)
  92. self[self.get_name(element_name)] = e
  93. return (element_name, e)
  94. else:
  95. return None
  96. def endElement(self, name, value, connection):
  97. if len(self.stack) > 0:
  98. self.stack.pop()
  99. value = value.strip()
  100. if value:
  101. if isinstance(self.parent, Element):
  102. self.parent[self.get_name(name)] = value
  103. elif isinstance(self.parent, ListElement):
  104. self.parent.append(value)
  105. class ListElement(list):
  106. def __init__(self, connection=None, element_name=None,
  107. list_marker=['Set'], item_marker=('member', 'item'),
  108. pythonize_name=False):
  109. list.__init__(self)
  110. self.connection = connection
  111. self.element_name = element_name
  112. self.list_marker = list_marker
  113. self.item_marker = item_marker
  114. self.pythonize_name = pythonize_name
  115. def get_name(self, name):
  116. if self.pythonize_name:
  117. name = utils.pythonize_name(name)
  118. return name
  119. def startElement(self, name, attrs, connection):
  120. for lm in self.list_marker:
  121. if name.endswith(lm):
  122. l = ListElement(self.connection, name,
  123. self.list_marker, self.item_marker,
  124. self.pythonize_name)
  125. setattr(self, self.get_name(name), l)
  126. return l
  127. if name in self.item_marker:
  128. e = Element(self.connection, name, parent=self,
  129. list_marker=self.list_marker,
  130. item_marker=self.item_marker,
  131. pythonize_name=self.pythonize_name)
  132. self.append(e)
  133. return e
  134. else:
  135. return None
  136. def endElement(self, name, value, connection):
  137. if name == self.element_name:
  138. if len(self) > 0:
  139. empty = []
  140. for e in self:
  141. if isinstance(e, Element):
  142. if len(e) == 0:
  143. empty.append(e)
  144. for e in empty:
  145. self.remove(e)
  146. else:
  147. setattr(self, self.get_name(name), value)