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