123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- from __future__ import absolute_import, division, unicode_literals
- try:
- from collections.abc import MutableMapping
- except ImportError: # Python 2.7
- from collections import MutableMapping
- from xml.dom import minidom, Node
- import weakref
- from . import base
- from .. import constants
- from ..constants import namespaces
- from .._utils import moduleFactoryFactory
- def getDomBuilder(DomImplementation):
- Dom = DomImplementation
- class AttrList(MutableMapping):
- def __init__(self, element):
- self.element = element
- def __iter__(self):
- return iter(self.element.attributes.keys())
- def __setitem__(self, name, value):
- if isinstance(name, tuple):
- raise NotImplementedError
- else:
- attr = self.element.ownerDocument.createAttribute(name)
- attr.value = value
- self.element.attributes[name] = attr
- def __len__(self):
- return len(self.element.attributes)
- def items(self):
- return list(self.element.attributes.items())
- def values(self):
- return list(self.element.attributes.values())
- def __getitem__(self, name):
- if isinstance(name, tuple):
- raise NotImplementedError
- else:
- return self.element.attributes[name].value
- def __delitem__(self, name):
- if isinstance(name, tuple):
- raise NotImplementedError
- else:
- del self.element.attributes[name]
- class NodeBuilder(base.Node):
- def __init__(self, element):
- base.Node.__init__(self, element.nodeName)
- self.element = element
- namespace = property(lambda self: hasattr(self.element, "namespaceURI") and
- self.element.namespaceURI or None)
- def appendChild(self, node):
- node.parent = self
- self.element.appendChild(node.element)
- def insertText(self, data, insertBefore=None):
- text = self.element.ownerDocument.createTextNode(data)
- if insertBefore:
- self.element.insertBefore(text, insertBefore.element)
- else:
- self.element.appendChild(text)
- def insertBefore(self, node, refNode):
- self.element.insertBefore(node.element, refNode.element)
- node.parent = self
- def removeChild(self, node):
- if node.element.parentNode == self.element:
- self.element.removeChild(node.element)
- node.parent = None
- def reparentChildren(self, newParent):
- while self.element.hasChildNodes():
- child = self.element.firstChild
- self.element.removeChild(child)
- newParent.element.appendChild(child)
- self.childNodes = []
- def getAttributes(self):
- return AttrList(self.element)
- def setAttributes(self, attributes):
- if attributes:
- for name, value in list(attributes.items()):
- if isinstance(name, tuple):
- if name[0] is not None:
- qualifiedName = (name[0] + ":" + name[1])
- else:
- qualifiedName = name[1]
- self.element.setAttributeNS(name[2], qualifiedName,
- value)
- else:
- self.element.setAttribute(
- name, value)
- attributes = property(getAttributes, setAttributes)
- def cloneNode(self):
- return NodeBuilder(self.element.cloneNode(False))
- def hasContent(self):
- return self.element.hasChildNodes()
- def getNameTuple(self):
- if self.namespace is None:
- return namespaces["html"], self.name
- else:
- return self.namespace, self.name
- nameTuple = property(getNameTuple)
- class TreeBuilder(base.TreeBuilder): # pylint:disable=unused-variable
- def documentClass(self):
- self.dom = Dom.getDOMImplementation().createDocument(None, None, None)
- return weakref.proxy(self)
- def insertDoctype(self, token):
- name = token["name"]
- publicId = token["publicId"]
- systemId = token["systemId"]
- domimpl = Dom.getDOMImplementation()
- doctype = domimpl.createDocumentType(name, publicId, systemId)
- self.document.appendChild(NodeBuilder(doctype))
- if Dom == minidom:
- doctype.ownerDocument = self.dom
- def elementClass(self, name, namespace=None):
- if namespace is None and self.defaultNamespace is None:
- node = self.dom.createElement(name)
- else:
- node = self.dom.createElementNS(namespace, name)
- return NodeBuilder(node)
- def commentClass(self, data):
- return NodeBuilder(self.dom.createComment(data))
- def fragmentClass(self):
- return NodeBuilder(self.dom.createDocumentFragment())
- def appendChild(self, node):
- self.dom.appendChild(node.element)
- def testSerializer(self, element):
- return testSerializer(element)
- def getDocument(self):
- return self.dom
- def getFragment(self):
- return base.TreeBuilder.getFragment(self).element
- def insertText(self, data, parent=None):
- data = data
- if parent != self:
- base.TreeBuilder.insertText(self, data, parent)
- else:
- # HACK: allow text nodes as children of the document node
- if hasattr(self.dom, '_child_node_types'):
- # pylint:disable=protected-access
- if Node.TEXT_NODE not in self.dom._child_node_types:
- self.dom._child_node_types = list(self.dom._child_node_types)
- self.dom._child_node_types.append(Node.TEXT_NODE)
- self.dom.appendChild(self.dom.createTextNode(data))
- implementation = DomImplementation
- name = None
- def testSerializer(element):
- element.normalize()
- rv = []
- def serializeElement(element, indent=0):
- if element.nodeType == Node.DOCUMENT_TYPE_NODE:
- if element.name:
- if element.publicId or element.systemId:
- publicId = element.publicId or ""
- systemId = element.systemId or ""
- rv.append("""|%s<!DOCTYPE %s "%s" "%s">""" %
- (' ' * indent, element.name, publicId, systemId))
- else:
- rv.append("|%s<!DOCTYPE %s>" % (' ' * indent, element.name))
- else:
- rv.append("|%s<!DOCTYPE >" % (' ' * indent,))
- elif element.nodeType == Node.DOCUMENT_NODE:
- rv.append("#document")
- elif element.nodeType == Node.DOCUMENT_FRAGMENT_NODE:
- rv.append("#document-fragment")
- elif element.nodeType == Node.COMMENT_NODE:
- rv.append("|%s<!-- %s -->" % (' ' * indent, element.nodeValue))
- elif element.nodeType == Node.TEXT_NODE:
- rv.append("|%s\"%s\"" % (' ' * indent, element.nodeValue))
- else:
- if (hasattr(element, "namespaceURI") and
- element.namespaceURI is not None):
- name = "%s %s" % (constants.prefixes[element.namespaceURI],
- element.nodeName)
- else:
- name = element.nodeName
- rv.append("|%s<%s>" % (' ' * indent, name))
- if element.hasAttributes():
- attributes = []
- for i in range(len(element.attributes)):
- attr = element.attributes.item(i)
- name = attr.nodeName
- value = attr.value
- ns = attr.namespaceURI
- if ns:
- name = "%s %s" % (constants.prefixes[ns], attr.localName)
- else:
- name = attr.nodeName
- attributes.append((name, value))
- for name, value in sorted(attributes):
- rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value))
- indent += 2
- for child in element.childNodes:
- serializeElement(child, indent)
- serializeElement(element, 0)
- return "\n".join(rv)
- return locals()
- # The actual means to get a module!
- getDomModule = moduleFactoryFactory(getDomBuilder)
|