"""Facility to use the Expat parser to load a minidom instancefrom a string or file.This avoids all the overhead of SAX and pulldom to gain performance."""# Warning!## This module is tightly bound to the implementation details of the# minidom DOM and can't be used with other DOM implementations. This# is due, in part, to a lack of appropriate methods in the DOM (there is# no way to create Entity and Notation nodes via the DOM Level 2# interface), and for performance. The latter is the cause of some fairly# cryptic code.## Performance hacks:## - .character_data_handler() has an extra case in which continuing# data is appended to an existing Text node; this can be a# speedup since pyexpat can break up character data into multiple# callbacks even though we set the buffer_text attribute on the# parser. This also gives us the advantage that we don't need a# separate normalization pass.## - Determining that a node exists is done using an identity comparison# with None rather than a truth test; this avoids searching for and# calling any methods on the node object if it exists. (A rather# nice speedup is achieved this way as well!)from xml.dom import xmlbuilder, minidom, Nodefrom xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACEfrom xml.parsers import expatfrom xml.dom.minidom import _append_child, _set_attribute_nodefrom xml.dom.NodeFilter import NodeFilterTEXT_NODE = Node.TEXT_NODECDATA_SECTION_NODE = Node.CDATA_SECTION_NODEDOCUMENT_NODE = Node.DOCUMENT_NODEFILTER_ACCEPT = xmlbuilder.DOMBuilderFilter.FILTER_ACCEPTFILTER_REJECT = xmlbuilder.DOMBuilderFilter.FILTER_REJECTFILTER_SKIP = xmlbuilder.DOMBuilderFilter.FILTER_SKIPFILTER_INTERRUPT = xmlbuilder.DOMBuilderFilter.FILTER_INTERRUPTtheDOMImplementation = minidom.getDOMImplementation()# Expat typename -> TypeInfo_typeinfo_map = {"CDATA": minidom.TypeInfo(None, "cdata"),"ENUM": minidom.TypeInfo(None, "enumeration"),"ENTITY": minidom.TypeInfo(None, "entity"),"ENTITIES": minidom.TypeInfo(None, "entities"),"ID": minidom.TypeInfo(None, "id"),"IDREF": minidom.TypeInfo(None, "idref"),"IDREFS": minidom.TypeInfo(None, "idrefs"),"NMTOKEN": minidom.TypeInfo(None, "nmtoken"),"NMTOKENS": minidom.TypeInfo(None, "nmtokens"),}class ElementInfo(object):__slots__ = '_attr_info', '_model', 'tagName'def __init__(self, tagName, model=None):self.tagName = tagNameself._attr_info = []self._model = modeldef __getstate__(self):return self._attr_info, self._model, self.tagNamedef __setstate__(self, state):self._attr_info, self._model, self.tagName = statedef getAttributeType(self, aname):for info in self._attr_info:if info[1] == aname:t = info[-2]if t[0] == "(":return _typeinfo_map["ENUM"]else:return _typeinfo_map[info[-2]]return minidom._no_typedef getAttributeTypeNS(self, namespaceURI, localName):return minidom._no_typedef isElementContent(self):if self._model:type = self._model[0]return type not in (expat.model.XML_CTYPE_ANY,expat.model.XML_CTYPE_MIXED)else:return Falsedef isEmpty(self):if self._model:return self._model[0] == expat.model.XML_CTYPE_EMPTYelse:return Falsedef isId(self, aname):for info in self._attr_info:if info[1] == aname:return info[-2] == "ID"return Falsedef isIdNS(self, euri, ename, auri, aname):# not sure this is meaningfulreturn self.isId((auri, aname))def _intern(builder, s):return builder._intern_setdefault(s, s)def _parse_ns_name(builder, name):assert ' ' in nameparts = name.split(' ')intern = builder._intern_setdefaultif len(parts) == 3:uri, localname, prefix = partsprefix = intern(prefix, prefix)qname = "%s:%s" % (prefix, localname)qname = intern(qname, qname)localname = intern(localname, localname)elif len(parts) == 2:uri, localname = partsprefix = EMPTY_PREFIXqname = localname = intern(localname, localname)else:raise ValueError("Unsupported syntax: spaces in URIs not supported: %r" % name)return intern(uri, uri), localname, prefix, qnameclass ExpatBuilder:"""Document builder that uses Expat to build a ParsedXML.DOM documentinstance."""def __init__(self, options=None):if options is None:options = xmlbuilder.Options()self._options = optionsif self._options.filter is not None:self._filter = FilterVisibilityController(self._options.filter)else:self._filter = None# This *really* doesn't do anything in this case, so# override it with something fast & minimal.self._finish_start_element = idself._parser = Noneself.reset()def createParser(self):"""Create a new parser object."""return expat.ParserCreate()def getParser(self):"""Return the parser object, creating a new one if needed."""if not self._parser:self._parser = self.createParser()self._intern_setdefault = self._parser.intern.setdefaultself._parser.buffer_text = Trueself._parser.ordered_attributes = Trueself._parser.specified_attributes = Trueself.install(self._parser)return self._parserdef reset(self):"""Free all data structures used during DOM construction."""self.document = theDOMImplementation.createDocument(EMPTY_NAMESPACE, None, None)self.curNode = self.documentself._elem_info = self.document._elem_infoself._cdata = Falsedef install(self, parser):"""Install the callbacks needed to build the DOM into the parser."""# This creates circular references!parser.StartDoctypeDeclHandler = self.start_doctype_decl_handlerparser.StartElementHandler = self.first_element_handlerparser.EndElementHandler = self.end_element_handlerparser.ProcessingInstructionHandler = self.pi_handlerif self._options.entities:parser.EntityDeclHandler = self.entity_decl_handlerparser.NotationDeclHandler = self.notation_decl_handlerif self._options.comments:parser.CommentHandler = self.comment_handlerif self._options.cdata_sections:parser.StartCdataSectionHandler = self.start_cdata_section_handlerparser.EndCdataSectionHandler = self.end_cdata_section_handlerparser.CharacterDataHandler = self.character_data_handler_cdataelse:parser.CharacterDataHandler = self.character_data_handlerparser.ExternalEntityRefHandler = self.external_entity_ref_handlerparser.XmlDeclHandler = self.xml_decl_handlerparser.ElementDeclHandler = self.element_decl_handlerparser.AttlistDeclHandler = self.attlist_decl_handlerdef parseFile(self, file):"""Parse a document from a file object, returning the documentnode."""parser = self.getParser()first_buffer = Truetry:while 1:buffer = file.read(16*1024)if not buffer:breakparser.Parse(buffer, 0)if first_buffer and self.document.documentElement:self._setup_subset(buffer)first_buffer = Falseparser.Parse("", True)except ParseEscape:passdoc = self.documentself.reset()self._parser = Nonereturn docdef parseString(self, string):"""Parse a document from a string, returning the document node."""parser = self.getParser()try:parser.Parse(string, True)self._setup_subset(string)except ParseEscape:passdoc = self.documentself.reset()self._parser = Nonereturn docdef _setup_subset(self, buffer):"""Load the internal subset if there might be one."""if self.document.doctype:extractor = InternalSubsetExtractor()extractor.parseString(buffer)subset = extractor.getSubset()self.document.doctype.internalSubset = subsetdef start_doctype_decl_handler(self, doctypeName, systemId, publicId,has_internal_subset):doctype = self.document.implementation.createDocumentType(doctypeName, publicId, systemId)doctype.ownerDocument = self.document_append_child(self.document, doctype)self.document.doctype = doctypeif self._filter and self._filter.acceptNode(doctype) == FILTER_REJECT:self.document.doctype = Nonedel self.document.childNodes[-1]doctype = Noneself._parser.EntityDeclHandler = Noneself._parser.NotationDeclHandler = Noneif has_internal_subset:if doctype is not None:doctype.entities._seq = []doctype.notations._seq = []self._parser.CommentHandler = Noneself._parser.ProcessingInstructionHandler = Noneself._parser.EndDoctypeDeclHandler = self.end_doctype_decl_handlerdef end_doctype_decl_handler(self):if self._options.comments:self._parser.CommentHandler = self.comment_handlerself._parser.ProcessingInstructionHandler = self.pi_handlerif not (self._elem_info or self._filter):self._finish_end_element = iddef pi_handler(self, target, data):node = self.document.createProcessingInstruction(target, data)_append_child(self.curNode, node)if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:self.curNode.removeChild(node)def character_data_handler_cdata(self, data):childNodes = self.curNode.childNodesif self._cdata:if ( self._cdata_continueand childNodes[-1].nodeType == CDATA_SECTION_NODE):childNodes[-1].appendData(data)returnnode = self.document.createCDATASection(data)self._cdata_continue = Trueelif childNodes and childNodes[-1].nodeType == TEXT_NODE:node = childNodes[-1]value = node.data + datanode.data = valuereturnelse:node = minidom.Text()node.data = datanode.ownerDocument = self.document_append_child(self.curNode, node)def character_data_handler(self, data):childNodes = self.curNode.childNodesif childNodes and childNodes[-1].nodeType == TEXT_NODE:node = childNodes[-1]node.data = node.data + datareturnnode = minidom.Text()node.data = node.data + datanode.ownerDocument = self.document_append_child(self.curNode, node)def entity_decl_handler(self, entityName, is_parameter_entity, value,base, systemId, publicId, notationName):if is_parameter_entity:# we don't care about parameter entities for the DOMreturnif not self._options.entities:returnnode = self.document._create_entity(entityName, publicId,systemId, notationName)if value is not None:# internal entity# node *should* be readonly, but we'll cheatchild = self.document.createTextNode(value)node.childNodes.append(child)self.document.doctype.entities._seq.append(node)if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:del self.document.doctype.entities._seq[-1]def notation_decl_handler(self, notationName, base, systemId, publicId):node = self.document._create_notation(notationName, publicId, systemId)self.document.doctype.notations._seq.append(node)if self._filter and self._filter.acceptNode(node) == FILTER_ACCEPT:del self.document.doctype.notations._seq[-1]def comment_handler(self, data):node = self.document.createComment(data)_append_child(self.curNode, node)if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:self.curNode.removeChild(node)def start_cdata_section_handler(self):self._cdata = Trueself._cdata_continue = Falsedef end_cdata_section_handler(self):self._cdata = Falseself._cdata_continue = Falsedef external_entity_ref_handler(self, context, base, systemId, publicId):return 1def first_element_handler(self, name, attributes):if self._filter is None and not self._elem_info:self._finish_end_element = idself.getParser().StartElementHandler = self.start_element_handlerself.start_element_handler(name, attributes)def start_element_handler(self, name, attributes):node = self.document.createElement(name)_append_child(self.curNode, node)self.curNode = nodeif attributes:for i in range(0, len(attributes), 2):a = minidom.Attr(attributes[i], EMPTY_NAMESPACE,None, EMPTY_PREFIX)value = attributes[i+1]a.value = valuea.ownerDocument = self.document_set_attribute_node(node, a)if node is not self.document.documentElement:self._finish_start_element(node)def _finish_start_element(self, node):if self._filter:# To be general, we'd have to call isSameNode(), but this# is sufficient for minidom:if node is self.document.documentElement:returnfilt = self._filter.startContainer(node)if filt == FILTER_REJECT:# ignore this node & all descendentsRejecter(self)elif filt == FILTER_SKIP:# ignore this node, but make it's children become# children of the parent nodeSkipper(self)else:returnself.curNode = node.parentNodenode.parentNode.removeChild(node)node.unlink()# If this ever changes, Namespaces.end_element_handler() needs to# be changed to match.#def end_element_handler(self, name):curNode = self.curNodeself.curNode = curNode.parentNodeself._finish_end_element(curNode)def _finish_end_element(self, curNode):info = self._elem_info.get(curNode.tagName)if info:self._handle_white_text_nodes(curNode, info)if self._filter:if curNode is self.document.documentElement:returnif self._filter.acceptNode(curNode) == FILTER_REJECT:self.curNode.removeChild(curNode)curNode.unlink()def _handle_white_text_nodes(self, node, info):if (self._options.whitespace_in_element_contentor not info.isElementContent()):return# We have element type information and should remove ignorable# whitespace; identify for text nodes which contain only# whitespace.L = []for child in node.childNodes:if child.nodeType == TEXT_NODE and not child.data.strip():L.append(child)# Remove ignorable whitespace from the tree.for child in L:node.removeChild(child)def element_decl_handler(self, name, model):info = self._elem_info.get(name)if info is None:self._elem_info[name] = ElementInfo(name, model)else:assert info._model is Noneinfo._model = modeldef attlist_decl_handler(self, elem, name, type, default, required):info = self._elem_info.get(elem)if info is None:info = ElementInfo(elem)self._elem_info[elem] = infoinfo._attr_info.append([None, name, None, None, default, 0, type, required])def xml_decl_handler(self, version, encoding, standalone):self.document.version = versionself.document.encoding = encoding# This is still a little ugly, thanks to the pyexpat API. ;-(if standalone >= 0:if standalone:self.document.standalone = Trueelse:self.document.standalone = False# Don't include FILTER_INTERRUPT, since that's checked separately# where allowed._ALLOWED_FILTER_RETURNS = (FILTER_ACCEPT, FILTER_REJECT, FILTER_SKIP)class FilterVisibilityController(object):"""Wrapper around a DOMBuilderFilter which implements the checksto make the whatToShow filter attribute work."""__slots__ = 'filter',def __init__(self, filter):self.filter = filterdef startContainer(self, node):mask = self._nodetype_mask[node.nodeType]if self.filter.whatToShow & mask:val = self.filter.startContainer(node)if val == FILTER_INTERRUPT:raise ParseEscapeif val not in _ALLOWED_FILTER_RETURNS:raise ValueError("startContainer() returned illegal value: " + repr(val))return valelse:return FILTER_ACCEPTdef acceptNode(self, node):mask = self._nodetype_mask[node.nodeType]if self.filter.whatToShow & mask:val = self.filter.acceptNode(node)if val == FILTER_INTERRUPT:raise ParseEscapeif val == FILTER_SKIP:# move all child nodes to the parent, and remove this nodeparent = node.parentNodefor child in node.childNodes[:]:parent.appendChild(child)# node is handled by the callerreturn FILTER_REJECTif val not in _ALLOWED_FILTER_RETURNS:raise ValueError("acceptNode() returned illegal value: " + repr(val))return valelse:return FILTER_ACCEPT_nodetype_mask = {Node.ELEMENT_NODE: NodeFilter.SHOW_ELEMENT,Node.ATTRIBUTE_NODE: NodeFilter.SHOW_ATTRIBUTE,Node.TEXT_NODE: NodeFilter.SHOW_TEXT,Node.CDATA_SECTION_NODE: NodeFilter.SHOW_CDATA_SECTION,Node.ENTITY_REFERENCE_NODE: NodeFilter.SHOW_ENTITY_REFERENCE,Node.ENTITY_NODE: NodeFilter.SHOW_ENTITY,Node.PROCESSING_INSTRUCTION_NODE: NodeFilter.SHOW_PROCESSING_INSTRUCTION,Node.COMMENT_NODE: NodeFilter.SHOW_COMMENT,Node.DOCUMENT_NODE: NodeFilter.SHOW_DOCUMENT,Node.DOCUMENT_TYPE_NODE: NodeFilter.SHOW_DOCUMENT_TYPE,Node.DOCUMENT_FRAGMENT_NODE: NodeFilter.SHOW_DOCUMENT_FRAGMENT,Node.NOTATION_NODE: NodeFilter.SHOW_NOTATION,}class FilterCrutch(object):__slots__ = '_builder', '_level', '_old_start', '_old_end'def __init__(self, builder):self._level = 0self._builder = builderparser = builder._parserself._old_start = parser.StartElementHandlerself._old_end = parser.EndElementHandlerparser.StartElementHandler = self.start_element_handlerparser.EndElementHandler = self.end_element_handlerclass Rejecter(FilterCrutch):__slots__ = ()def __init__(self, builder):FilterCrutch.__init__(self, builder)parser = builder._parserfor name in ("ProcessingInstructionHandler","CommentHandler","CharacterDataHandler","StartCdataSectionHandler","EndCdataSectionHandler","ExternalEntityRefHandler",):setattr(parser, name, None)def start_element_handler(self, *args):self._level = self._level + 1def end_element_handler(self, *args):if self._level == 0:# restore the old handlersparser = self._builder._parserself._builder.install(parser)parser.StartElementHandler = self._old_startparser.EndElementHandler = self._old_endelse:self._level = self._level - 1class Skipper(FilterCrutch):__slots__ = ()def start_element_handler(self, *args):node = self._builder.curNodeself._old_start(*args)if self._builder.curNode is not node:self._level = self._level + 1def end_element_handler(self, *args):if self._level == 0:# We're popping back out of the node we're skipping, so we# shouldn't need to do anything but reset the handlers.self._builder._parser.StartElementHandler = self._old_startself._builder._parser.EndElementHandler = self._old_endself._builder = Noneelse:self._level = self._level - 1self._old_end(*args)# framework document used by the fragment builder.# Takes a string for the doctype, subset string, and namespace attrs string._FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID = \"http://xml.python.org/entities/fragment-builder/internal"_FRAGMENT_BUILDER_TEMPLATE = ('''\<!DOCTYPE wrapper%%s [<!ENTITY fragment-builder-internalSYSTEM "%s">%%s]><wrapper %%s>&fragment-builder-internal;</wrapper>'''% _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID)class FragmentBuilder(ExpatBuilder):"""Builder which constructs document fragments given XML sourcetext and a context node.The context node is expected to provide information about thenamespace declarations which are in scope at the start of thefragment."""def __init__(self, context, options=None):if context.nodeType == DOCUMENT_NODE:self.originalDocument = contextself.context = contextelse:self.originalDocument = context.ownerDocumentself.context = contextExpatBuilder.__init__(self, options)def reset(self):ExpatBuilder.reset(self)self.fragment = Nonedef parseFile(self, file):"""Parse a document fragment from a file object, returning thefragment node."""return self.parseString(file.read())def parseString(self, string):"""Parse a document fragment from a string, returning thefragment node."""self._source = stringparser = self.getParser()doctype = self.originalDocument.doctypeident = ""if doctype:subset = doctype.internalSubset or self._getDeclarations()if doctype.publicId:ident = ('PUBLIC "%s" "%s"'% (doctype.publicId, doctype.systemId))elif doctype.systemId:ident = 'SYSTEM "%s"' % doctype.systemIdelse:subset = ""nsattrs = self._getNSattrs() # get ns decls from node's ancestorsdocument = _FRAGMENT_BUILDER_TEMPLATE % (ident, subset, nsattrs)try:parser.Parse(document, 1)except:self.reset()raisefragment = self.fragmentself.reset()## self._parser = Nonereturn fragmentdef _getDeclarations(self):"""Re-create the internal subset from the DocumentType node.This is only needed if we don't already have theinternalSubset as a string."""doctype = self.context.ownerDocument.doctypes = ""if doctype:for i in range(doctype.notations.length):notation = doctype.notations.item(i)if s:s = s + "\n "s = "%s<!NOTATION %s" % (s, notation.nodeName)if notation.publicId:s = '%s PUBLIC "%s"\n "%s">' \% (s, notation.publicId, notation.systemId)else:s = '%s SYSTEM "%s">' % (s, notation.systemId)for i in range(doctype.entities.length):entity = doctype.entities.item(i)if s:s = s + "\n "s = "%s<!ENTITY %s" % (s, entity.nodeName)if entity.publicId:s = '%s PUBLIC "%s"\n "%s"' \% (s, entity.publicId, entity.systemId)elif entity.systemId:s = '%s SYSTEM "%s"' % (s, entity.systemId)else:s = '%s "%s"' % (s, entity.firstChild.data)if entity.notationName:s = "%s NOTATION %s" % (s, entity.notationName)s = s + ">"return sdef _getNSattrs(self):return ""def external_entity_ref_handler(self, context, base, systemId, publicId):if systemId == _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID:# this entref is the one that we made to put the subtree# in; all of our given input is parsed in here.old_document = self.documentold_cur_node = self.curNodeparser = self._parser.ExternalEntityParserCreate(context)# put the real document back, parse into the fragment to returnself.document = self.originalDocumentself.fragment = self.document.createDocumentFragment()self.curNode = self.fragmenttry:parser.Parse(self._source, 1)finally:self.curNode = old_cur_nodeself.document = old_documentself._source = Nonereturn -1else:return ExpatBuilder.external_entity_ref_handler(self, context, base, systemId, publicId)class Namespaces:"""Mix-in class for builders; adds support for namespaces."""def _initNamespaces(self):# list of (prefix, uri) ns declarations. Namespace attrs are# constructed from this and added to the element's attrs.self._ns_ordered_prefixes = []def createParser(self):"""Create a new namespace-handling parser."""parser = expat.ParserCreate(namespace_separator=" ")parser.namespace_prefixes = Truereturn parserdef install(self, parser):"""Insert the namespace-handlers onto the parser."""ExpatBuilder.install(self, parser)if self._options.namespace_declarations:parser.StartNamespaceDeclHandler = (self.start_namespace_decl_handler)def start_namespace_decl_handler(self, prefix, uri):"""Push this namespace declaration on our storage."""self._ns_ordered_prefixes.append((prefix, uri))def start_element_handler(self, name, attributes):if ' ' in name:uri, localname, prefix, qname = _parse_ns_name(self, name)else:uri = EMPTY_NAMESPACEqname = namelocalname = Noneprefix = EMPTY_PREFIXnode = minidom.Element(qname, uri, prefix, localname)node.ownerDocument = self.document_append_child(self.curNode, node)self.curNode = nodeif self._ns_ordered_prefixes:for prefix, uri in self._ns_ordered_prefixes:if prefix:a = minidom.Attr(_intern(self, 'xmlns:' + prefix),XMLNS_NAMESPACE, prefix, "xmlns")else:a = minidom.Attr("xmlns", XMLNS_NAMESPACE,"xmlns", EMPTY_PREFIX)a.value = uria.ownerDocument = self.document_set_attribute_node(node, a)del self._ns_ordered_prefixes[:]if attributes:node._ensure_attributes()_attrs = node._attrs_attrsNS = node._attrsNSfor i in range(0, len(attributes), 2):aname = attributes[i]value = attributes[i+1]if ' ' in aname:uri, localname, prefix, qname = _parse_ns_name(self, aname)a = minidom.Attr(qname, uri, localname, prefix)_attrs[qname] = a_attrsNS[(uri, localname)] = aelse:a = minidom.Attr(aname, EMPTY_NAMESPACE,aname, EMPTY_PREFIX)_attrs[aname] = a_attrsNS[(EMPTY_NAMESPACE, aname)] = aa.ownerDocument = self.documenta.value = valuea.ownerElement = nodeif __debug__:# This only adds some asserts to the original# end_element_handler(), so we only define this when -O is not# used. If changing one, be sure to check the other to see if# it needs to be changed as well.#def end_element_handler(self, name):curNode = self.curNodeif ' ' in name:uri, localname, prefix, qname = _parse_ns_name(self, name)assert (curNode.namespaceURI == uriand curNode.localName == localnameand curNode.prefix == prefix), \"element stack messed up! (namespace)"else:assert curNode.nodeName == name, \"element stack messed up - bad nodeName"assert curNode.namespaceURI == EMPTY_NAMESPACE, \"element stack messed up - bad namespaceURI"self.curNode = curNode.parentNodeself._finish_end_element(curNode)class ExpatBuilderNS(Namespaces, ExpatBuilder):"""Document builder that supports namespaces."""def reset(self):ExpatBuilder.reset(self)self._initNamespaces()class FragmentBuilderNS(Namespaces, FragmentBuilder):"""Fragment builder that supports namespaces."""def reset(self):FragmentBuilder.reset(self)self._initNamespaces()def _getNSattrs(self):"""Return string of namespace attributes from this element andancestors."""# XXX This needs to be re-written to walk the ancestors of the# context to build up the namespace information from# declarations, elements, and attributes found in context.# Otherwise we have to store a bunch more data on the DOM# (though that *might* be more reliable -- not clear).attrs = ""context = self.contextL = []while context:if hasattr(context, '_ns_prefix_uri'):for prefix, uri in context._ns_prefix_uri.items():# add every new NS decl from context to L and attrs stringif prefix in L:continueL.append(prefix)if prefix:declname = "xmlns:" + prefixelse:declname = "xmlns"if attrs:attrs = "%s\n %s='%s'" % (attrs, declname, uri)else:attrs = " %s='%s'" % (declname, uri)context = context.parentNodereturn attrsclass ParseEscape(Exception):"""Exception raised to short-circuit parsing in InternalSubsetExtractor."""passclass InternalSubsetExtractor(ExpatBuilder):"""XML processor which can rip out the internal document type subset."""subset = Nonedef getSubset(self):"""Return the internal subset as a string."""return self.subsetdef parseFile(self, file):try:ExpatBuilder.parseFile(self, file)except ParseEscape:passdef parseString(self, string):try:ExpatBuilder.parseString(self, string)except ParseEscape:passdef install(self, parser):parser.StartDoctypeDeclHandler = self.start_doctype_decl_handlerparser.StartElementHandler = self.start_element_handlerdef start_doctype_decl_handler(self, name, publicId, systemId,has_internal_subset):if has_internal_subset:parser = self.getParser()self.subset = []parser.DefaultHandler = self.subset.appendparser.EndDoctypeDeclHandler = self.end_doctype_decl_handlerelse:raise ParseEscape()def end_doctype_decl_handler(self):s = ''.join(self.subset).replace('\r\n', '\n').replace('\r', '\n')self.subset = sraise ParseEscape()def start_element_handler(self, name, attrs):raise ParseEscape()def parse(file, namespaces=True):"""Parse a document, returning the resulting Document node.'file' may be either a file name or an open file object."""if namespaces:builder = ExpatBuilderNS()else:builder = ExpatBuilder()if isinstance(file, str):with open(file, 'rb') as fp:result = builder.parseFile(fp)else:result = builder.parseFile(file)return resultdef parseString(string, namespaces=True):"""Parse a document from a string, returning the resultingDocument node."""if namespaces:builder = ExpatBuilderNS()else:builder = ExpatBuilder()return builder.parseString(string)def parseFragment(file, context, namespaces=True):"""Parse a fragment of a document, given the context from which itwas originally extracted. context should be the parent of thenode(s) which are in the fragment.'file' may be either a file name or an open file object."""if namespaces:builder = FragmentBuilderNS(context)else:builder = FragmentBuilder(context)if isinstance(file, str):with open(file, 'rb') as fp:result = builder.parseFile(fp)else:result = builder.parseFile(file)return resultdef parseFragmentString(string, context, namespaces=True):"""Parse a fragment of a document from a string, given the contextfrom which it was originally extracted. context should be theparent of the node(s) which are in the fragment."""if namespaces:builder = FragmentBuilderNS(context)else:builder = FragmentBuilder(context)return builder.parseString(string)def makeBuilder(options):"""Create a builder based on an Options object."""if options.namespaces:return ExpatBuilderNS(options)else:return ExpatBuilder(options)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。