+++ /dev/null
-"""Implementation of the DOM Level 3 'LS-Load' feature."""\r
-\r
-import copy\r
-import xml.dom\r
-\r
-from xml.dom.NodeFilter import NodeFilter\r
-\r
-\r
-__all__ = ["DOMBuilder", "DOMEntityResolver", "DOMInputSource"]\r
-\r
-\r
-class Options:\r
- """Features object that has variables set for each DOMBuilder feature.\r
-\r
- The DOMBuilder class uses an instance of this class to pass settings to\r
- the ExpatBuilder class.\r
- """\r
-\r
- # Note that the DOMBuilder class in LoadSave constrains which of these\r
- # values can be set using the DOM Level 3 LoadSave feature.\r
-\r
- namespaces = 1\r
- namespace_declarations = True\r
- validation = False\r
- external_parameter_entities = True\r
- external_general_entities = True\r
- external_dtd_subset = True\r
- validate_if_schema = False\r
- validate = False\r
- datatype_normalization = False\r
- create_entity_ref_nodes = True\r
- entities = True\r
- whitespace_in_element_content = True\r
- cdata_sections = True\r
- comments = True\r
- charset_overrides_xml_encoding = True\r
- infoset = False\r
- supported_mediatypes_only = False\r
-\r
- errorHandler = None\r
- filter = None\r
-\r
-\r
-class DOMBuilder:\r
- entityResolver = None\r
- errorHandler = None\r
- filter = None\r
-\r
- ACTION_REPLACE = 1\r
- ACTION_APPEND_AS_CHILDREN = 2\r
- ACTION_INSERT_AFTER = 3\r
- ACTION_INSERT_BEFORE = 4\r
-\r
- _legal_actions = (ACTION_REPLACE, ACTION_APPEND_AS_CHILDREN,\r
- ACTION_INSERT_AFTER, ACTION_INSERT_BEFORE)\r
-\r
- def __init__(self):\r
- self._options = Options()\r
-\r
- def _get_entityResolver(self):\r
- return self.entityResolver\r
- def _set_entityResolver(self, entityResolver):\r
- self.entityResolver = entityResolver\r
-\r
- def _get_errorHandler(self):\r
- return self.errorHandler\r
- def _set_errorHandler(self, errorHandler):\r
- self.errorHandler = errorHandler\r
-\r
- def _get_filter(self):\r
- return self.filter\r
- def _set_filter(self, filter):\r
- self.filter = filter\r
-\r
- def setFeature(self, name, state):\r
- if self.supportsFeature(name):\r
- state = state and 1 or 0\r
- try:\r
- settings = self._settings[(_name_xform(name), state)]\r
- except KeyError:\r
- raise xml.dom.NotSupportedErr(\r
- "unsupported feature: %r" % (name,))\r
- else:\r
- for name, value in settings:\r
- setattr(self._options, name, value)\r
- else:\r
- raise xml.dom.NotFoundErr("unknown feature: " + repr(name))\r
-\r
- def supportsFeature(self, name):\r
- return hasattr(self._options, _name_xform(name))\r
-\r
- def canSetFeature(self, name, state):\r
- key = (_name_xform(name), state and 1 or 0)\r
- return key in self._settings\r
-\r
- # This dictionary maps from (feature,value) to a list of\r
- # (option,value) pairs that should be set on the Options object.\r
- # If a (feature,value) setting is not in this dictionary, it is\r
- # not supported by the DOMBuilder.\r
- #\r
- _settings = {\r
- ("namespace_declarations", 0): [\r
- ("namespace_declarations", 0)],\r
- ("namespace_declarations", 1): [\r
- ("namespace_declarations", 1)],\r
- ("validation", 0): [\r
- ("validation", 0)],\r
- ("external_general_entities", 0): [\r
- ("external_general_entities", 0)],\r
- ("external_general_entities", 1): [\r
- ("external_general_entities", 1)],\r
- ("external_parameter_entities", 0): [\r
- ("external_parameter_entities", 0)],\r
- ("external_parameter_entities", 1): [\r
- ("external_parameter_entities", 1)],\r
- ("validate_if_schema", 0): [\r
- ("validate_if_schema", 0)],\r
- ("create_entity_ref_nodes", 0): [\r
- ("create_entity_ref_nodes", 0)],\r
- ("create_entity_ref_nodes", 1): [\r
- ("create_entity_ref_nodes", 1)],\r
- ("entities", 0): [\r
- ("create_entity_ref_nodes", 0),\r
- ("entities", 0)],\r
- ("entities", 1): [\r
- ("entities", 1)],\r
- ("whitespace_in_element_content", 0): [\r
- ("whitespace_in_element_content", 0)],\r
- ("whitespace_in_element_content", 1): [\r
- ("whitespace_in_element_content", 1)],\r
- ("cdata_sections", 0): [\r
- ("cdata_sections", 0)],\r
- ("cdata_sections", 1): [\r
- ("cdata_sections", 1)],\r
- ("comments", 0): [\r
- ("comments", 0)],\r
- ("comments", 1): [\r
- ("comments", 1)],\r
- ("charset_overrides_xml_encoding", 0): [\r
- ("charset_overrides_xml_encoding", 0)],\r
- ("charset_overrides_xml_encoding", 1): [\r
- ("charset_overrides_xml_encoding", 1)],\r
- ("infoset", 0): [],\r
- ("infoset", 1): [\r
- ("namespace_declarations", 0),\r
- ("validate_if_schema", 0),\r
- ("create_entity_ref_nodes", 0),\r
- ("entities", 0),\r
- ("cdata_sections", 0),\r
- ("datatype_normalization", 1),\r
- ("whitespace_in_element_content", 1),\r
- ("comments", 1),\r
- ("charset_overrides_xml_encoding", 1)],\r
- ("supported_mediatypes_only", 0): [\r
- ("supported_mediatypes_only", 0)],\r
- ("namespaces", 0): [\r
- ("namespaces", 0)],\r
- ("namespaces", 1): [\r
- ("namespaces", 1)],\r
- }\r
-\r
- def getFeature(self, name):\r
- xname = _name_xform(name)\r
- try:\r
- return getattr(self._options, xname)\r
- except AttributeError:\r
- if name == "infoset":\r
- options = self._options\r
- return (options.datatype_normalization\r
- and options.whitespace_in_element_content\r
- and options.comments\r
- and options.charset_overrides_xml_encoding\r
- and not (options.namespace_declarations\r
- or options.validate_if_schema\r
- or options.create_entity_ref_nodes\r
- or options.entities\r
- or options.cdata_sections))\r
- raise xml.dom.NotFoundErr("feature %s not known" % repr(name))\r
-\r
- def parseURI(self, uri):\r
- if self.entityResolver:\r
- input = self.entityResolver.resolveEntity(None, uri)\r
- else:\r
- input = DOMEntityResolver().resolveEntity(None, uri)\r
- return self.parse(input)\r
-\r
- def parse(self, input):\r
- options = copy.copy(self._options)\r
- options.filter = self.filter\r
- options.errorHandler = self.errorHandler\r
- fp = input.byteStream\r
- if fp is None and options.systemId:\r
- import urllib2\r
- fp = urllib2.urlopen(input.systemId)\r
- return self._parse_bytestream(fp, options)\r
-\r
- def parseWithContext(self, input, cnode, action):\r
- if action not in self._legal_actions:\r
- raise ValueError("not a legal action")\r
- raise NotImplementedError("Haven't written this yet...")\r
-\r
- def _parse_bytestream(self, stream, options):\r
- import xml.dom.expatbuilder\r
- builder = xml.dom.expatbuilder.makeBuilder(options)\r
- return builder.parseFile(stream)\r
-\r
-\r
-def _name_xform(name):\r
- return name.lower().replace('-', '_')\r
-\r
-\r
-class DOMEntityResolver(object):\r
- __slots__ = '_opener',\r
-\r
- def resolveEntity(self, publicId, systemId):\r
- assert systemId is not None\r
- source = DOMInputSource()\r
- source.publicId = publicId\r
- source.systemId = systemId\r
- source.byteStream = self._get_opener().open(systemId)\r
-\r
- # determine the encoding if the transport provided it\r
- source.encoding = self._guess_media_encoding(source)\r
-\r
- # determine the base URI is we can\r
- import posixpath, urlparse\r
- parts = urlparse.urlparse(systemId)\r
- scheme, netloc, path, params, query, fragment = parts\r
- # XXX should we check the scheme here as well?\r
- if path and not path.endswith("/"):\r
- path = posixpath.dirname(path) + "/"\r
- parts = scheme, netloc, path, params, query, fragment\r
- source.baseURI = urlparse.urlunparse(parts)\r
-\r
- return source\r
-\r
- def _get_opener(self):\r
- try:\r
- return self._opener\r
- except AttributeError:\r
- self._opener = self._create_opener()\r
- return self._opener\r
-\r
- def _create_opener(self):\r
- import urllib2\r
- return urllib2.build_opener()\r
-\r
- def _guess_media_encoding(self, source):\r
- info = source.byteStream.info()\r
- if "Content-Type" in info:\r
- for param in info.getplist():\r
- if param.startswith("charset="):\r
- return param.split("=", 1)[1].lower()\r
-\r
-\r
-class DOMInputSource(object):\r
- __slots__ = ('byteStream', 'characterStream', 'stringData',\r
- 'encoding', 'publicId', 'systemId', 'baseURI')\r
-\r
- def __init__(self):\r
- self.byteStream = None\r
- self.characterStream = None\r
- self.stringData = None\r
- self.encoding = None\r
- self.publicId = None\r
- self.systemId = None\r
- self.baseURI = None\r
-\r
- def _get_byteStream(self):\r
- return self.byteStream\r
- def _set_byteStream(self, byteStream):\r
- self.byteStream = byteStream\r
-\r
- def _get_characterStream(self):\r
- return self.characterStream\r
- def _set_characterStream(self, characterStream):\r
- self.characterStream = characterStream\r
-\r
- def _get_stringData(self):\r
- return self.stringData\r
- def _set_stringData(self, data):\r
- self.stringData = data\r
-\r
- def _get_encoding(self):\r
- return self.encoding\r
- def _set_encoding(self, encoding):\r
- self.encoding = encoding\r
-\r
- def _get_publicId(self):\r
- return self.publicId\r
- def _set_publicId(self, publicId):\r
- self.publicId = publicId\r
-\r
- def _get_systemId(self):\r
- return self.systemId\r
- def _set_systemId(self, systemId):\r
- self.systemId = systemId\r
-\r
- def _get_baseURI(self):\r
- return self.baseURI\r
- def _set_baseURI(self, uri):\r
- self.baseURI = uri\r
-\r
-\r
-class DOMBuilderFilter:\r
- """Element filter which can be used to tailor construction of\r
- a DOM instance.\r
- """\r
-\r
- # There's really no need for this class; concrete implementations\r
- # should just implement the endElement() and startElement()\r
- # methods as appropriate. Using this makes it easy to only\r
- # implement one of them.\r
-\r
- FILTER_ACCEPT = 1\r
- FILTER_REJECT = 2\r
- FILTER_SKIP = 3\r
- FILTER_INTERRUPT = 4\r
-\r
- whatToShow = NodeFilter.SHOW_ALL\r
-\r
- def _get_whatToShow(self):\r
- return self.whatToShow\r
-\r
- def acceptNode(self, element):\r
- return self.FILTER_ACCEPT\r
-\r
- def startContainer(self, element):\r
- return self.FILTER_ACCEPT\r
-\r
-del NodeFilter\r
-\r
-\r
-class DocumentLS:\r
- """Mixin to create documents that conform to the load/save spec."""\r
-\r
- async = False\r
-\r
- def _get_async(self):\r
- return False\r
- def _set_async(self, async):\r
- if async:\r
- raise xml.dom.NotSupportedErr(\r
- "asynchronous document loading is not supported")\r
-\r
- def abort(self):\r
- # What does it mean to "clear" a document? Does the\r
- # documentElement disappear?\r
- raise NotImplementedError(\r
- "haven't figured out what this means yet")\r
-\r
- def load(self, uri):\r
- raise NotImplementedError("haven't written this yet")\r
-\r
- def loadXML(self, source):\r
- raise NotImplementedError("haven't written this yet")\r
-\r
- def saveXML(self, snode):\r
- if snode is None:\r
- snode = self\r
- elif snode.ownerDocument is not self:\r
- raise xml.dom.WrongDocumentErr()\r
- return snode.toxml()\r
-\r
-\r
-class DOMImplementationLS:\r
- MODE_SYNCHRONOUS = 1\r
- MODE_ASYNCHRONOUS = 2\r
-\r
- def createDOMBuilder(self, mode, schemaType):\r
- if schemaType is not None:\r
- raise xml.dom.NotSupportedErr(\r
- "schemaType not yet supported")\r
- if mode == self.MODE_SYNCHRONOUS:\r
- return DOMBuilder()\r
- if mode == self.MODE_ASYNCHRONOUS:\r
- raise xml.dom.NotSupportedErr(\r
- "asynchronous builders are not supported")\r
- raise ValueError("unknown value for mode")\r
-\r
- def createDOMWriter(self):\r
- raise NotImplementedError(\r
- "the writer interface hasn't been written yet!")\r
-\r
- def createDOMInputSource(self):\r
- return DOMInputSource()\r