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.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2003-12-30  |  45KB  |  1,004 lines

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