home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 January / maximum-cd-2011-01.iso / DiscContents / calibre-0.7.26.msi / file_706 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-10-31  |  48.9 KB  |  1,615 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyc (Python 2.6)
  3.  
  4. from __future__ import generators
  5. __author__ = 'Leonard Richardson (leonardr@segfault.org)'
  6. __version__ = '3.0.8.1'
  7. __copyright__ = 'Copyright (c) 2004-2010 Leonard Richardson'
  8. __license__ = 'New-style BSD'
  9. from sgmllib import SGMLParser, SGMLParseError
  10. import codecs
  11. import markupbase
  12. import types
  13. import re
  14. import sgmllib
  15.  
  16. try:
  17.     from htmlentitydefs import name2codepoint
  18. except ImportError:
  19.     name2codepoint = { }
  20.  
  21.  
  22. try:
  23.     set
  24. except NameError:
  25.     from sets import Set as set
  26.  
  27. sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*')
  28. markupbase._declname_match = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*\\s*').match
  29. DEFAULT_OUTPUT_ENCODING = 'utf-8'
  30.  
  31. def _match_css_class(str):
  32.     return re.compile('(^|.*\\s)%s($|\\s)' % str)
  33.  
  34.  
  35. class PageElement(object):
  36.     
  37.     def setup(self, parent = None, previous = None):
  38.         self.parent = parent
  39.         self.previous = previous
  40.         self.next = None
  41.         self.previousSibling = None
  42.         self.nextSibling = None
  43.         if self.parent and self.parent.contents:
  44.             self.previousSibling = self.parent.contents[-1]
  45.             self.previousSibling.nextSibling = self
  46.         
  47.  
  48.     
  49.     def replaceWith(self, replaceWith):
  50.         oldParent = self.parent
  51.         myIndex = self.parent.index(self)
  52.         if hasattr(replaceWith, 'parent') and replaceWith.parent is self.parent:
  53.             index = replaceWith.parent.index(replaceWith)
  54.             if index and index < myIndex:
  55.                 myIndex = myIndex - 1
  56.             
  57.         
  58.         self.extract()
  59.         oldParent.insert(myIndex, replaceWith)
  60.  
  61.     
  62.     def replaceWithChildren(self):
  63.         myParent = self.parent
  64.         myIndex = self.parent.index(self)
  65.         self.extract()
  66.         reversedChildren = list(self.contents)
  67.         reversedChildren.reverse()
  68.         for child in reversedChildren:
  69.             myParent.insert(myIndex, child)
  70.         
  71.  
  72.     
  73.     def extract(self):
  74.         if self.parent:
  75.             
  76.             try:
  77.                 del self.parent.contents[self.parent.index(self)]
  78.             except ValueError:
  79.                 pass
  80.             except:
  81.                 None<EXCEPTION MATCH>ValueError
  82.             
  83.  
  84.         None<EXCEPTION MATCH>ValueError
  85.         lastChild = self._lastRecursiveChild()
  86.         nextElement = lastChild.next
  87.         if self.previous:
  88.             self.previous.next = nextElement
  89.         
  90.         if nextElement:
  91.             nextElement.previous = self.previous
  92.         
  93.         self.previous = None
  94.         lastChild.next = None
  95.         self.parent = None
  96.         if self.previousSibling:
  97.             self.previousSibling.nextSibling = self.nextSibling
  98.         
  99.         if self.nextSibling:
  100.             self.nextSibling.previousSibling = self.previousSibling
  101.         
  102.         self.previousSibling = None
  103.         self.nextSibling = None
  104.         return self
  105.  
  106.     
  107.     def _lastRecursiveChild(self):
  108.         lastChild = self
  109.         while hasattr(lastChild, 'contents') and lastChild.contents:
  110.             lastChild = lastChild.contents[-1]
  111.         return lastChild
  112.  
  113.     
  114.     def insert(self, position, newChild):
  115.         if isinstance(newChild, basestring) and not isinstance(newChild, NavigableString):
  116.             newChild = NavigableString(newChild)
  117.         
  118.         position = min(position, len(self.contents))
  119.         if hasattr(newChild, 'parent') and newChild.parent is not None:
  120.             if newChild.parent is self:
  121.                 index = self.index(newChild)
  122.                 if index > position:
  123.                     position = position - 1
  124.                 
  125.             
  126.             newChild.extract()
  127.         
  128.         newChild.parent = self
  129.         previousChild = None
  130.         if position == 0:
  131.             newChild.previousSibling = None
  132.             newChild.previous = self
  133.         else:
  134.             previousChild = self.contents[position - 1]
  135.             newChild.previousSibling = previousChild
  136.             newChild.previousSibling.nextSibling = newChild
  137.             newChild.previous = previousChild._lastRecursiveChild()
  138.         if newChild.previous:
  139.             newChild.previous.next = newChild
  140.         
  141.         newChildsLastElement = newChild._lastRecursiveChild()
  142.         if position >= len(self.contents):
  143.             newChild.nextSibling = None
  144.             parent = self
  145.             parentsNextSibling = None
  146.             while not parentsNextSibling:
  147.                 parentsNextSibling = parent.nextSibling
  148.                 parent = parent.parent
  149.                 if not parent:
  150.                     break
  151.                     continue
  152.             if parentsNextSibling:
  153.                 newChildsLastElement.next = parentsNextSibling
  154.             else:
  155.                 newChildsLastElement.next = None
  156.         else:
  157.             nextChild = self.contents[position]
  158.             newChild.nextSibling = nextChild
  159.             if newChild.nextSibling:
  160.                 newChild.nextSibling.previousSibling = newChild
  161.             
  162.             newChildsLastElement.next = nextChild
  163.         if newChildsLastElement.next:
  164.             newChildsLastElement.next.previous = newChildsLastElement
  165.         
  166.         self.contents.insert(position, newChild)
  167.  
  168.     
  169.     def append(self, tag):
  170.         self.insert(len(self.contents), tag)
  171.  
  172.     
  173.     def findNext(self, name = None, attrs = { }, text = None, **kwargs):
  174.         return self._findOne(self.findAllNext, name, attrs, text, **kwargs)
  175.  
  176.     
  177.     def findAllNext(self, name = None, attrs = { }, text = None, limit = None, **kwargs):
  178.         return self._findAll(name, attrs, text, limit, self.nextGenerator, **kwargs)
  179.  
  180.     
  181.     def findNextSibling(self, name = None, attrs = { }, text = None, **kwargs):
  182.         return self._findOne(self.findNextSiblings, name, attrs, text, **kwargs)
  183.  
  184.     
  185.     def findNextSiblings(self, name = None, attrs = { }, text = None, limit = None, **kwargs):
  186.         return self._findAll(name, attrs, text, limit, self.nextSiblingGenerator, **kwargs)
  187.  
  188.     fetchNextSiblings = findNextSiblings
  189.     
  190.     def findPrevious(self, name = None, attrs = { }, text = None, **kwargs):
  191.         return self._findOne(self.findAllPrevious, name, attrs, text, **kwargs)
  192.  
  193.     
  194.     def findAllPrevious(self, name = None, attrs = { }, text = None, limit = None, **kwargs):
  195.         return self._findAll(name, attrs, text, limit, self.previousGenerator, **kwargs)
  196.  
  197.     fetchPrevious = findAllPrevious
  198.     
  199.     def findPreviousSibling(self, name = None, attrs = { }, text = None, **kwargs):
  200.         return self._findOne(self.findPreviousSiblings, name, attrs, text, **kwargs)
  201.  
  202.     
  203.     def findPreviousSiblings(self, name = None, attrs = { }, text = None, limit = None, **kwargs):
  204.         return self._findAll(name, attrs, text, limit, self.previousSiblingGenerator, **kwargs)
  205.  
  206.     fetchPreviousSiblings = findPreviousSiblings
  207.     
  208.     def findParent(self, name = None, attrs = { }, **kwargs):
  209.         r = None
  210.         l = self.findParents(name, attrs, 1)
  211.         if l:
  212.             r = l[0]
  213.         
  214.         return r
  215.  
  216.     
  217.     def findParents(self, name = None, attrs = { }, limit = None, **kwargs):
  218.         return self._findAll(name, attrs, None, limit, self.parentGenerator, **kwargs)
  219.  
  220.     fetchParents = findParents
  221.     
  222.     def _findOne(self, method, name, attrs, text, **kwargs):
  223.         r = None
  224.         l = method(name, attrs, text, 1, **kwargs)
  225.         if l:
  226.             r = l[0]
  227.         
  228.         return r
  229.  
  230.     
  231.     def _findAll(self, name, attrs, text, limit, generator, **kwargs):
  232.         if isinstance(name, SoupStrainer):
  233.             strainer = name
  234.         elif text is None and not limit and not attrs and not kwargs:
  235.             if name is True:
  236.                 return _[1]
  237.             if isinstance(name, basestring):
  238.                 return _[2]
  239.             strainer = SoupStrainer(name, attrs, text, **kwargs)
  240.         else:
  241.             strainer = SoupStrainer(name, attrs, text, **kwargs)
  242.         results = ResultSet(strainer)
  243.         g = generator()
  244.         while True:
  245.             
  246.             try:
  247.                 i = g.next()
  248.             except StopIteration:
  249.                 name is True
  250.                 name is True
  251.                 break
  252.             except:
  253.                 name is True
  254.  
  255.             if i:
  256.                 found = strainer.search(i)
  257.                 if found:
  258.                     results.append(found)
  259.                     if limit and len(results) >= limit:
  260.                         break
  261.                     
  262.                 
  263.             found
  264.             continue
  265.             name is True
  266.         return results
  267.  
  268.     
  269.     def nextGenerator(self):
  270.         i = self
  271.         while i is not None:
  272.             i = i.next
  273.             yield i
  274.  
  275.     
  276.     def nextSiblingGenerator(self):
  277.         i = self
  278.         while i is not None:
  279.             i = i.nextSibling
  280.             yield i
  281.  
  282.     
  283.     def previousGenerator(self):
  284.         i = self
  285.         while i is not None:
  286.             i = i.previous
  287.             yield i
  288.  
  289.     
  290.     def previousSiblingGenerator(self):
  291.         i = self
  292.         while i is not None:
  293.             i = i.previousSibling
  294.             yield i
  295.  
  296.     
  297.     def parentGenerator(self):
  298.         i = self
  299.         while i is not None:
  300.             i = i.parent
  301.             yield i
  302.  
  303.     
  304.     def substituteEncoding(self, str, encoding = None):
  305.         if not encoding:
  306.             pass
  307.         encoding = 'utf-8'
  308.         return str.replace('%SOUP-ENCODING%', encoding)
  309.  
  310.     
  311.     def toEncoding(self, s, encoding = None):
  312.         if isinstance(s, unicode):
  313.             if encoding:
  314.                 s = s.encode(encoding)
  315.             
  316.         elif isinstance(s, str):
  317.             if encoding:
  318.                 s = s.encode(encoding)
  319.             else:
  320.                 s = unicode(s)
  321.         elif encoding:
  322.             s = self.toEncoding(str(s), encoding)
  323.         else:
  324.             s = unicode(s)
  325.         return s
  326.  
  327.  
  328.  
  329. class NavigableString(unicode, PageElement):
  330.     
  331.     def __new__(cls, value):
  332.         if isinstance(value, unicode):
  333.             return unicode.__new__(cls, value)
  334.         return unicode.__new__(cls, value, DEFAULT_OUTPUT_ENCODING)
  335.  
  336.     
  337.     def __getnewargs__(self):
  338.         return (NavigableString.__str__(self),)
  339.  
  340.     
  341.     def __getattr__(self, attr):
  342.         if attr == 'string':
  343.             return self
  344.         raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__.__name__, attr)
  345.  
  346.     
  347.     def __unicode__(self):
  348.         return str(self).decode(DEFAULT_OUTPUT_ENCODING)
  349.  
  350.     
  351.     def __str__(self, encoding = DEFAULT_OUTPUT_ENCODING):
  352.         if encoding:
  353.             return self.encode(encoding)
  354.         return self
  355.  
  356.  
  357.  
  358. class CData(NavigableString):
  359.     
  360.     def __str__(self, encoding = DEFAULT_OUTPUT_ENCODING):
  361.         return '<![CDATA[%s]]>' % NavigableString.__str__(self, encoding)
  362.  
  363.  
  364.  
  365. class ProcessingInstruction(NavigableString):
  366.     
  367.     def __str__(self, encoding = DEFAULT_OUTPUT_ENCODING):
  368.         output = self
  369.         if '%SOUP-ENCODING%' in output:
  370.             output = self.substituteEncoding(output, encoding)
  371.         
  372.         return '<?%s?>' % self.toEncoding(output, encoding)
  373.  
  374.  
  375.  
  376. class Comment(NavigableString):
  377.     
  378.     def __str__(self, encoding = DEFAULT_OUTPUT_ENCODING):
  379.         return '<!--%s-->' % NavigableString.__str__(self, encoding)
  380.  
  381.  
  382.  
  383. class Declaration(NavigableString):
  384.     
  385.     def __str__(self, encoding = DEFAULT_OUTPUT_ENCODING):
  386.         return '<!%s>' % NavigableString.__str__(self, encoding)
  387.  
  388.  
  389.  
  390. class Tag(PageElement):
  391.     
  392.     def _invert(h):
  393.         i = { }
  394.         for k, v in h.items():
  395.             i[v] = k
  396.         
  397.         return i
  398.  
  399.     XML_ENTITIES_TO_SPECIAL_CHARS = {
  400.         'apos': "'",
  401.         'quot': '"',
  402.         'amp': '&',
  403.         'lt': '<',
  404.         'gt': '>' }
  405.     XML_SPECIAL_CHARS_TO_ENTITIES = _invert(XML_ENTITIES_TO_SPECIAL_CHARS)
  406.     
  407.     def _convertEntities(self, match):
  408.         x = match.group(1)
  409.         if self.convertHTMLEntities and x in name2codepoint:
  410.             return unichr(name2codepoint[x])
  411.         if x in self.XML_ENTITIES_TO_SPECIAL_CHARS:
  412.             if self.convertXMLEntities:
  413.                 return self.XML_ENTITIES_TO_SPECIAL_CHARS[x]
  414.             return u'&%s;' % x
  415.         x in self.XML_ENTITIES_TO_SPECIAL_CHARS
  416.         if len(x) > 0 and x[0] == '#':
  417.             if len(x) > 1 and x[1] == 'x':
  418.                 return unichr(int(x[2:], 16))
  419.             return unichr(int(x[1:]))
  420.         x[0] == '#'
  421.         if self.escapeUnrecognizedEntities:
  422.             return u'&%s;' % x
  423.         return u'&%s;' % x
  424.  
  425.     
  426.     def __init__(self, parser, name, attrs = None, parent = None, previous = None):
  427.         self.parserClass = parser.__class__
  428.         self.isSelfClosing = parser.isSelfClosingTag(name)
  429.         self.name = name
  430.         if attrs is None:
  431.             attrs = []
  432.         
  433.         self.attrs = attrs
  434.         self.contents = []
  435.         self.setup(parent, previous)
  436.         self.hidden = False
  437.         self.containsSubstitutions = False
  438.         self.convertHTMLEntities = parser.convertHTMLEntities
  439.         self.convertXMLEntities = parser.convertXMLEntities
  440.         self.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities
  441.         
  442.         convert = lambda .0: (k, val) = .0(k, re.sub('&(#\\d+|#x[0-9a-fA-F]+|\\w+);', self._convertEntities, val))
  443.         self.attrs = map(convert, self.attrs)
  444.  
  445.     
  446.     def getString(self):
  447.         if len(self.contents) == 1 and isinstance(self.contents[0], NavigableString):
  448.             return self.contents[0]
  449.  
  450.     
  451.     def setString(self, string):
  452.         self.clear()
  453.         self.append(string)
  454.  
  455.     string = property(getString, setString)
  456.     
  457.     def getText(self, separator = u''):
  458.         if not len(self.contents):
  459.             return u''
  460.         stopNode = self._lastRecursiveChild().next
  461.         strings = []
  462.         current = self.contents[0]
  463.         while current is not stopNode:
  464.             if isinstance(current, NavigableString):
  465.                 strings.append(current.strip())
  466.             
  467.             current = current.next
  468.         return separator.join(strings)
  469.  
  470.     text = property(getText)
  471.     
  472.     def get(self, key, default = None):
  473.         return self._getAttrMap().get(key, default)
  474.  
  475.     
  476.     def clear(self):
  477.         for child in self.contents[:]:
  478.             child.extract()
  479.         
  480.  
  481.     
  482.     def index(self, element):
  483.         for i, child in enumerate(self.contents):
  484.             if child is element:
  485.                 return i
  486.         
  487.         raise ValueError('Tag.index: element not in tag')
  488.  
  489.     
  490.     def has_key(self, key):
  491.         return self._getAttrMap().has_key(key)
  492.  
  493.     
  494.     def __getitem__(self, key):
  495.         return self._getAttrMap()[key]
  496.  
  497.     
  498.     def __iter__(self):
  499.         return iter(self.contents)
  500.  
  501.     
  502.     def __len__(self):
  503.         return len(self.contents)
  504.  
  505.     
  506.     def __contains__(self, x):
  507.         return x in self.contents
  508.  
  509.     
  510.     def __nonzero__(self):
  511.         return True
  512.  
  513.     
  514.     def __setitem__(self, key, value):
  515.         self._getAttrMap()
  516.         self.attrMap[key] = value
  517.         found = False
  518.         for i in range(0, len(self.attrs)):
  519.             if self.attrs[i][0] == key:
  520.                 self.attrs[i] = (key, value)
  521.                 found = True
  522.                 continue
  523.         
  524.         if not found:
  525.             self.attrs.append((key, value))
  526.         
  527.         self._getAttrMap()[key] = value
  528.  
  529.     
  530.     def __delitem__(self, key):
  531.         for item in self.attrs:
  532.             if item[0] == key:
  533.                 self.attrs.remove(item)
  534.             
  535.             self._getAttrMap()
  536.             if self.attrMap.has_key(key):
  537.                 del self.attrMap[key]
  538.                 continue
  539.         
  540.  
  541.     
  542.     def __call__(self, *args, **kwargs):
  543.         return apply(self.findAll, args, kwargs)
  544.  
  545.     
  546.     def __getattr__(self, tag):
  547.         if len(tag) > 3 and tag.rfind('Tag') == len(tag) - 3:
  548.             return self.find(tag[:-3])
  549.         if tag.find('__') != 0:
  550.             return self.find(tag)
  551.         raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__, tag)
  552.  
  553.     
  554.     def __eq__(self, other):
  555.         if other is self:
  556.             return True
  557.         if not hasattr(other, 'name') and not hasattr(other, 'attrs') and not hasattr(other, 'contents') and self.name != other.name and self.attrs != other.attrs or len(self) != len(other):
  558.             return False
  559.         for i in range(0, len(self.contents)):
  560.             if self.contents[i] != other.contents[i]:
  561.                 return False
  562.         
  563.         return True
  564.  
  565.     
  566.     def __ne__(self, other):
  567.         return not (self == other)
  568.  
  569.     
  570.     def __repr__(self, encoding = DEFAULT_OUTPUT_ENCODING):
  571.         return self.__str__(encoding)
  572.  
  573.     
  574.     def __unicode__(self):
  575.         return self.__str__(None)
  576.  
  577.     BARE_AMPERSAND_OR_BRACKET = re.compile('([<>]|' + '&(?!#\\d+;|#x[0-9a-fA-F]+;|\\w+;)' + ')')
  578.     
  579.     def _sub_entity(self, x):
  580.         return '&' + self.XML_SPECIAL_CHARS_TO_ENTITIES[x.group(0)[0]] + ';'
  581.  
  582.     
  583.     def __str__(self, encoding = DEFAULT_OUTPUT_ENCODING, prettyPrint = False, indentLevel = 0):
  584.         encodedName = self.toEncoding(self.name, encoding)
  585.         attrs = []
  586.         if self.attrs:
  587.             for key, val in self.attrs:
  588.                 fmt = '%s="%s"'
  589.                 if isinstance(val, basestring):
  590.                     if self.containsSubstitutions and '%SOUP-ENCODING%' in val:
  591.                         val = self.substituteEncoding(val, encoding)
  592.                     
  593.                     if '"' in val:
  594.                         fmt = "%s='%s'"
  595.                         if "'" in val:
  596.                             val = val.replace("'", '&squot;')
  597.                         
  598.                     
  599.                     val = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, val)
  600.                 
  601.                 attrs.append(fmt % (self.toEncoding(key, encoding), self.toEncoding(val, encoding)))
  602.             
  603.         
  604.         close = ''
  605.         closeTag = ''
  606.         if self.isSelfClosing:
  607.             close = ' /'
  608.         else:
  609.             closeTag = '</%s>' % encodedName
  610.         (indentTag, indentContents) = (0, 0)
  611.         if prettyPrint:
  612.             indentTag = indentLevel
  613.             space = ' ' * (indentTag - 1)
  614.             indentContents = indentTag + 1
  615.         
  616.         contents = self.renderContents(encoding, prettyPrint, indentContents)
  617.         if self.hidden:
  618.             s = contents
  619.         else:
  620.             s = []
  621.             attributeString = ''
  622.             if attrs:
  623.                 attributeString = ' ' + ' '.join(attrs)
  624.             
  625.             if prettyPrint:
  626.                 s.append(space)
  627.             
  628.             s.append('<%s%s%s>' % (encodedName, attributeString, close))
  629.             if prettyPrint:
  630.                 s.append('\n')
  631.             
  632.             s.append(contents)
  633.             if prettyPrint and contents and contents[-1] != '\n':
  634.                 s.append('\n')
  635.             
  636.             if prettyPrint and closeTag:
  637.                 s.append(space)
  638.             
  639.             s.append(closeTag)
  640.             if prettyPrint and closeTag and self.nextSibling:
  641.                 s.append('\n')
  642.             
  643.             s = ''.join(s)
  644.         return s
  645.  
  646.     
  647.     def decompose(self):
  648.         self.extract()
  649.         if len(self.contents) == 0:
  650.             return None
  651.         current = self.contents[0]
  652.         while current is not None:
  653.             next = current.next
  654.             if isinstance(current, Tag):
  655.                 del current.contents[:]
  656.             
  657.             current.parent = None
  658.             current.previous = None
  659.             current.previousSibling = None
  660.             current.next = None
  661.             current.nextSibling = None
  662.             current = next
  663.  
  664.     
  665.     def prettify(self, encoding = DEFAULT_OUTPUT_ENCODING):
  666.         return self.__str__(encoding, True)
  667.  
  668.     
  669.     def renderContents(self, encoding = DEFAULT_OUTPUT_ENCODING, prettyPrint = False, indentLevel = 0):
  670.         s = []
  671.         for c in self:
  672.             text = None
  673.             if isinstance(c, NavigableString):
  674.                 text = c.__str__(encoding)
  675.             elif isinstance(c, Tag):
  676.                 s.append(c.__str__(encoding, prettyPrint, indentLevel))
  677.             
  678.             if text and prettyPrint:
  679.                 text = text.strip()
  680.             
  681.             if text:
  682.                 if prettyPrint:
  683.                     s.append(' ' * (indentLevel - 1))
  684.                 
  685.                 s.append(text)
  686.                 if prettyPrint:
  687.                     s.append('\n')
  688.                 
  689.             prettyPrint
  690.         
  691.         return ''.join(s)
  692.  
  693.     
  694.     def find(self, name = None, attrs = { }, recursive = True, text = None, **kwargs):
  695.         r = None
  696.         l = self.findAll(name, attrs, recursive, text, 1, **kwargs)
  697.         if l:
  698.             r = l[0]
  699.         
  700.         return r
  701.  
  702.     findChild = find
  703.     
  704.     def findAll(self, name = None, attrs = { }, recursive = True, text = None, limit = None, **kwargs):
  705.         generator = self.recursiveChildGenerator
  706.         if not recursive:
  707.             generator = self.childGenerator
  708.         
  709.         return self._findAll(name, attrs, text, limit, generator, **kwargs)
  710.  
  711.     findChildren = findAll
  712.     first = find
  713.     fetch = findAll
  714.     
  715.     def fetchText(self, text = None, recursive = True, limit = None):
  716.         return self.findAll(text = text, recursive = recursive, limit = limit)
  717.  
  718.     
  719.     def firstText(self, text = None, recursive = True):
  720.         return self.find(text = text, recursive = recursive)
  721.  
  722.     
  723.     def _getAttrMap(self):
  724.         if not getattr(self, 'attrMap'):
  725.             self.attrMap = { }
  726.             for key, value in self.attrs:
  727.                 self.attrMap[key] = value
  728.             
  729.         
  730.         return self.attrMap
  731.  
  732.     
  733.     def childGenerator(self):
  734.         return iter(self.contents)
  735.  
  736.     
  737.     def recursiveChildGenerator(self):
  738.         if not len(self.contents):
  739.             raise StopIteration
  740.         len(self.contents)
  741.         stopNode = self._lastRecursiveChild().next
  742.         current = self.contents[0]
  743.         while current is not stopNode:
  744.             yield current
  745.             current = current.next
  746.  
  747.  
  748.  
  749. class SoupStrainer:
  750.     
  751.     def __init__(self, name = None, attrs = { }, text = None, **kwargs):
  752.         self.name = name
  753.         if isinstance(attrs, basestring):
  754.             kwargs['class'] = _match_css_class(attrs)
  755.             attrs = None
  756.         
  757.         if kwargs:
  758.             if attrs:
  759.                 attrs = attrs.copy()
  760.                 attrs.update(kwargs)
  761.             else:
  762.                 attrs = kwargs
  763.         
  764.         self.attrs = attrs
  765.         self.text = text
  766.  
  767.     
  768.     def __str__(self):
  769.         if self.text:
  770.             return self.text
  771.         return '%s|%s' % (self.name, self.attrs)
  772.  
  773.     
  774.     def searchTag(self, markupName = None, markupAttrs = { }):
  775.         found = None
  776.         markup = None
  777.         if isinstance(markupName, Tag):
  778.             markup = markupName
  779.             markupAttrs = markup
  780.         
  781.         if callable(self.name):
  782.             pass
  783.         callFunctionWithTagData = not isinstance(markupName, Tag)
  784.         if not not (self.name) and callFunctionWithTagData:
  785.             if (markup or self._matches(markup, self.name) or not markup) and self._matches(markupName, self.name):
  786.                 if callFunctionWithTagData:
  787.                     match = self.name(markupName, markupAttrs)
  788.                 else:
  789.                     match = True
  790.                     markupAttrMap = None
  791.                     for attr, matchAgainst in self.attrs.items():
  792.                         if not markupAttrMap:
  793.                             if hasattr(markupAttrs, 'get'):
  794.                                 markupAttrMap = markupAttrs
  795.                             else:
  796.                                 markupAttrMap = { }
  797.                                 for k, v in markupAttrs:
  798.                                     markupAttrMap[k] = v
  799.                                 
  800.                         
  801.                         attrValue = markupAttrMap.get(attr)
  802.                         if not self._matches(attrValue, matchAgainst):
  803.                             match = False
  804.                             break
  805.                             continue
  806.                     
  807.                 if match:
  808.                     if markup:
  809.                         found = markup
  810.                     else:
  811.                         found = markupName
  812.                 
  813.             
  814.         return found
  815.  
  816.     
  817.     def search(self, markup):
  818.         found = None
  819.         if hasattr(markup, '__iter__') and not isinstance(markup, Tag):
  820.             for element in markup:
  821.                 if isinstance(element, NavigableString) and self.search(element):
  822.                     found = element
  823.                     break
  824.                     continue
  825.             
  826.         elif isinstance(markup, Tag):
  827.             if not self.text:
  828.                 found = self.searchTag(markup)
  829.             
  830.         elif isinstance(markup, NavigableString) or isinstance(markup, basestring):
  831.             if self._matches(markup, self.text):
  832.                 found = markup
  833.             
  834.         else:
  835.             raise Exception, "I don't know how to match against a %s" % markup.__class__
  836.         return isinstance(markup, basestring)
  837.  
  838.     
  839.     def _matches(self, markup, matchAgainst):
  840.         result = False
  841.         if matchAgainst is True:
  842.             result = markup is not None
  843.         elif callable(matchAgainst):
  844.             result = matchAgainst(markup)
  845.         elif isinstance(markup, Tag):
  846.             markup = markup.name
  847.         
  848.         if markup and not isinstance(markup, basestring):
  849.             markup = unicode(markup)
  850.         
  851.         if hasattr(matchAgainst, 'match'):
  852.             if markup:
  853.                 pass
  854.             result = matchAgainst.search(markup)
  855.         elif hasattr(matchAgainst, '__iter__'):
  856.             result = markup in matchAgainst
  857.         elif hasattr(matchAgainst, 'items'):
  858.             result = markup.has_key(matchAgainst)
  859.         elif matchAgainst and isinstance(markup, basestring):
  860.             if isinstance(markup, unicode):
  861.                 matchAgainst = unicode(matchAgainst)
  862.             else:
  863.                 matchAgainst = str(matchAgainst)
  864.         
  865.         if not result:
  866.             result = matchAgainst == markup
  867.         
  868.         return result
  869.  
  870.  
  871.  
  872. class ResultSet(list):
  873.     
  874.     def __init__(self, source):
  875.         list.__init__([])
  876.         self.source = source
  877.  
  878.  
  879.  
  880. def buildTagMap(default, *args):
  881.     built = { }
  882.     for portion in args:
  883.         if hasattr(portion, 'items'):
  884.             for k, v in portion.items():
  885.                 built[k] = v
  886.             
  887.         if hasattr(portion, '__iter__'):
  888.             for k in portion:
  889.                 built[k] = default
  890.             
  891.         built[portion] = default
  892.     
  893.     return built
  894.  
  895.  
  896. class BeautifulStoneSoup(Tag, SGMLParser):
  897.     SELF_CLOSING_TAGS = { }
  898.     NESTABLE_TAGS = { }
  899.     RESET_NESTING_TAGS = { }
  900.     QUOTE_TAGS = { }
  901.     PRESERVE_WHITESPACE_TAGS = []
  902.     MARKUP_MASSAGE = [
  903.         (re.compile('(<[^<>]*)/>'), (lambda x: x.group(1) + ' />')),
  904.         (re.compile('<!\\s+([^<>]*)>'), (lambda x: '<!' + x.group(1) + '>'))]
  905.     ROOT_TAG_NAME = u'[document]'
  906.     HTML_ENTITIES = 'html'
  907.     XML_ENTITIES = 'xml'
  908.     XHTML_ENTITIES = 'xhtml'
  909.     ALL_ENTITIES = XHTML_ENTITIES
  910.     STRIP_ASCII_SPACES = {
  911.         9: None,
  912.         10: None,
  913.         12: None,
  914.         13: None,
  915.         32: None }
  916.     
  917.     def __init__(self, markup = '', parseOnlyThese = None, fromEncoding = None, markupMassage = True, smartQuotesTo = XML_ENTITIES, convertEntities = None, selfClosingTags = None, isHTML = False):
  918.         self.parseOnlyThese = parseOnlyThese
  919.         self.fromEncoding = fromEncoding
  920.         self.smartQuotesTo = smartQuotesTo
  921.         self.convertEntities = convertEntities
  922.         if self.convertEntities:
  923.             self.smartQuotesTo = None
  924.             if convertEntities == self.HTML_ENTITIES:
  925.                 self.convertXMLEntities = False
  926.                 self.convertHTMLEntities = True
  927.                 self.escapeUnrecognizedEntities = True
  928.             elif convertEntities == self.XHTML_ENTITIES:
  929.                 self.convertXMLEntities = True
  930.                 self.convertHTMLEntities = True
  931.                 self.escapeUnrecognizedEntities = False
  932.             elif convertEntities == self.XML_ENTITIES:
  933.                 self.convertXMLEntities = True
  934.                 self.convertHTMLEntities = False
  935.                 self.escapeUnrecognizedEntities = False
  936.             
  937.         else:
  938.             self.convertXMLEntities = False
  939.             self.convertHTMLEntities = False
  940.             self.escapeUnrecognizedEntities = False
  941.         self.instanceSelfClosingTags = buildTagMap(None, selfClosingTags)
  942.         SGMLParser.__init__(self)
  943.         if hasattr(markup, 'read'):
  944.             markup = markup.read()
  945.         
  946.         self.markup = markup
  947.         self.markupMassage = markupMassage
  948.         
  949.         try:
  950.             self._feed(isHTML = isHTML)
  951.         except StopParsing:
  952.             pass
  953.  
  954.         self.markup = None
  955.  
  956.     
  957.     def convert_charref(self, name):
  958.         
  959.         try:
  960.             n = int(name)
  961.         except ValueError:
  962.             return None
  963.  
  964.         if n <= n:
  965.             pass
  966.         elif not n <= 127:
  967.             return None
  968.         return self.convert_codepoint(n)
  969.  
  970.     
  971.     def _feed(self, inDocumentEncoding = None, isHTML = False):
  972.         markup = self.markup
  973.         if isinstance(markup, unicode):
  974.             if not hasattr(self, 'originalEncoding'):
  975.                 self.originalEncoding = None
  976.             
  977.         else:
  978.             dammit = UnicodeDammit(markup, [
  979.                 self.fromEncoding,
  980.                 inDocumentEncoding], smartQuotesTo = self.smartQuotesTo, isHTML = isHTML)
  981.             markup = dammit.unicode
  982.             self.originalEncoding = dammit.originalEncoding
  983.             self.declaredHTMLEncoding = dammit.declaredHTMLEncoding
  984.         if markup:
  985.             if self.markupMassage:
  986.                 if not hasattr(self.markupMassage, '__iter__'):
  987.                     self.markupMassage = self.MARKUP_MASSAGE
  988.                 
  989.                 for fix, m in self.markupMassage:
  990.                     markup = fix.sub(m, markup)
  991.                 
  992.                 del self.markupMassage
  993.             
  994.         
  995.         self.reset()
  996.         SGMLParser.feed(self, markup)
  997.         self.endData()
  998.         while self.currentTag.name != self.ROOT_TAG_NAME:
  999.             self.popTag()
  1000.  
  1001.     
  1002.     def __getattr__(self, methodName):
  1003.         if methodName.startswith('start_') and methodName.startswith('end_') or methodName.startswith('do_'):
  1004.             return SGMLParser.__getattr__(self, methodName)
  1005.         if not methodName.startswith('__'):
  1006.             return Tag.__getattr__(self, methodName)
  1007.         raise AttributeError
  1008.  
  1009.     
  1010.     def isSelfClosingTag(self, name):
  1011.         if not self.SELF_CLOSING_TAGS.has_key(name):
  1012.             pass
  1013.         return self.instanceSelfClosingTags.has_key(name)
  1014.  
  1015.     
  1016.     def reset(self):
  1017.         Tag.__init__(self, self, self.ROOT_TAG_NAME)
  1018.         self.hidden = 1
  1019.         SGMLParser.reset(self)
  1020.         self.currentData = []
  1021.         self.currentTag = None
  1022.         self.tagStack = []
  1023.         self.quoteStack = []
  1024.         self.pushTag(self)
  1025.  
  1026.     
  1027.     def popTag(self):
  1028.         tag = self.tagStack.pop()
  1029.         if self.tagStack:
  1030.             self.currentTag = self.tagStack[-1]
  1031.         
  1032.         return self.currentTag
  1033.  
  1034.     
  1035.     def pushTag(self, tag):
  1036.         if self.currentTag:
  1037.             self.currentTag.contents.append(tag)
  1038.         
  1039.         self.tagStack.append(tag)
  1040.         self.currentTag = self.tagStack[-1]
  1041.  
  1042.     
  1043.     def endData(self, containerClass = NavigableString):
  1044.         if self.currentData:
  1045.             currentData = u''.join(self.currentData)
  1046.             self.currentData = []
  1047.             if self.parseOnlyThese and len(self.tagStack) <= 1:
  1048.                 if not (self.parseOnlyThese.text) or not self.parseOnlyThese.search(currentData):
  1049.                     return None
  1050.                 o = containerClass(currentData)
  1051.                 o.setup(self.currentTag, self.previous)
  1052.             self.previous = o
  1053.             self.currentTag.contents.append(o)
  1054.         
  1055.  
  1056.     
  1057.     def _popToTag(self, name, inclusivePop = True):
  1058.         if name == self.ROOT_TAG_NAME:
  1059.             return None
  1060.         numPops = 0
  1061.         mostRecentTag = None
  1062.         for i in range(len(self.tagStack) - 1, 0, -1):
  1063.             if name == self.tagStack[i].name:
  1064.                 numPops = len(self.tagStack) - i
  1065.                 break
  1066.                 continue
  1067.             name == self.ROOT_TAG_NAME
  1068.         
  1069.         if not inclusivePop:
  1070.             numPops = numPops - 1
  1071.         
  1072.         for i in range(0, numPops):
  1073.             mostRecentTag = self.popTag()
  1074.         
  1075.         return mostRecentTag
  1076.  
  1077.     
  1078.     def _smartPop(self, name):
  1079.         nestingResetTriggers = self.NESTABLE_TAGS.get(name)
  1080.         isNestable = nestingResetTriggers != None
  1081.         isResetNesting = self.RESET_NESTING_TAGS.has_key(name)
  1082.         popTo = None
  1083.         inclusive = True
  1084.         for i in range(len(self.tagStack) - 1, 0, -1):
  1085.             p = self.tagStack[i]
  1086.             if (not p or p.name == name) and not isNestable:
  1087.                 popTo = name
  1088.                 break
  1089.             
  1090.             if (nestingResetTriggers is not None or p.name in nestingResetTriggers or nestingResetTriggers is None) and isResetNesting and self.RESET_NESTING_TAGS.has_key(p.name):
  1091.                 popTo = p.name
  1092.                 inclusive = False
  1093.                 break
  1094.             
  1095.             p = p.parent
  1096.         
  1097.         if popTo:
  1098.             self._popToTag(popTo, inclusive)
  1099.         
  1100.  
  1101.     
  1102.     def unknown_starttag(self, name, attrs, selfClosing = 0):
  1103.         if self.quoteStack:
  1104.             attrs = []([ ' %s="%s"' % (x, y) for x, y in attrs ])
  1105.             self.handle_data('<%s%s>' % (name, attrs))
  1106.             return None
  1107.         self.endData()
  1108.         if not self.isSelfClosingTag(name) and not selfClosing:
  1109.             self._smartPop(name)
  1110.         
  1111.         if self.parseOnlyThese and len(self.tagStack) <= 1:
  1112.             if self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(name, attrs):
  1113.                 return None
  1114.             tag = Tag(self, name, attrs, self.currentTag, self.previous)
  1115.             if self.previous:
  1116.                 self.previous.next = tag
  1117.             
  1118.         self.previous = tag
  1119.         self.pushTag(tag)
  1120.         if selfClosing or self.isSelfClosingTag(name):
  1121.             self.popTag()
  1122.         
  1123.         if name in self.QUOTE_TAGS:
  1124.             self.quoteStack.append(name)
  1125.             self.literal = 1
  1126.         
  1127.         return tag
  1128.  
  1129.     
  1130.     def unknown_endtag(self, name):
  1131.         if self.quoteStack and self.quoteStack[-1] != name:
  1132.             self.handle_data('</%s>' % name)
  1133.             return None
  1134.         self.endData()
  1135.         self._popToTag(name)
  1136.         if self.quoteStack and self.quoteStack[-1] == name:
  1137.             self.quoteStack.pop()
  1138.             self.literal = len(self.quoteStack) > 0
  1139.         
  1140.  
  1141.     
  1142.     def handle_data(self, data):
  1143.         self.currentData.append(data)
  1144.  
  1145.     
  1146.     def _toStringSubclass(self, text, subclass):
  1147.         self.endData()
  1148.         self.handle_data(text)
  1149.         self.endData(subclass)
  1150.  
  1151.     
  1152.     def handle_pi(self, text):
  1153.         if text[:3] == 'xml':
  1154.             text = u"xml version='1.0' encoding='%SOUP-ENCODING%'"
  1155.         
  1156.         self._toStringSubclass(text, ProcessingInstruction)
  1157.  
  1158.     
  1159.     def handle_comment(self, text):
  1160.         self._toStringSubclass(text, Comment)
  1161.  
  1162.     
  1163.     def handle_charref(self, ref):
  1164.         if self.convertEntities:
  1165.             data = unichr(int(ref))
  1166.         else:
  1167.             data = '&#%s;' % ref
  1168.         self.handle_data(data)
  1169.  
  1170.     
  1171.     def handle_entityref(self, ref):
  1172.         data = None
  1173.         if self.convertHTMLEntities:
  1174.             
  1175.             try:
  1176.                 data = unichr(name2codepoint[ref])
  1177.             except KeyError:
  1178.                 pass
  1179.             except:
  1180.                 None<EXCEPTION MATCH>KeyError
  1181.             
  1182.  
  1183.         None<EXCEPTION MATCH>KeyError
  1184.         if not data and self.convertXMLEntities:
  1185.             data = self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref)
  1186.         
  1187.         if not data and self.convertHTMLEntities and not self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref):
  1188.             data = '&%s' % ref
  1189.         
  1190.         if not data:
  1191.             data = '&%s;' % ref
  1192.         
  1193.         self.handle_data(data)
  1194.  
  1195.     
  1196.     def handle_decl(self, data):
  1197.         self._toStringSubclass(data, Declaration)
  1198.  
  1199.     
  1200.     def parse_declaration(self, i):
  1201.         j = None
  1202.         if self.rawdata[i:i + 9] == '<![CDATA[':
  1203.             k = self.rawdata.find(']]>', i)
  1204.             if k == -1:
  1205.                 k = len(self.rawdata)
  1206.             
  1207.             data = self.rawdata[i + 9:k]
  1208.             j = k + 3
  1209.             self._toStringSubclass(data, CData)
  1210.         else:
  1211.             
  1212.             try:
  1213.                 j = SGMLParser.parse_declaration(self, i)
  1214.             except SGMLParseError:
  1215.                 toHandle = self.rawdata[i:]
  1216.                 self.handle_data(toHandle)
  1217.                 j = i + len(toHandle)
  1218.  
  1219.         return j
  1220.  
  1221.  
  1222.  
  1223. class BeautifulSoup(BeautifulStoneSoup):
  1224.     
  1225.     def __init__(self, *args, **kwargs):
  1226.         if not kwargs.has_key('smartQuotesTo'):
  1227.             kwargs['smartQuotesTo'] = self.HTML_ENTITIES
  1228.         
  1229.         kwargs['isHTML'] = True
  1230.         BeautifulStoneSoup.__init__(self, *args, **kwargs)
  1231.  
  1232.     SELF_CLOSING_TAGS = buildTagMap(None, ('br', 'hr', 'input', 'img', 'meta', 'spacer', 'link', 'frame', 'base', 'col'))
  1233.     PRESERVE_WHITESPACE_TAGS = set([
  1234.         'pre',
  1235.         'textarea'])
  1236.     QUOTE_TAGS = {
  1237.         'script': None,
  1238.         'textarea': None }
  1239.     NESTABLE_INLINE_TAGS = ('span', 'font', 'q', 'object', 'bdo', 'sub', 'sup', 'center')
  1240.     NESTABLE_BLOCK_TAGS = ('blockquote', 'div', 'fieldset', 'ins', 'del')
  1241.     NESTABLE_LIST_TAGS = {
  1242.         'ol': [],
  1243.         'ul': [],
  1244.         'li': [
  1245.             'ul',
  1246.             'ol'],
  1247.         'dl': [],
  1248.         'dd': [
  1249.             'dl'],
  1250.         'dt': [
  1251.             'dl'] }
  1252.     NESTABLE_TABLE_TAGS = {
  1253.         'table': [],
  1254.         'tr': [
  1255.             'table',
  1256.             'tbody',
  1257.             'tfoot',
  1258.             'thead'],
  1259.         'td': [
  1260.             'tr'],
  1261.         'th': [
  1262.             'tr'],
  1263.         'thead': [
  1264.             'table'],
  1265.         'tbody': [
  1266.             'table'],
  1267.         'tfoot': [
  1268.             'table'] }
  1269.     NON_NESTABLE_BLOCK_TAGS = ('address', 'form', 'p', 'pre')
  1270.     RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript', NON_NESTABLE_BLOCK_TAGS, NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS)
  1271.     NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS, NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS)
  1272.     CHARSET_RE = re.compile('((^|;)\\s*charset=)([^;]*)', re.M)
  1273.     
  1274.     def start_meta(self, attrs):
  1275.         httpEquiv = None
  1276.         contentType = None
  1277.         contentTypeIndex = None
  1278.         tagNeedsEncodingSubstitution = False
  1279.         for i in range(0, len(attrs)):
  1280.             (key, value) = attrs[i]
  1281.             key = key.lower()
  1282.             if key == 'http-equiv':
  1283.                 httpEquiv = value
  1284.                 continue
  1285.             if key == 'content':
  1286.                 contentType = value
  1287.                 contentTypeIndex = i
  1288.                 continue
  1289.         
  1290.         if httpEquiv and contentType:
  1291.             match = self.CHARSET_RE.search(contentType)
  1292.             if match:
  1293.                 if self.declaredHTMLEncoding is not None or self.originalEncoding == self.fromEncoding:
  1294.                     
  1295.                     def rewrite(match):
  1296.                         return match.group(1) + '%SOUP-ENCODING%'
  1297.  
  1298.                     newAttr = self.CHARSET_RE.sub(rewrite, contentType)
  1299.                     attrs[contentTypeIndex] = (attrs[contentTypeIndex][0], newAttr)
  1300.                     tagNeedsEncodingSubstitution = True
  1301.                 else:
  1302.                     newCharset = match.group(3)
  1303.                     if newCharset and newCharset != self.originalEncoding:
  1304.                         self.declaredHTMLEncoding = newCharset
  1305.                         self._feed(self.declaredHTMLEncoding)
  1306.                         raise StopParsing
  1307.                     newCharset != self.originalEncoding
  1308.             
  1309.         
  1310.         tag = self.unknown_starttag('meta', attrs)
  1311.         if tag and tagNeedsEncodingSubstitution:
  1312.             tag.containsSubstitutions = True
  1313.         
  1314.  
  1315.  
  1316.  
  1317. class StopParsing(Exception):
  1318.     pass
  1319.  
  1320.  
  1321. class ICantBelieveItsBeautifulSoup(BeautifulSoup):
  1322.     I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = ('em', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'strong', 'cite', 'code', 'dfn', 'kbd', 'samp', 'strong', 'var', 'b', 'big')
  1323.     I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = ('noscript',)
  1324.     NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS, I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS, I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS)
  1325.  
  1326.  
  1327. class MinimalSoup(BeautifulSoup):
  1328.     RESET_NESTING_TAGS = buildTagMap('noscript')
  1329.     NESTABLE_TAGS = { }
  1330.  
  1331.  
  1332. class BeautifulSOAP(BeautifulStoneSoup):
  1333.     
  1334.     def popTag(self):
  1335.         if len(self.tagStack) > 1:
  1336.             tag = self.tagStack[-1]
  1337.             parent = self.tagStack[-2]
  1338.             parent._getAttrMap()
  1339.             if isinstance(tag, Tag) and len(tag.contents) == 1 and isinstance(tag.contents[0], NavigableString) and not parent.attrMap.has_key(tag.name):
  1340.                 parent[tag.name] = tag.contents[0]
  1341.             
  1342.         
  1343.         BeautifulStoneSoup.popTag(self)
  1344.  
  1345.  
  1346.  
  1347. class RobustXMLParser(BeautifulStoneSoup):
  1348.     pass
  1349.  
  1350.  
  1351. class RobustHTMLParser(BeautifulSoup):
  1352.     pass
  1353.  
  1354.  
  1355. class RobustWackAssHTMLParser(ICantBelieveItsBeautifulSoup):
  1356.     pass
  1357.  
  1358.  
  1359. class RobustInsanelyWackAssHTMLParser(MinimalSoup):
  1360.     pass
  1361.  
  1362.  
  1363. class SimplifyingSOAPParser(BeautifulSOAP):
  1364.     pass
  1365.  
  1366.  
  1367. try:
  1368.     import chardet
  1369. except ImportError:
  1370.     chardet = None
  1371.  
  1372.  
  1373. try:
  1374.     import cjkcodecs.aliases as cjkcodecs
  1375. except ImportError:
  1376.     pass
  1377.  
  1378.  
  1379. try:
  1380.     import iconv_codec
  1381. except ImportError:
  1382.     pass
  1383.  
  1384.  
  1385. class UnicodeDammit:
  1386.     CHARSET_ALIASES = {
  1387.         'macintosh': 'mac-roman',
  1388.         'x-sjis': 'shift-jis' }
  1389.     
  1390.     def __init__(self, markup, overrideEncodings = [], smartQuotesTo = 'xml', isHTML = False):
  1391.         self.declaredHTMLEncoding = None
  1392.         (self.markup, documentEncoding, sniffedEncoding) = self._detectEncoding(markup, isHTML)
  1393.         self.smartQuotesTo = smartQuotesTo
  1394.         self.triedEncodings = []
  1395.         if markup == '' or isinstance(markup, unicode):
  1396.             self.originalEncoding = None
  1397.             self.unicode = unicode(markup)
  1398.             return None
  1399.         u = None
  1400.         for proposedEncoding in overrideEncodings:
  1401.             u = self._convertFrom(proposedEncoding)
  1402.             if u:
  1403.                 break
  1404.                 continue
  1405.             isinstance(markup, unicode)
  1406.         
  1407.         if not u:
  1408.             for proposedEncoding in (documentEncoding, sniffedEncoding):
  1409.                 u = self._convertFrom(proposedEncoding)
  1410.                 if u:
  1411.                     break
  1412.                     continue
  1413.             
  1414.         
  1415.         if not u and chardet and not isinstance(self.markup, unicode):
  1416.             u = self._convertFrom(chardet.detect(self.markup)['encoding'])
  1417.         
  1418.         if not u:
  1419.             for proposed_encoding in ('utf-8', 'windows-1252'):
  1420.                 u = self._convertFrom(proposed_encoding)
  1421.                 if u:
  1422.                     break
  1423.                     continue
  1424.             
  1425.         
  1426.         self.unicode = u
  1427.         if not u:
  1428.             self.originalEncoding = None
  1429.         
  1430.  
  1431.     
  1432.     def _subMSChar(self, orig):
  1433.         sub = self.MS_CHARS.get(orig)
  1434.         if isinstance(sub, tuple):
  1435.             if self.smartQuotesTo == 'xml':
  1436.                 sub = '&#x%s;' % sub[1]
  1437.             else:
  1438.                 sub = '&%s;' % sub[0]
  1439.         
  1440.         return sub
  1441.  
  1442.     
  1443.     def _convertFrom(self, proposed):
  1444.         proposed = self.find_codec(proposed)
  1445.         if not proposed or proposed in self.triedEncodings:
  1446.             return None
  1447.         self.triedEncodings.append(proposed)
  1448.         markup = self.markup
  1449.         if self.smartQuotesTo and proposed.lower() in ('windows-1252', 'iso-8859-1', 'iso-8859-2'):
  1450.             markup = (re.compile('([\x80-\x9f])').sub,)((lambda x: self._subMSChar(x.group(1))), markup)
  1451.         
  1452.         
  1453.         try:
  1454.             u = self._toUnicode(markup, proposed)
  1455.             self.markup = u
  1456.             self.originalEncoding = proposed
  1457.         except Exception:
  1458.             e = None
  1459.             return None
  1460.  
  1461.         return self.markup
  1462.  
  1463.     
  1464.     def _toUnicode(self, data, encoding):
  1465.         if len(data) >= 4 and data[:2] == '\xfe\xff' and data[2:4] != '\x00\x00':
  1466.             encoding = 'utf-16be'
  1467.             data = data[2:]
  1468.         elif len(data) >= 4 and data[:2] == '\xff\xfe' and data[2:4] != '\x00\x00':
  1469.             encoding = 'utf-16le'
  1470.             data = data[2:]
  1471.         elif data[:3] == '\xef\xbb\xbf':
  1472.             encoding = 'utf-8'
  1473.             data = data[3:]
  1474.         elif data[:4] == '\x00\x00\xfe\xff':
  1475.             encoding = 'utf-32be'
  1476.             data = data[4:]
  1477.         elif data[:4] == '\xff\xfe\x00\x00':
  1478.             encoding = 'utf-32le'
  1479.             data = data[4:]
  1480.         
  1481.         newdata = unicode(data, encoding)
  1482.         return newdata
  1483.  
  1484.     
  1485.     def _detectEncoding(self, xml_data, isHTML = False):
  1486.         xml_encoding = None
  1487.         sniffed_xml_encoding = None
  1488.         
  1489.         try:
  1490.             if xml_data[:4] == 'Lo\xa7\x94':
  1491.                 xml_data = self._ebcdic_to_ascii(xml_data)
  1492.             elif xml_data[:4] == '\x00<\x00?':
  1493.                 sniffed_xml_encoding = 'utf-16be'
  1494.                 xml_data = unicode(xml_data, 'utf-16be').encode('utf-8')
  1495.             elif len(xml_data) >= 4 and xml_data[:2] == '\xfe\xff' and xml_data[2:4] != '\x00\x00':
  1496.                 sniffed_xml_encoding = 'utf-16be'
  1497.                 xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8')
  1498.             elif xml_data[:4] == '<\x00?\x00':
  1499.                 sniffed_xml_encoding = 'utf-16le'
  1500.                 xml_data = unicode(xml_data, 'utf-16le').encode('utf-8')
  1501.             elif len(xml_data) >= 4 and xml_data[:2] == '\xff\xfe' and xml_data[2:4] != '\x00\x00':
  1502.                 sniffed_xml_encoding = 'utf-16le'
  1503.                 xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8')
  1504.             elif xml_data[:4] == '\x00\x00\x00<':
  1505.                 sniffed_xml_encoding = 'utf-32be'
  1506.                 xml_data = unicode(xml_data, 'utf-32be').encode('utf-8')
  1507.             elif xml_data[:4] == '<\x00\x00\x00':
  1508.                 sniffed_xml_encoding = 'utf-32le'
  1509.                 xml_data = unicode(xml_data, 'utf-32le').encode('utf-8')
  1510.             elif xml_data[:4] == '\x00\x00\xfe\xff':
  1511.                 sniffed_xml_encoding = 'utf-32be'
  1512.                 xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8')
  1513.             elif xml_data[:4] == '\xff\xfe\x00\x00':
  1514.                 sniffed_xml_encoding = 'utf-32le'
  1515.                 xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8')
  1516.             elif xml_data[:3] == '\xef\xbb\xbf':
  1517.                 sniffed_xml_encoding = 'utf-8'
  1518.                 xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8')
  1519.             else:
  1520.                 sniffed_xml_encoding = 'ascii'
  1521.         except:
  1522.             xml_encoding_match = None
  1523.  
  1524.         xml_encoding_match = re.compile('^<\\?.*encoding=[\'"](.*?)[\'"].*\\?>').match(xml_data)
  1525.         if not xml_encoding_match and isHTML:
  1526.             regexp = re.compile('<\\s*meta[^>]+charset=([^>]*?)[;\'">]', re.I)
  1527.             xml_encoding_match = regexp.search(xml_data)
  1528.         
  1529.         if xml_encoding_match is not None:
  1530.             xml_encoding = xml_encoding_match.groups()[0].lower()
  1531.             if isHTML:
  1532.                 self.declaredHTMLEncoding = xml_encoding
  1533.             
  1534.             if sniffed_xml_encoding and xml_encoding in ('iso-10646-ucs-2', 'ucs-2', 'csunicode', 'iso-10646-ucs-4', 'ucs-4', 'csucs4', 'utf-16', 'utf-32', 'utf_16', 'utf_32', 'utf16', 'u16'):
  1535.                 xml_encoding = sniffed_xml_encoding
  1536.             
  1537.         
  1538.         return (xml_data, xml_encoding, sniffed_xml_encoding)
  1539.  
  1540.     
  1541.     def find_codec(self, charset):
  1542.         if not self._codec(self.CHARSET_ALIASES.get(charset, charset)):
  1543.             if not charset or self._codec(charset.replace('-', '')):
  1544.                 if not charset or self._codec(charset.replace('-', '_')):
  1545.                     pass
  1546.         return charset
  1547.  
  1548.     
  1549.     def _codec(self, charset):
  1550.         if not charset:
  1551.             return charset
  1552.         codec = None
  1553.         
  1554.         try:
  1555.             codecs.lookup(charset)
  1556.             codec = charset
  1557.         except (LookupError, ValueError):
  1558.             charset
  1559.             charset
  1560.         except:
  1561.             charset
  1562.  
  1563.         return codec
  1564.  
  1565.     EBCDIC_TO_ASCII_MAP = None
  1566.     
  1567.     def _ebcdic_to_ascii(self, s):
  1568.         c = self.__class__
  1569.         if not c.EBCDIC_TO_ASCII_MAP:
  1570.             emap = (0, 1, 2, 3, 156, 9, 134, 127, 151, 141, 142, 11, 12, 13, 14, 15, 16, 17, 18, 19, 157, 133, 8, 135, 24, 25, 146, 143, 28, 29, 30, 31, 128, 129, 130, 131, 132, 10, 23, 27, 136, 137, 138, 139, 140, 5, 6, 7, 144, 145, 22, 147, 148, 149, 150, 4, 152, 153, 154, 155, 20, 21, 158, 26, 32, 160, 161, 162, 163, 164, 165, 166, 167, 168, 91, 46, 60, 40, 43, 33, 38, 169, 170, 171, 172, 173, 174, 175, 176, 177, 93, 36, 42, 41, 59, 94, 45, 47, 178, 179, 180, 181, 182, 183, 184, 185, 124, 44, 37, 95, 62, 63, 186, 187, 188, 189, 190, 191, 192, 193, 194, 96, 58, 35, 64, 39, 61, 34, 195, 97, 98, 99, 100, 101, 102, 103, 104, 105, 196, 197, 198, 199, 200, 201, 202, 106, 107, 108, 109, 110, 111, 112, 113, 114, 203, 204, 205, 206, 207, 208, 209, 126, 115, 116, 117, 118, 119, 120, 121, 122, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 123, 65, 66, 67, 68, 69, 70, 71, 72, 73, 232, 233, 234, 235, 236, 237, 125, 74, 75, 76, 77, 78, 79, 80, 81, 82, 238, 239, 240, 241, 242, 243, 92, 159, 83, 84, 85, 86, 87, 88, 89, 90, 244, 245, 246, 247, 248, 249, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 250, 251, 252, 253, 254, 255)
  1571.             import string
  1572.             c.EBCDIC_TO_ASCII_MAP = string.maketrans(''.join(map(chr, range(256))), ''.join(map(chr, emap)))
  1573.         
  1574.         return s.translate(c.EBCDIC_TO_ASCII_MAP)
  1575.  
  1576.     MS_CHARS = {
  1577.         '\x80': ('euro', '20AC'),
  1578.         '\x81': ' ',
  1579.         '\x82': ('sbquo', '201A'),
  1580.         '\x83': ('fnof', '192'),
  1581.         '\x84': ('bdquo', '201E'),
  1582.         '\x85': ('hellip', '2026'),
  1583.         '\x86': ('dagger', '2020'),
  1584.         '\x87': ('Dagger', '2021'),
  1585.         '\x88': ('circ', '2C6'),
  1586.         '\x89': ('permil', '2030'),
  1587.         '\x8a': ('Scaron', '160'),
  1588.         '\x8b': ('lsaquo', '2039'),
  1589.         '\x8c': ('OElig', '152'),
  1590.         '\x8d': '?',
  1591.         '\x8e': ('#x17D', '17D'),
  1592.         '\x8f': '?',
  1593.         '\x90': '?',
  1594.         '\x91': ('lsquo', '2018'),
  1595.         '\x92': ('rsquo', '2019'),
  1596.         '\x93': ('ldquo', '201C'),
  1597.         '\x94': ('rdquo', '201D'),
  1598.         '\x95': ('bull', '2022'),
  1599.         '\x96': ('ndash', '2013'),
  1600.         '\x97': ('mdash', '2014'),
  1601.         '\x98': ('tilde', '2DC'),
  1602.         '\x99': ('trade', '2122'),
  1603.         '\x9a': ('scaron', '161'),
  1604.         '\x9b': ('rsaquo', '203A'),
  1605.         '\x9c': ('oelig', '153'),
  1606.         '\x9d': '?',
  1607.         '\x9e': ('#x17E', '17E'),
  1608.         '\x9f': ('Yuml', '') }
  1609.  
  1610. if __name__ == '__main__':
  1611.     import sys
  1612.     soup = BeautifulSoup(sys.stdin)
  1613.     print soup.prettify()
  1614.  
  1615.