dom.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. from __future__ import absolute_import, division, unicode_literals
  2. from xml.dom import minidom, Node
  3. import weakref
  4. from . import _base
  5. from .. import constants
  6. from ..constants import namespaces
  7. from ..utils import moduleFactoryFactory
  8. def getDomBuilder(DomImplementation):
  9. Dom = DomImplementation
  10. class AttrList(object):
  11. def __init__(self, element):
  12. self.element = element
  13. def __iter__(self):
  14. return list(self.element.attributes.items()).__iter__()
  15. def __setitem__(self, name, value):
  16. self.element.setAttribute(name, value)
  17. def __len__(self):
  18. return len(list(self.element.attributes.items()))
  19. def items(self):
  20. return [(item[0], item[1]) for item in
  21. list(self.element.attributes.items())]
  22. def keys(self):
  23. return list(self.element.attributes.keys())
  24. def __getitem__(self, name):
  25. return self.element.getAttribute(name)
  26. def __contains__(self, name):
  27. if isinstance(name, tuple):
  28. raise NotImplementedError
  29. else:
  30. return self.element.hasAttribute(name)
  31. class NodeBuilder(_base.Node):
  32. def __init__(self, element):
  33. _base.Node.__init__(self, element.nodeName)
  34. self.element = element
  35. namespace = property(lambda self: hasattr(self.element, "namespaceURI")
  36. and self.element.namespaceURI or None)
  37. def appendChild(self, node):
  38. node.parent = self
  39. self.element.appendChild(node.element)
  40. def insertText(self, data, insertBefore=None):
  41. text = self.element.ownerDocument.createTextNode(data)
  42. if insertBefore:
  43. self.element.insertBefore(text, insertBefore.element)
  44. else:
  45. self.element.appendChild(text)
  46. def insertBefore(self, node, refNode):
  47. self.element.insertBefore(node.element, refNode.element)
  48. node.parent = self
  49. def removeChild(self, node):
  50. if node.element.parentNode == self.element:
  51. self.element.removeChild(node.element)
  52. node.parent = None
  53. def reparentChildren(self, newParent):
  54. while self.element.hasChildNodes():
  55. child = self.element.firstChild
  56. self.element.removeChild(child)
  57. newParent.element.appendChild(child)
  58. self.childNodes = []
  59. def getAttributes(self):
  60. return AttrList(self.element)
  61. def setAttributes(self, attributes):
  62. if attributes:
  63. for name, value in list(attributes.items()):
  64. if isinstance(name, tuple):
  65. if name[0] is not None:
  66. qualifiedName = (name[0] + ":" + name[1])
  67. else:
  68. qualifiedName = name[1]
  69. self.element.setAttributeNS(name[2], qualifiedName,
  70. value)
  71. else:
  72. self.element.setAttribute(
  73. name, value)
  74. attributes = property(getAttributes, setAttributes)
  75. def cloneNode(self):
  76. return NodeBuilder(self.element.cloneNode(False))
  77. def hasContent(self):
  78. return self.element.hasChildNodes()
  79. def getNameTuple(self):
  80. if self.namespace is None:
  81. return namespaces["html"], self.name
  82. else:
  83. return self.namespace, self.name
  84. nameTuple = property(getNameTuple)
  85. class TreeBuilder(_base.TreeBuilder):
  86. def documentClass(self):
  87. self.dom = Dom.getDOMImplementation().createDocument(None, None, None)
  88. return weakref.proxy(self)
  89. def insertDoctype(self, token):
  90. name = token["name"]
  91. publicId = token["publicId"]
  92. systemId = token["systemId"]
  93. domimpl = Dom.getDOMImplementation()
  94. doctype = domimpl.createDocumentType(name, publicId, systemId)
  95. self.document.appendChild(NodeBuilder(doctype))
  96. if Dom == minidom:
  97. doctype.ownerDocument = self.dom
  98. def elementClass(self, name, namespace=None):
  99. if namespace is None and self.defaultNamespace is None:
  100. node = self.dom.createElement(name)
  101. else:
  102. node = self.dom.createElementNS(namespace, name)
  103. return NodeBuilder(node)
  104. def commentClass(self, data):
  105. return NodeBuilder(self.dom.createComment(data))
  106. def fragmentClass(self):
  107. return NodeBuilder(self.dom.createDocumentFragment())
  108. def appendChild(self, node):
  109. self.dom.appendChild(node.element)
  110. def testSerializer(self, element):
  111. return testSerializer(element)
  112. def getDocument(self):
  113. return self.dom
  114. def getFragment(self):
  115. return _base.TreeBuilder.getFragment(self).element
  116. def insertText(self, data, parent=None):
  117. data = data
  118. if parent != self:
  119. _base.TreeBuilder.insertText(self, data, parent)
  120. else:
  121. # HACK: allow text nodes as children of the document node
  122. if hasattr(self.dom, '_child_node_types'):
  123. if not Node.TEXT_NODE in self.dom._child_node_types:
  124. self.dom._child_node_types = list(self.dom._child_node_types)
  125. self.dom._child_node_types.append(Node.TEXT_NODE)
  126. self.dom.appendChild(self.dom.createTextNode(data))
  127. implementation = DomImplementation
  128. name = None
  129. def testSerializer(element):
  130. element.normalize()
  131. rv = []
  132. def serializeElement(element, indent=0):
  133. if element.nodeType == Node.DOCUMENT_TYPE_NODE:
  134. if element.name:
  135. if element.publicId or element.systemId:
  136. publicId = element.publicId or ""
  137. systemId = element.systemId or ""
  138. rv.append("""|%s<!DOCTYPE %s "%s" "%s">""" %
  139. (' ' * indent, element.name, publicId, systemId))
  140. else:
  141. rv.append("|%s<!DOCTYPE %s>" % (' ' * indent, element.name))
  142. else:
  143. rv.append("|%s<!DOCTYPE >" % (' ' * indent,))
  144. elif element.nodeType == Node.DOCUMENT_NODE:
  145. rv.append("#document")
  146. elif element.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
  147. rv.append("#document-fragment")
  148. elif element.nodeType == Node.COMMENT_NODE:
  149. rv.append("|%s<!-- %s -->" % (' ' * indent, element.nodeValue))
  150. elif element.nodeType == Node.TEXT_NODE:
  151. rv.append("|%s\"%s\"" % (' ' * indent, element.nodeValue))
  152. else:
  153. if (hasattr(element, "namespaceURI") and
  154. element.namespaceURI is not None):
  155. name = "%s %s" % (constants.prefixes[element.namespaceURI],
  156. element.nodeName)
  157. else:
  158. name = element.nodeName
  159. rv.append("|%s<%s>" % (' ' * indent, name))
  160. if element.hasAttributes():
  161. attributes = []
  162. for i in range(len(element.attributes)):
  163. attr = element.attributes.item(i)
  164. name = attr.nodeName
  165. value = attr.value
  166. ns = attr.namespaceURI
  167. if ns:
  168. name = "%s %s" % (constants.prefixes[ns], attr.localName)
  169. else:
  170. name = attr.nodeName
  171. attributes.append((name, value))
  172. for name, value in sorted(attributes):
  173. rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value))
  174. indent += 2
  175. for child in element.childNodes:
  176. serializeElement(child, indent)
  177. serializeElement(element, 0)
  178. return "\n".join(rv)
  179. return locals()
  180. # The actual means to get a module!
  181. getDomModule = moduleFactoryFactory(getDomBuilder)