home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / expatbuilder.pyc (.txt) < prev    next >
Python Compiled Bytecode  |  2003-12-30  |  46KB  |  1,023 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.3)
  3.  
  4. '''Facility to use the Expat parser to load a minidom instance
  5. from a string or file.
  6.  
  7. This avoids all the overhead of SAX and pulldom to gain performance.
  8. '''
  9. from xml.dom import xmlbuilder, minidom, Node
  10. from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE
  11. from xml.parsers import expat
  12. from xml.dom.minidom import _append_child, _set_attribute_node
  13. from xml.dom.NodeFilter import NodeFilter
  14. from xml.dom.minicompat import *
  15. TEXT_NODE = Node.TEXT_NODE
  16. CDATA_SECTION_NODE = Node.CDATA_SECTION_NODE
  17. DOCUMENT_NODE = Node.DOCUMENT_NODE
  18. FILTER_ACCEPT = xmlbuilder.DOMBuilderFilter.FILTER_ACCEPT
  19. FILTER_REJECT = xmlbuilder.DOMBuilderFilter.FILTER_REJECT
  20. FILTER_SKIP = xmlbuilder.DOMBuilderFilter.FILTER_SKIP
  21. FILTER_INTERRUPT = xmlbuilder.DOMBuilderFilter.FILTER_INTERRUPT
  22. theDOMImplementation = minidom.getDOMImplementation()
  23. _typeinfo_map = {
  24.     'CDATA': minidom.TypeInfo(None, 'cdata'),
  25.     'ENUM': minidom.TypeInfo(None, 'enumeration'),
  26.     'ENTITY': minidom.TypeInfo(None, 'entity'),
  27.     'ENTITIES': minidom.TypeInfo(None, 'entities'),
  28.     'ID': minidom.TypeInfo(None, 'id'),
  29.     'IDREF': minidom.TypeInfo(None, 'idref'),
  30.     'IDREFS': minidom.TypeInfo(None, 'idrefs'),
  31.     'NMTOKEN': minidom.TypeInfo(None, 'nmtoken'),
  32.     'NMTOKENS': minidom.TypeInfo(None, 'nmtokens') }
  33.  
  34. class ElementInfo(NewStyle):
  35.     __slots__ = ('_attr_info', '_model', 'tagName')
  36.     
  37.     def __init__(self, tagName, model = None):
  38.         self.tagName = tagName
  39.         self._attr_info = []
  40.         self._model = model
  41.  
  42.     
  43.     def __getstate__(self):
  44.         return (self._attr_info, self._model, self.tagName)
  45.  
  46.     
  47.     def __setstate__(self, state):
  48.         (self._attr_info, self._model, self.tagName) = state
  49.  
  50.     
  51.     def getAttributeType(self, aname):
  52.         for info in self._attr_info:
  53.             if info[1] == aname:
  54.                 t = info[-2]
  55.                 if t[0] == '(':
  56.                     return _typeinfo_map['ENUM']
  57.                 else:
  58.                     return _typeinfo_map[info[-2]]
  59.             t[0] == '('
  60.         
  61.         return minidom._no_type
  62.  
  63.     
  64.     def getAttributeTypeNS(self, namespaceURI, localName):
  65.         return minidom._no_type
  66.  
  67.     
  68.     def isElementContent(self):
  69.         if self._model:
  70.             type = self._model[0]
  71.             return type not in (expat.model.XML_CTYPE_ANY, expat.model.XML_CTYPE_MIXED)
  72.         else:
  73.             return False
  74.  
  75.     
  76.     def isEmpty(self):
  77.         if self._model:
  78.             return self._model[0] == expat.model.XML_CTYPE_EMPTY
  79.         else:
  80.             return False
  81.  
  82.     
  83.     def isId(self, aname):
  84.         for info in self._attr_info:
  85.             if info[1] == aname:
  86.                 return info[-2] == 'ID'
  87.                 continue
  88.         
  89.         return False
  90.  
  91.     
  92.     def isIdNS(self, euri, ename, auri, aname):
  93.         return self.isId((auri, aname))
  94.  
  95.  
  96.  
  97. def _intern(builder, s):
  98.     return builder._intern_setdefault(s, s)
  99.  
  100.  
  101. def _parse_ns_name(builder, name):
  102.     if not ' ' in name:
  103.         raise AssertionError
  104.     parts = name.split(' ')
  105.     intern = builder._intern_setdefault
  106.     if len(parts) == 3:
  107.         (uri, localname, prefix) = parts
  108.         prefix = intern(prefix, prefix)
  109.         qname = '%s:%s' % (prefix, localname)
  110.         qname = intern(qname, qname)
  111.         localname = intern(localname, localname)
  112.     else:
  113.         (uri, localname) = parts
  114.         prefix = EMPTY_PREFIX
  115.         qname = localname = intern(localname, localname)
  116.     return (intern(uri, uri), localname, prefix, qname)
  117.  
  118.  
  119. class ExpatBuilder:
  120.     '''Document builder that uses Expat to build a ParsedXML.DOM document
  121.     instance.'''
  122.     
  123.     def __init__(self, options = None):
  124.         if options is None:
  125.             options = xmlbuilder.Options()
  126.         
  127.         self._options = options
  128.         if self._options.filter is not None:
  129.             self._filter = FilterVisibilityController(self._options.filter)
  130.         else:
  131.             self._filter = None
  132.             self._finish_start_element = id
  133.         self._parser = None
  134.         self.reset()
  135.  
  136.     
  137.     def createParser(self):
  138.         '''Create a new parser object.'''
  139.         return expat.ParserCreate()
  140.  
  141.     
  142.     def getParser(self):
  143.         '''Return the parser object, creating a new one if needed.'''
  144.         if not (self._parser):
  145.             self._parser = self.createParser()
  146.             self._intern_setdefault = self._parser.intern.setdefault
  147.             self._parser.buffer_text = True
  148.             self._parser.ordered_attributes = True
  149.             self._parser.specified_attributes = True
  150.             self.install(self._parser)
  151.         
  152.         return self._parser
  153.  
  154.     
  155.     def reset(self):
  156.         '''Free all data structures used during DOM construction.'''
  157.         self.document = theDOMImplementation.createDocument(EMPTY_NAMESPACE, None, None)
  158.         self.curNode = self.document
  159.         self._elem_info = self.document._elem_info
  160.         self._cdata = False
  161.  
  162.     
  163.     def install(self, parser):
  164.         '''Install the callbacks needed to build the DOM into the parser.'''
  165.         parser.StartDoctypeDeclHandler = self.start_doctype_decl_handler
  166.         parser.StartElementHandler = self.first_element_handler
  167.         parser.EndElementHandler = self.end_element_handler
  168.         parser.ProcessingInstructionHandler = self.pi_handler
  169.         if self._options.entities:
  170.             parser.EntityDeclHandler = self.entity_decl_handler
  171.         
  172.         parser.NotationDeclHandler = self.notation_decl_handler
  173.         if self._options.comments:
  174.             parser.CommentHandler = self.comment_handler
  175.         
  176.         if self._options.cdata_sections:
  177.             parser.StartCdataSectionHandler = self.start_cdata_section_handler
  178.             parser.EndCdataSectionHandler = self.end_cdata_section_handler
  179.             parser.CharacterDataHandler = self.character_data_handler_cdata
  180.         else:
  181.             parser.CharacterDataHandler = self.character_data_handler
  182.         parser.ExternalEntityRefHandler = self.external_entity_ref_handler
  183.         parser.XmlDeclHandler = self.xml_decl_handler
  184.         parser.ElementDeclHandler = self.element_decl_handler
  185.         parser.AttlistDeclHandler = self.attlist_decl_handler
  186.  
  187.     
  188.     def parseFile(self, file):
  189.         '''Parse a document from a file object, returning the document
  190.         node.'''
  191.         parser = self.getParser()
  192.         first_buffer = True
  193.         
  194.         try:
  195.             while None:
  196.                 pass
  197.             if None:
  198.                 buffer = file.read(16 * 1024)
  199.                 if not buffer:
  200.                     break
  201.                 
  202.                 parser.Parse(buffer, 0)
  203.                 if first_buffer and self.document.documentElement:
  204.                     self._setup_subset(buffer)
  205.                 
  206.                 first_buffer = False
  207.                 continue
  208.         except ParseEscape:
  209.             pass
  210.  
  211.         doc = self.document
  212.         self.reset()
  213.         self._parser = None
  214.         return doc
  215.  
  216.     
  217.     def parseString(self, string):
  218.         '''Parse a document from a string, returning the document node.'''
  219.         parser = self.getParser()
  220.         
  221.         try:
  222.             parser.Parse(string, True)
  223.             self._setup_subset(string)
  224.         except ParseEscape:
  225.             pass
  226.  
  227.         doc = self.document
  228.         self.reset()
  229.         self._parser = None
  230.         return doc
  231.  
  232.     
  233.     def _setup_subset(self, buffer):
  234.         '''Load the internal subset if there might be one.'''
  235.         if self.document.doctype:
  236.             extractor = InternalSubsetExtractor()
  237.             extractor.parseString(buffer)
  238.             subset = extractor.getSubset()
  239.             self.document.doctype.internalSubset = subset
  240.         
  241.  
  242.     
  243.     def start_doctype_decl_handler(self, doctypeName, systemId, publicId, has_internal_subset):
  244.         doctype = self.document.implementation.createDocumentType(doctypeName, publicId, systemId)
  245.         doctype.ownerDocument = self.document
  246.         self.document.childNodes.append(doctype)
  247.         self.document.doctype = doctype
  248.         if self._filter and self._filter.acceptNode(doctype) == FILTER_REJECT:
  249.             self.document.doctype = None
  250.             del self.document.childNodes[-1]
  251.             doctype = None
  252.             self._parser.EntityDeclHandler = None
  253.             self._parser.NotationDeclHandler = None
  254.         
  255.         if has_internal_subset:
  256.             if doctype is not None:
  257.                 doctype.entities._seq = []
  258.                 doctype.notations._seq = []
  259.             
  260.             self._parser.CommentHandler = None
  261.             self._parser.ProcessingInstructionHandler = None
  262.             self._parser.EndDoctypeDeclHandler = self.end_doctype_decl_handler
  263.         
  264.  
  265.     
  266.     def end_doctype_decl_handler(self):
  267.         if self._options.comments:
  268.             self._parser.CommentHandler = self.comment_handler
  269.         
  270.         self._parser.ProcessingInstructionHandler = self.pi_handler
  271.         if not self._elem_info:
  272.             pass
  273.         if not (self._filter):
  274.             self._finish_end_element = id
  275.         
  276.  
  277.     
  278.     def pi_handler(self, target, data):
  279.         node = self.document.createProcessingInstruction(target, data)
  280.         _append_child(self.curNode, node)
  281.         if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:
  282.             self.curNode.removeChild(node)
  283.         
  284.  
  285.     
  286.     def character_data_handler_cdata(self, data):
  287.         childNodes = self.curNode.childNodes
  288.         if self._cdata:
  289.             if self._cdata_continue and childNodes[-1].nodeType == CDATA_SECTION_NODE:
  290.                 childNodes[-1].appendData(data)
  291.                 return None
  292.             
  293.             node = self.document.createCDATASection(data)
  294.             self._cdata_continue = True
  295.         elif childNodes and childNodes[-1].nodeType == TEXT_NODE:
  296.             node = childNodes[-1]
  297.             value = node.data + data
  298.             d = node.__dict__
  299.             d['data'] = d['nodeValue'] = value
  300.             return None
  301.         else:
  302.             node = minidom.Text()
  303.             d = node.__dict__
  304.             d['data'] = d['nodeValue'] = data
  305.             d['ownerDocument'] = self.document
  306.         _append_child(self.curNode, node)
  307.  
  308.     
  309.     def character_data_handler(self, data):
  310.         childNodes = self.curNode.childNodes
  311.         if childNodes and childNodes[-1].nodeType == TEXT_NODE:
  312.             node = childNodes[-1]
  313.             d = node.__dict__
  314.             d['data'] = d['nodeValue'] = node.data + data
  315.             return None
  316.         
  317.         node = minidom.Text()
  318.         d = node.__dict__
  319.         d['data'] = d['nodeValue'] = node.data + data
  320.         d['ownerDocument'] = self.document
  321.         _append_child(self.curNode, node)
  322.  
  323.     
  324.     def entity_decl_handler(self, entityName, is_parameter_entity, value, base, systemId, publicId, notationName):
  325.         if is_parameter_entity:
  326.             return None
  327.         
  328.         if not (self._options.entities):
  329.             return None
  330.         
  331.         node = self.document._create_entity(entityName, publicId, systemId, notationName)
  332.         if value is not None:
  333.             child = self.document.createTextNode(value)
  334.             node.childNodes.append(child)
  335.         
  336.         self.document.doctype.entities._seq.append(node)
  337.         if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:
  338.             del self.document.doctype.entities._seq[-1]
  339.         
  340.  
  341.     
  342.     def notation_decl_handler(self, notationName, base, systemId, publicId):
  343.         node = self.document._create_notation(notationName, publicId, systemId)
  344.         self.document.doctype.notations._seq.append(node)
  345.         if self._filter and self._filter.acceptNode(node) == FILTER_ACCEPT:
  346.             del self.document.doctype.notations._seq[-1]
  347.         
  348.  
  349.     
  350.     def comment_handler(self, data):
  351.         node = self.document.createComment(data)
  352.         _append_child(self.curNode, node)
  353.         if self._filter and self._filter.acceptNode(node) == FILTER_REJECT:
  354.             self.curNode.removeChild(node)
  355.         
  356.  
  357.     
  358.     def start_cdata_section_handler(self):
  359.         self._cdata = True
  360.         self._cdata_continue = False
  361.  
  362.     
  363.     def end_cdata_section_handler(self):
  364.         self._cdata = False
  365.         self._cdata_continue = False
  366.  
  367.     
  368.     def external_entity_ref_handler(self, context, base, systemId, publicId):
  369.         return 1
  370.  
  371.     
  372.     def first_element_handler(self, name, attributes):
  373.         if self._filter is None and not (self._elem_info):
  374.             self._finish_end_element = id
  375.         
  376.         self.getParser().StartElementHandler = self.start_element_handler
  377.         self.start_element_handler(name, attributes)
  378.  
  379.     
  380.     def start_element_handler(self, name, attributes):
  381.         node = self.document.createElement(name)
  382.         _append_child(self.curNode, node)
  383.         self.curNode = node
  384.         if attributes:
  385.             for i in range(0, len(attributes), 2):
  386.                 a = minidom.Attr(attributes[i], EMPTY_NAMESPACE, None, EMPTY_PREFIX)
  387.                 value = attributes[i + 1]
  388.                 d = a.childNodes[0].__dict__
  389.                 d['data'] = d['nodeValue'] = value
  390.                 d = a.__dict__
  391.                 d['value'] = d['nodeValue'] = value
  392.                 d['ownerDocument'] = self.document
  393.                 _set_attribute_node(node, a)
  394.             
  395.         
  396.         if node is not self.document.documentElement:
  397.             self._finish_start_element(node)
  398.         
  399.  
  400.     
  401.     def _finish_start_element(self, node):
  402.         if self._filter:
  403.             if node is self.document.documentElement:
  404.                 return None
  405.             
  406.             filt = self._filter.startContainer(node)
  407.             if filt == FILTER_REJECT:
  408.                 Rejecter(self)
  409.             elif filt == FILTER_SKIP:
  410.                 Skipper(self)
  411.             else:
  412.                 return None
  413.             self.curNode = node.parentNode
  414.             node.parentNode.removeChild(node)
  415.             node.unlink()
  416.         
  417.  
  418.     
  419.     def end_element_handler(self, name):
  420.         curNode = self.curNode
  421.         self.curNode = curNode.parentNode
  422.         self._finish_end_element(curNode)
  423.  
  424.     
  425.     def _finish_end_element(self, curNode):
  426.         info = self._elem_info.get(curNode.tagName)
  427.         if info:
  428.             self._handle_white_text_nodes(curNode, info)
  429.         
  430.         if self._filter:
  431.             if curNode is self.document.documentElement:
  432.                 return None
  433.             
  434.             if self._filter.acceptNode(curNode) == FILTER_REJECT:
  435.                 self.curNode.removeChild(curNode)
  436.                 curNode.unlink()
  437.             
  438.         
  439.  
  440.     
  441.     def _handle_white_text_nodes(self, node, info):
  442.         if self._options.whitespace_in_element_content or not info.isElementContent():
  443.             return None
  444.         
  445.         L = []
  446.         for child in node.childNodes:
  447.             if child.nodeType == TEXT_NODE and not child.data.strip():
  448.                 L.append(child)
  449.                 continue
  450.         
  451.         for child in L:
  452.             node.removeChild(child)
  453.         
  454.  
  455.     
  456.     def element_decl_handler(self, name, model):
  457.         info = self._elem_info.get(name)
  458.         if info is None:
  459.             self._elem_info[name] = ElementInfo(name, model)
  460.         elif not info._model is None:
  461.             raise AssertionError
  462.         info._model = model
  463.  
  464.     
  465.     def attlist_decl_handler(self, elem, name, type, default, required):
  466.         info = self._elem_info.get(elem)
  467.         if info is None:
  468.             info = ElementInfo(elem)
  469.             self._elem_info[elem] = info
  470.         
  471.         info._attr_info.append([
  472.             None,
  473.             name,
  474.             None,
  475.             None,
  476.             default,
  477.             0,
  478.             type,
  479.             required])
  480.  
  481.     
  482.     def xml_decl_handler(self, version, encoding, standalone):
  483.         self.document.version = version
  484.         self.document.encoding = encoding
  485.         if standalone >= 0:
  486.             if standalone:
  487.                 self.document.standalone = True
  488.             else:
  489.                 self.document.standalone = False
  490.         
  491.  
  492.  
  493. _ALLOWED_FILTER_RETURNS = (FILTER_ACCEPT, FILTER_REJECT, FILTER_SKIP)
  494.  
  495. class FilterVisibilityController(NewStyle):
  496.     '''Wrapper around a DOMBuilderFilter which implements the checks
  497.     to make the whatToShow filter attribute work.'''
  498.     __slots__ = ('filter',)
  499.     
  500.     def __init__(self, filter):
  501.         self.filter = filter
  502.  
  503.     
  504.     def startContainer(self, node):
  505.         mask = self._nodetype_mask[node.nodeType]
  506.         if self.filter.whatToShow & mask:
  507.             val = self.filter.startContainer(node)
  508.             if val == FILTER_INTERRUPT:
  509.                 raise ParseEscape
  510.             
  511.             if val not in _ALLOWED_FILTER_RETURNS:
  512.                 raise ValueError, 'startContainer() returned illegal value: ' + repr(val)
  513.             
  514.             return val
  515.         else:
  516.             return FILTER_ACCEPT
  517.  
  518.     
  519.     def acceptNode(self, node):
  520.         mask = self._nodetype_mask[node.nodeType]
  521.         if self.filter.whatToShow & mask:
  522.             val = self.filter.acceptNode(node)
  523.             if val == FILTER_INTERRUPT:
  524.                 raise ParseEscape
  525.             
  526.             if val == FILTER_SKIP:
  527.                 parent = node.parentNode
  528.                 for child in node.childNodes[:]:
  529.                     parent.appendChild(child)
  530.                 
  531.                 return FILTER_REJECT
  532.             
  533.             if val not in _ALLOWED_FILTER_RETURNS:
  534.                 raise ValueError, 'acceptNode() returned illegal value: ' + repr(val)
  535.             
  536.             return val
  537.         else:
  538.             return FILTER_ACCEPT
  539.  
  540.     _nodetype_mask = {
  541.         Node.ELEMENT_NODE: NodeFilter.SHOW_ELEMENT,
  542.         Node.ATTRIBUTE_NODE: NodeFilter.SHOW_ATTRIBUTE,
  543.         Node.TEXT_NODE: NodeFilter.SHOW_TEXT,
  544.         Node.CDATA_SECTION_NODE: NodeFilter.SHOW_CDATA_SECTION,
  545.         Node.ENTITY_REFERENCE_NODE: NodeFilter.SHOW_ENTITY_REFERENCE,
  546.         Node.ENTITY_NODE: NodeFilter.SHOW_ENTITY,
  547.         Node.PROCESSING_INSTRUCTION_NODE: NodeFilter.SHOW_PROCESSING_INSTRUCTION,
  548.         Node.COMMENT_NODE: NodeFilter.SHOW_COMMENT,
  549.         Node.DOCUMENT_NODE: NodeFilter.SHOW_DOCUMENT,
  550.         Node.DOCUMENT_TYPE_NODE: NodeFilter.SHOW_DOCUMENT_TYPE,
  551.         Node.DOCUMENT_FRAGMENT_NODE: NodeFilter.SHOW_DOCUMENT_FRAGMENT,
  552.         Node.NOTATION_NODE: NodeFilter.SHOW_NOTATION }
  553.  
  554.  
  555. class FilterCrutch(NewStyle):
  556.     __slots__ = ('_builder', '_level', '_old_start', '_old_end')
  557.     
  558.     def __init__(self, builder):
  559.         self._level = 0
  560.         self._builder = builder
  561.         parser = builder._parser
  562.         self._old_start = parser.StartElementHandler
  563.         self._old_end = parser.EndElementHandler
  564.         parser.StartElementHandler = self.start_element_handler
  565.         parser.EndElementHandler = self.end_element_handler
  566.  
  567.  
  568.  
  569. class Rejecter(FilterCrutch):
  570.     __slots__ = ()
  571.     
  572.     def __init__(self, builder):
  573.         FilterCrutch.__init__(self, builder)
  574.         parser = builder._parser
  575.         for name in ('ProcessingInstructionHandler', 'CommentHandler', 'CharacterDataHandler', 'StartCdataSectionHandler', 'EndCdataSectionHandler', 'ExternalEntityRefHandler'):
  576.             setattr(parser, name, None)
  577.         
  578.  
  579.     
  580.     def start_element_handler(self, *args):
  581.         self._level = self._level + 1
  582.  
  583.     
  584.     def end_element_handler(self, *args):
  585.         if self._level == 0:
  586.             parser = self._builder._parser
  587.             self._builder.install(parser)
  588.             parser.StartElementHandler = self._old_start
  589.             parser.EndElementHandler = self._old_end
  590.         else:
  591.             self._level = self._level - 1
  592.  
  593.  
  594.  
  595. class Skipper(FilterCrutch):
  596.     __slots__ = ()
  597.     
  598.     def start_element_handler(self, *args):
  599.         node = self._builder.curNode
  600.         self._old_start(*args)
  601.         if self._builder.curNode is not node:
  602.             self._level = self._level + 1
  603.         
  604.  
  605.     
  606.     def end_element_handler(self, *args):
  607.         if self._level == 0:
  608.             self._builder._parser.StartElementHandler = self._old_start
  609.             self._builder._parser.EndElementHandler = self._old_end
  610.             self._builder = None
  611.         else:
  612.             self._level = self._level - 1
  613.             self._old_end(*args)
  614.  
  615.  
  616. _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID = 'http://xml.python.org/entities/fragment-builder/internal'
  617. _FRAGMENT_BUILDER_TEMPLATE = '<!DOCTYPE wrapper\n  %%s [\n  <!ENTITY fragment-builder-internal\n    SYSTEM "%s">\n%%s\n]>\n<wrapper %%s\n>&fragment-builder-internal;</wrapper>' % _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID
  618.  
  619. class FragmentBuilder(ExpatBuilder):
  620.     '''Builder which constructs document fragments given XML source
  621.     text and a context node.
  622.  
  623.     The context node is expected to provide information about the
  624.     namespace declarations which are in scope at the start of the
  625.     fragment.
  626.     '''
  627.     
  628.     def __init__(self, context, options = None):
  629.         if context.nodeType == DOCUMENT_NODE:
  630.             self.originalDocument = context
  631.             self.context = context
  632.         else:
  633.             self.originalDocument = context.ownerDocument
  634.             self.context = context
  635.         ExpatBuilder.__init__(self, options)
  636.  
  637.     
  638.     def reset(self):
  639.         ExpatBuilder.reset(self)
  640.         self.fragment = None
  641.  
  642.     
  643.     def parseFile(self, file):
  644.         '''Parse a document fragment from a file object, returning the
  645.         fragment node.'''
  646.         return self.parseString(file.read())
  647.  
  648.     
  649.     def parseString(self, string):
  650.         '''Parse a document fragment from a string, returning the
  651.         fragment node.'''
  652.         self._source = string
  653.         parser = self.getParser()
  654.         doctype = self.originalDocument.doctype
  655.         ident = ''
  656.         if doctype:
  657.             if not doctype.internalSubset:
  658.                 pass
  659.             subset = self._getDeclarations()
  660.             if doctype.publicId:
  661.                 ident = 'PUBLIC "%s" "%s"' % (doctype.publicId, doctype.systemId)
  662.             elif doctype.systemId:
  663.                 ident = 'SYSTEM "%s"' % doctype.systemId
  664.             
  665.         else:
  666.             subset = ''
  667.         nsattrs = self._getNSattrs()
  668.         document = _FRAGMENT_BUILDER_TEMPLATE % (ident, subset, nsattrs)
  669.         
  670.         try:
  671.             parser.Parse(document, 1)
  672.         except:
  673.             self.reset()
  674.             raise 
  675.  
  676.         fragment = self.fragment
  677.         self.reset()
  678.         return fragment
  679.  
  680.     
  681.     def _getDeclarations(self):
  682.         """Re-create the internal subset from the DocumentType node.
  683.  
  684.         This is only needed if we don't already have the
  685.         internalSubset as a string.
  686.         """
  687.         doctype = self.context.ownerDocument.doctype
  688.         s = ''
  689.         if doctype:
  690.             for i in range(doctype.notations.length):
  691.                 notation = doctype.notations.item(i)
  692.                 if s:
  693.                     s = s + '\n  '
  694.                 
  695.                 s = '%s<!NOTATION %s' % (s, notation.nodeName)
  696.                 if notation.publicId:
  697.                     s = '%s PUBLIC "%s"\n             "%s">' % (s, notation.publicId, notation.systemId)
  698.                     continue
  699.                 s = '%s SYSTEM "%s">' % (s, notation.systemId)
  700.             
  701.             for i in range(doctype.entities.length):
  702.                 entity = doctype.entities.item(i)
  703.                 if s:
  704.                     s = s + '\n  '
  705.                 
  706.                 s = '%s<!ENTITY %s' % (s, entity.nodeName)
  707.                 if entity.publicId:
  708.                     s = '%s PUBLIC "%s"\n             "%s"' % (s, entity.publicId, entity.systemId)
  709.                 elif entity.systemId:
  710.                     s = '%s SYSTEM "%s"' % (s, entity.systemId)
  711.                 else:
  712.                     s = '%s "%s"' % (s, entity.firstChild.data)
  713.                 if entity.notationName:
  714.                     s = '%s NOTATION %s' % (s, entity.notationName)
  715.                 
  716.                 s = s + '>'
  717.             
  718.         
  719.         return s
  720.  
  721.     
  722.     def _getNSattrs(self):
  723.         return ''
  724.  
  725.     
  726.     def external_entity_ref_handler(self, context, base, systemId, publicId):
  727.         if systemId == _FRAGMENT_BUILDER_INTERNAL_SYSTEM_ID:
  728.             old_document = self.document
  729.             old_cur_node = self.curNode
  730.             parser = self._parser.ExternalEntityParserCreate(context)
  731.             self.document = self.originalDocument
  732.             self.fragment = self.document.createDocumentFragment()
  733.             self.curNode = self.fragment
  734.             
  735.             try:
  736.                 parser.Parse(self._source, 1)
  737.             finally:
  738.                 self.curNode = old_cur_node
  739.                 self.document = old_document
  740.                 self._source = None
  741.  
  742.             return -1
  743.         else:
  744.             return ExpatBuilder.external_entity_ref_handler(self, context, base, systemId, publicId)
  745.  
  746.  
  747.  
  748. class Namespaces:
  749.     '''Mix-in class for builders; adds support for namespaces.'''
  750.     
  751.     def _initNamespaces(self):
  752.         self._ns_ordered_prefixes = []
  753.  
  754.     
  755.     def createParser(self):
  756.         '''Create a new namespace-handling parser.'''
  757.         parser = expat.ParserCreate(namespace_separator = ' ')
  758.         parser.namespace_prefixes = True
  759.         return parser
  760.  
  761.     
  762.     def install(self, parser):
  763.         '''Insert the namespace-handlers onto the parser.'''
  764.         ExpatBuilder.install(self, parser)
  765.         if self._options.namespace_declarations:
  766.             parser.StartNamespaceDeclHandler = self.start_namespace_decl_handler
  767.         
  768.  
  769.     
  770.     def start_namespace_decl_handler(self, prefix, uri):
  771.         '''Push this namespace declaration on our storage.'''
  772.         self._ns_ordered_prefixes.append((prefix, uri))
  773.  
  774.     
  775.     def start_element_handler(self, name, attributes):
  776.         if ' ' in name:
  777.             (uri, localname, prefix, qname) = _parse_ns_name(self, name)
  778.         else:
  779.             uri = EMPTY_NAMESPACE
  780.             qname = name
  781.             localname = None
  782.             prefix = EMPTY_PREFIX
  783.         node = minidom.Element(qname, uri, prefix, localname)
  784.         node.ownerDocument = self.document
  785.         _append_child(self.curNode, node)
  786.         self.curNode = node
  787.         if self._ns_ordered_prefixes:
  788.             for prefix, uri in self._ns_ordered_prefixes:
  789.                 if prefix:
  790.                     a = minidom.Attr(_intern(self, 'xmlns:' + prefix), XMLNS_NAMESPACE, prefix, 'xmlns')
  791.                 else:
  792.                     a = minidom.Attr('xmlns', XMLNS_NAMESPACE, 'xmlns', EMPTY_PREFIX)
  793.                 d = a.childNodes[0].__dict__
  794.                 d['data'] = d['nodeValue'] = uri
  795.                 d = a.__dict__
  796.                 d['value'] = d['nodeValue'] = uri
  797.                 d['ownerDocument'] = self.document
  798.                 _set_attribute_node(node, a)
  799.             
  800.             del self._ns_ordered_prefixes[:]
  801.         
  802.         if attributes:
  803.             _attrs = node._attrs
  804.             _attrsNS = node._attrsNS
  805.             for i in range(0, len(attributes), 2):
  806.                 aname = attributes[i]
  807.                 value = attributes[i + 1]
  808.                 if ' ' in aname:
  809.                     (uri, localname, prefix, qname) = _parse_ns_name(self, aname)
  810.                     a = minidom.Attr(qname, uri, localname, prefix)
  811.                     _attrs[qname] = a
  812.                     _attrsNS[(uri, localname)] = a
  813.                 else:
  814.                     a = minidom.Attr(aname, EMPTY_NAMESPACE, aname, EMPTY_PREFIX)
  815.                     _attrs[aname] = a
  816.                     _attrsNS[(EMPTY_NAMESPACE, aname)] = a
  817.                 d = a.childNodes[0].__dict__
  818.                 d['data'] = d['nodeValue'] = value
  819.                 d = a.__dict__
  820.                 d['ownerDocument'] = self.document
  821.                 d['value'] = d['nodeValue'] = value
  822.                 d['ownerElement'] = node
  823.             
  824.         
  825.  
  826.     if __debug__:
  827.         
  828.         def end_element_handler(self, name):
  829.             curNode = self.curNode
  830.             if ' ' in name:
  831.                 (uri, localname, prefix, qname) = _parse_ns_name(self, name)
  832.                 if not curNode.namespaceURI == uri and curNode.localName == localname and curNode.prefix == prefix:
  833.                     raise AssertionError, 'element stack messed up! (namespace)'
  834.             elif not curNode.nodeName == name:
  835.                 raise AssertionError, 'element stack messed up - bad nodeName'
  836.             if not curNode.namespaceURI == EMPTY_NAMESPACE:
  837.                 raise AssertionError, 'element stack messed up - bad namespaceURI'
  838.             self.curNode = curNode.parentNode
  839.             self._finish_end_element(curNode)
  840.  
  841.     
  842.  
  843.  
  844. class ExpatBuilderNS(Namespaces, ExpatBuilder):
  845.     '''Document builder that supports namespaces.'''
  846.     
  847.     def reset(self):
  848.         ExpatBuilder.reset(self)
  849.         self._initNamespaces()
  850.  
  851.  
  852.  
  853. class FragmentBuilderNS(Namespaces, FragmentBuilder):
  854.     '''Fragment builder that supports namespaces.'''
  855.     
  856.     def reset(self):
  857.         FragmentBuilder.reset(self)
  858.         self._initNamespaces()
  859.  
  860.     
  861.     def _getNSattrs(self):
  862.         '''Return string of namespace attributes from this element and
  863.         ancestors.'''
  864.         attrs = ''
  865.         context = self.context
  866.         L = []
  867.         while context:
  868.             if hasattr(context, '_ns_prefix_uri'):
  869.                 for prefix, uri in context._ns_prefix_uri.items():
  870.                     if prefix in L:
  871.                         continue
  872.                     
  873.                     L.append(prefix)
  874.                     if prefix:
  875.                         declname = 'xmlns:' + prefix
  876.                     else:
  877.                         declname = 'xmlns'
  878.                     if attrs:
  879.                         attrs = "%s\n    %s='%s'" % (attrs, declname, uri)
  880.                         continue
  881.                     attrs = " %s='%s'" % (declname, uri)
  882.                 
  883.             
  884.             context = context.parentNode
  885.         return attrs
  886.  
  887.  
  888.  
  889. class ParseEscape(Exception):
  890.     '''Exception raised to short-circuit parsing in InternalSubsetExtractor.'''
  891.     pass
  892.  
  893.  
  894. class InternalSubsetExtractor(ExpatBuilder):
  895.     '''XML processor which can rip out the internal document type subset.'''
  896.     subset = None
  897.     
  898.     def getSubset(self):
  899.         '''Return the internal subset as a string.'''
  900.         return self.subset
  901.  
  902.     
  903.     def parseFile(self, file):
  904.         
  905.         try:
  906.             ExpatBuilder.parseFile(self, file)
  907.         except ParseEscape:
  908.             pass
  909.  
  910.  
  911.     
  912.     def parseString(self, string):
  913.         
  914.         try:
  915.             ExpatBuilder.parseString(self, string)
  916.         except ParseEscape:
  917.             pass
  918.  
  919.  
  920.     
  921.     def install(self, parser):
  922.         parser.StartDoctypeDeclHandler = self.start_doctype_decl_handler
  923.         parser.StartElementHandler = self.start_element_handler
  924.  
  925.     
  926.     def start_doctype_decl_handler(self, name, publicId, systemId, has_internal_subset):
  927.         if has_internal_subset:
  928.             parser = self.getParser()
  929.             self.subset = []
  930.             parser.DefaultHandler = self.subset.append
  931.             parser.EndDoctypeDeclHandler = self.end_doctype_decl_handler
  932.         else:
  933.             raise ParseEscape()
  934.  
  935.     
  936.     def end_doctype_decl_handler(self):
  937.         s = ''.join(self.subset).replace('\r\n', '\n').replace('\r', '\n')
  938.         self.subset = s
  939.         raise ParseEscape()
  940.  
  941.     
  942.     def start_element_handler(self, name, attrs):
  943.         raise ParseEscape()
  944.  
  945.  
  946.  
  947. def parse(file, namespaces = 1):
  948.     """Parse a document, returning the resulting Document node.
  949.  
  950.     'file' may be either a file name or an open file object.
  951.     """
  952.     if namespaces:
  953.         builder = ExpatBuilderNS()
  954.     else:
  955.         builder = ExpatBuilder()
  956.     if isinstance(file, StringTypes):
  957.         fp = open(file, 'rb')
  958.         
  959.         try:
  960.             result = builder.parseFile(fp)
  961.         finally:
  962.             fp.close()
  963.  
  964.     else:
  965.         result = builder.parseFile(file)
  966.     return result
  967.  
  968.  
  969. def parseString(string, namespaces = 1):
  970.     '''Parse a document from a string, returning the resulting
  971.     Document node.
  972.     '''
  973.     if namespaces:
  974.         builder = ExpatBuilderNS()
  975.     else:
  976.         builder = ExpatBuilder()
  977.     return builder.parseString(string)
  978.  
  979.  
  980. def parseFragment(file, context, namespaces = 1):
  981.     """Parse a fragment of a document, given the context from which it
  982.     was originally extracted.  context should be the parent of the
  983.     node(s) which are in the fragment.
  984.  
  985.     'file' may be either a file name or an open file object.
  986.     """
  987.     if namespaces:
  988.         builder = FragmentBuilderNS(context)
  989.     else:
  990.         builder = FragmentBuilder(context)
  991.     if isinstance(file, StringTypes):
  992.         fp = open(file, 'rb')
  993.         
  994.         try:
  995.             result = builder.parseFile(fp)
  996.         finally:
  997.             fp.close()
  998.  
  999.     else:
  1000.         result = builder.parseFile(file)
  1001.     return result
  1002.  
  1003.  
  1004. def parseFragmentString(string, context, namespaces = 1):
  1005.     '''Parse a fragment of a document from a string, given the context
  1006.     from which it was originally extracted.  context should be the
  1007.     parent of the node(s) which are in the fragment.
  1008.     '''
  1009.     if namespaces:
  1010.         builder = FragmentBuilderNS(context)
  1011.     else:
  1012.         builder = FragmentBuilder(context)
  1013.     return builder.parseString(string)
  1014.  
  1015.  
  1016. def makeBuilder(options):
  1017.     '''Create a builder based on an Options object.'''
  1018.     if options.namespaces:
  1019.         return ExpatBuilderNS(options)
  1020.     else:
  1021.         return ExpatBuilder(options)
  1022.  
  1023.