home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2010 November / maximum-cd-2010-11.iso / DiscContents / calibre-0.7.13.msi / file_2024 (.txt) < prev    next >
Encoding:
Python Compiled Bytecode  |  2010-08-06  |  30.2 KB  |  908 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__ = '2.1.1'
  7. __date__ = '$Date: 2004/10/18 00:14:20 $'
  8. __copyright__ = 'Copyright (c) 2004-2005 Leonard Richardson'
  9. __license__ = 'PSF'
  10. from sgmllib import SGMLParser, SGMLParseError
  11. import types
  12. import re
  13. import sgmllib
  14. sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*')
  15.  
  16. class NullType(object):
  17.     
  18.     def __new__(cls):
  19.         return Null
  20.  
  21.     
  22.     def __call__(self, *args, **kwargs):
  23.         return Null
  24.  
  25.     
  26.     def __getattr__(self, attr):
  27.         return Null
  28.  
  29.     
  30.     def __getitem__(self, item):
  31.         return Null
  32.  
  33.     
  34.     def __setattr__(self, attr, value):
  35.         pass
  36.  
  37.     
  38.     def __setitem__(self, item, value):
  39.         pass
  40.  
  41.     
  42.     def __len__(self):
  43.         return 0
  44.  
  45.     
  46.     def __iter__(self):
  47.         return iter([])
  48.  
  49.     
  50.     def __contains__(self, item):
  51.         return False
  52.  
  53.     
  54.     def __repr__(self):
  55.         return 'Null'
  56.  
  57.  
  58. Null = object.__new__(NullType)
  59.  
  60. class PageElement:
  61.     
  62.     def setup(self, parent = Null, previous = Null):
  63.         self.parent = parent
  64.         self.previous = previous
  65.         self.next = Null
  66.         self.previousSibling = Null
  67.         self.nextSibling = Null
  68.         if self.parent and self.parent.contents:
  69.             self.previousSibling = self.parent.contents[-1]
  70.             self.previousSibling.nextSibling = self
  71.         
  72.  
  73.     
  74.     def findNext(self, name = None, attrs = { }, text = None):
  75.         return self._first(self.fetchNext, name, attrs, text)
  76.  
  77.     firstNext = findNext
  78.     
  79.     def fetchNext(self, name = None, attrs = { }, text = None, limit = None):
  80.         return self._fetch(name, attrs, text, limit, self.nextGenerator)
  81.  
  82.     
  83.     def findNextSibling(self, name = None, attrs = { }, text = None):
  84.         return self._first(self.fetchNextSiblings, name, attrs, text)
  85.  
  86.     firstNextSibling = findNextSibling
  87.     
  88.     def fetchNextSiblings(self, name = None, attrs = { }, text = None, limit = None):
  89.         return self._fetch(name, attrs, text, limit, self.nextSiblingGenerator)
  90.  
  91.     
  92.     def findPrevious(self, name = None, attrs = { }, text = None):
  93.         return self._first(self.fetchPrevious, name, attrs, text)
  94.  
  95.     
  96.     def fetchPrevious(self, name = None, attrs = { }, text = None, limit = None):
  97.         return self._fetch(name, attrs, text, limit, self.previousGenerator)
  98.  
  99.     firstPrevious = findPrevious
  100.     
  101.     def findPreviousSibling(self, name = None, attrs = { }, text = None):
  102.         return self._first(self.fetchPreviousSiblings, name, attrs, text)
  103.  
  104.     firstPreviousSibling = findPreviousSibling
  105.     
  106.     def fetchPreviousSiblings(self, name = None, attrs = { }, text = None, limit = None):
  107.         return self._fetch(name, attrs, text, limit, self.previousSiblingGenerator)
  108.  
  109.     
  110.     def findParent(self, name = None, attrs = { }):
  111.         r = Null
  112.         l = self.fetchParents(name, attrs, 1)
  113.         if l:
  114.             r = l[0]
  115.         
  116.         return r
  117.  
  118.     firstParent = findParent
  119.     
  120.     def fetchParents(self, name = None, attrs = { }, limit = None):
  121.         return self._fetch(name, attrs, None, limit, self.parentGenerator)
  122.  
  123.     
  124.     def _first(self, method, name, attrs, text):
  125.         r = Null
  126.         l = method(name, attrs, text, 1)
  127.         if l:
  128.             r = l[0]
  129.         
  130.         return r
  131.  
  132.     
  133.     def _fetch(self, name, attrs, text, limit, generator):
  134.         if not hasattr(attrs, 'items'):
  135.             attrs = {
  136.                 'class': attrs }
  137.         
  138.         results = []
  139.         g = generator()
  140.         while True:
  141.             
  142.             try:
  143.                 i = g.next()
  144.             except StopIteration:
  145.                 break
  146.  
  147.             found = None
  148.             if isinstance(i, Tag):
  149.                 if not text:
  150.                     if not name or self._matches(i, name):
  151.                         match = True
  152.                         for attr, matchAgainst in attrs.items():
  153.                             check = i.get(attr)
  154.                             if not self._matches(check, matchAgainst):
  155.                                 match = False
  156.                                 break
  157.                                 continue
  158.                         
  159.                         if match:
  160.                             found = i
  161.                         
  162.                     
  163.                 
  164.             elif text:
  165.                 if self._matches(i, text):
  166.                     found = i
  167.                 
  168.             
  169.             if found:
  170.                 results.append(found)
  171.                 if limit and len(results) >= limit:
  172.                     break
  173.                 
  174.             len(results) >= limit
  175.         return results
  176.  
  177.     
  178.     def nextGenerator(self):
  179.         i = self
  180.         while i:
  181.             i = i.next
  182.             yield i
  183.  
  184.     
  185.     def nextSiblingGenerator(self):
  186.         i = self
  187.         while i:
  188.             i = i.nextSibling
  189.             yield i
  190.  
  191.     
  192.     def previousGenerator(self):
  193.         i = self
  194.         while i:
  195.             i = i.previous
  196.             yield i
  197.  
  198.     
  199.     def previousSiblingGenerator(self):
  200.         i = self
  201.         while i:
  202.             i = i.previousSibling
  203.             yield i
  204.  
  205.     
  206.     def parentGenerator(self):
  207.         i = self
  208.         while i:
  209.             i = i.parent
  210.             yield i
  211.  
  212.     
  213.     def _matches(self, chunk, howToMatch):
  214.         if isList(chunk) and not isinstance(chunk, Tag):
  215.             for tag in chunk:
  216.                 if isinstance(tag, NavigableText) and self._matches(tag, howToMatch):
  217.                     return True
  218.             
  219.             return False
  220.         if callable(howToMatch):
  221.             return howToMatch(chunk)
  222.         if not isinstance(chunk, basestring):
  223.             chunk = str(chunk)
  224.         
  225.         if hasattr(howToMatch, 'match'):
  226.             return howToMatch.search(chunk)
  227.         if isList(howToMatch):
  228.             return chunk in howToMatch
  229.         if hasattr(howToMatch, 'items'):
  230.             return howToMatch.has_key(chunk)
  231.         return str(howToMatch) == chunk
  232.  
  233.  
  234.  
  235. class NavigableText(PageElement):
  236.     
  237.     def __getattr__(self, attr):
  238.         if attr == 'string':
  239.             return self
  240.         raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__.__name__, attr)
  241.  
  242.  
  243.  
  244. class NavigableString(str, NavigableText):
  245.     pass
  246.  
  247.  
  248. class NavigableUnicodeString(unicode, NavigableText):
  249.     pass
  250.  
  251.  
  252. class Tag(PageElement):
  253.     
  254.     def __init__(self, name, attrs = None, parent = Null, previous = Null):
  255.         self.name = name
  256.         if attrs == None:
  257.             attrs = []
  258.         
  259.         self.attrs = attrs
  260.         self.contents = []
  261.         self.setup(parent, previous)
  262.         self.hidden = False
  263.  
  264.     
  265.     def get(self, key, default = None):
  266.         return self._getAttrMap().get(key, default)
  267.  
  268.     
  269.     def __getitem__(self, key):
  270.         return self._getAttrMap()[key]
  271.  
  272.     
  273.     def __iter__(self):
  274.         return iter(self.contents)
  275.  
  276.     
  277.     def __len__(self):
  278.         return len(self.contents)
  279.  
  280.     
  281.     def __contains__(self, x):
  282.         return x in self.contents
  283.  
  284.     
  285.     def __nonzero__(self):
  286.         return True
  287.  
  288.     
  289.     def __setitem__(self, key, value):
  290.         self._getAttrMap()
  291.         self.attrMap[key] = value
  292.         found = False
  293.         for i in range(0, len(self.attrs)):
  294.             if self.attrs[i][0] == key:
  295.                 self.attrs[i] = (key, value)
  296.                 found = True
  297.                 continue
  298.         
  299.         if not found:
  300.             self.attrs.append((key, value))
  301.         
  302.         self._getAttrMap()[key] = value
  303.  
  304.     
  305.     def __delitem__(self, key):
  306.         for item in self.attrs:
  307.             if item[0] == key:
  308.                 self.attrs.remove(item)
  309.             
  310.             self._getAttrMap()
  311.             if self.attrMap.has_key(key):
  312.                 del self.attrMap[key]
  313.                 continue
  314.         
  315.  
  316.     
  317.     def __call__(self, *args, **kwargs):
  318.         return apply(self.fetch, args, kwargs)
  319.  
  320.     
  321.     def __getattr__(self, tag):
  322.         if len(tag) > 3 and tag.rfind('Tag') == len(tag) - 3:
  323.             return self.first(tag[:-3])
  324.         if tag.find('__') != 0:
  325.             return self.first(tag)
  326.  
  327.     
  328.     def __eq__(self, other):
  329.         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):
  330.             return False
  331.         for i in range(0, len(self.contents)):
  332.             if self.contents[i] != other.contents[i]:
  333.                 return False
  334.         
  335.         return True
  336.  
  337.     
  338.     def __ne__(self, other):
  339.         return not (self == other)
  340.  
  341.     
  342.     def __repr__(self):
  343.         return str(self)
  344.  
  345.     
  346.     def __unicode__(self):
  347.         return self.__str__(1)
  348.  
  349.     
  350.     def __str__(self, needUnicode = None, showStructureIndent = None):
  351.         attrs = []
  352.         if self.attrs:
  353.             for key, val in self.attrs:
  354.                 attrs.append('%s="%s"' % (key, val))
  355.             
  356.         
  357.         close = ''
  358.         closeTag = ''
  359.         if self.isSelfClosing():
  360.             close = ' /'
  361.         else:
  362.             closeTag = '</%s>' % self.name
  363.         indentIncrement = None
  364.         if showStructureIndent != None:
  365.             indentIncrement = showStructureIndent
  366.             if not self.hidden:
  367.                 indentIncrement += 1
  368.             
  369.         
  370.         contents = self.renderContents(indentIncrement, needUnicode = needUnicode)
  371.         if showStructureIndent:
  372.             space = '\n%s' % ' ' * showStructureIndent
  373.         
  374.         if self.hidden:
  375.             s = contents
  376.         else:
  377.             s = []
  378.             attributeString = ''
  379.             if attrs:
  380.                 attributeString = ' ' + ' '.join(attrs)
  381.             
  382.             if showStructureIndent:
  383.                 s.append(space)
  384.             
  385.             s.append('<%s%s%s>' % (self.name, attributeString, close))
  386.             s.append(contents)
  387.             if closeTag and showStructureIndent != None:
  388.                 s.append(space)
  389.             
  390.             s.append(closeTag)
  391.             s = ''.join(s)
  392.         isUnicode = type(s) == types.UnicodeType
  393.         if needUnicode and not isUnicode:
  394.             s = unicode(s)
  395.         elif isUnicode and needUnicode == False:
  396.             s = str(s)
  397.         
  398.         return s
  399.  
  400.     
  401.     def prettify(self, needUnicode = None):
  402.         return self.__str__(needUnicode, showStructureIndent = True)
  403.  
  404.     
  405.     def renderContents(self, showStructureIndent = None, needUnicode = None):
  406.         s = []
  407.         for c in self:
  408.             text = None
  409.             if isinstance(c, NavigableUnicodeString) or type(c) == types.UnicodeType:
  410.                 text = unicode(c)
  411.             elif isinstance(c, Tag):
  412.                 s.append(c.__str__(needUnicode, showStructureIndent))
  413.             elif needUnicode:
  414.                 text = unicode(c)
  415.             else:
  416.                 text = str(c)
  417.             if text:
  418.                 if showStructureIndent != None:
  419.                     if text[-1] == '\n':
  420.                         text = text[:-1]
  421.                     
  422.                 
  423.                 s.append(text)
  424.                 continue
  425.         
  426.         return ''.join(s)
  427.  
  428.     
  429.     def firstText(self, text, recursive = True):
  430.         return self.first(recursive = recursive, text = text)
  431.  
  432.     
  433.     def fetchText(self, text, recursive = True, limit = None):
  434.         return self.fetch(recursive = recursive, text = text, limit = limit)
  435.  
  436.     
  437.     def first(self, name = None, attrs = { }, recursive = True, text = None):
  438.         r = Null
  439.         l = self.fetch(name, attrs, recursive, text, 1)
  440.         if l:
  441.             r = l[0]
  442.         
  443.         return r
  444.  
  445.     findChild = first
  446.     
  447.     def fetch(self, name = None, attrs = { }, recursive = True, text = None, limit = None):
  448.         generator = self.recursiveChildGenerator
  449.         if not recursive:
  450.             generator = self.childGenerator
  451.         
  452.         return self._fetch(name, attrs, text, limit, generator)
  453.  
  454.     fetchChildren = fetch
  455.     
  456.     def isSelfClosing(self):
  457.         return self.name in BeautifulSoup.SELF_CLOSING_TAGS
  458.  
  459.     
  460.     def append(self, tag):
  461.         self.contents.append(tag)
  462.  
  463.     
  464.     def _getAttrMap(self):
  465.         if not getattr(self, 'attrMap'):
  466.             self.attrMap = { }
  467.             for key, value in self.attrs:
  468.                 self.attrMap[key] = value
  469.             
  470.         
  471.         return self.attrMap
  472.  
  473.     
  474.     def childGenerator(self):
  475.         for i in range(0, len(self.contents)):
  476.             yield self.contents[i]
  477.         
  478.         raise StopIteration
  479.  
  480.     
  481.     def recursiveChildGenerator(self):
  482.         stack = [
  483.             (self, 0)]
  484.         while stack:
  485.             (tag, start) = stack.pop()
  486.             if isinstance(tag, Tag):
  487.                 for i in range(start, len(tag.contents)):
  488.                     a = tag.contents[i]
  489.                     yield a
  490.                     if isinstance(a, Tag) and tag.contents:
  491.                         if i < len(tag.contents) - 1:
  492.                             stack.append((tag, i + 1))
  493.                         
  494.                         stack.append((a, 0))
  495.                         break
  496.                         continue
  497.                 
  498.         raise StopIteration
  499.  
  500.  
  501.  
  502. def isList(l):
  503.     if not hasattr(l, '__iter__'):
  504.         pass
  505.     return type(l) in (types.ListType, types.TupleType)
  506.  
  507.  
  508. def buildTagMap(default, *args):
  509.     built = { }
  510.     for portion in args:
  511.         if hasattr(portion, 'items'):
  512.             for k, v in portion.items():
  513.                 built[k] = v
  514.             
  515.         if isList(portion):
  516.             for k in portion:
  517.                 built[k] = default
  518.             
  519.         built[portion] = default
  520.     
  521.     return built
  522.  
  523.  
  524. class BeautifulStoneSoup(Tag, SGMLParser):
  525.     SELF_CLOSING_TAGS = { }
  526.     NESTABLE_TAGS = { }
  527.     RESET_NESTING_TAGS = { }
  528.     QUOTE_TAGS = { }
  529.     MS_CHARS = {
  530.         '\x80': '€',
  531.         '\x81': ' ',
  532.         '\x82': '‚',
  533.         '\x83': 'ƒ',
  534.         '\x84': '„',
  535.         '\x85': '…',
  536.         '\x86': '†',
  537.         '\x87': '‡',
  538.         '\x88': '⁁',
  539.         '\x89': '%',
  540.         '\x8a': 'Š',
  541.         '\x8b': '<',
  542.         '\x8c': 'Œ',
  543.         '\x8d': '?',
  544.         '\x8e': 'Z',
  545.         '\x8f': '?',
  546.         '\x90': '?',
  547.         '\x91': '‘',
  548.         '\x92': '’',
  549.         '\x93': '“',
  550.         '\x94': '”',
  551.         '\x95': '•',
  552.         '\x96': '–',
  553.         '\x97': '—',
  554.         '\x98': '˜',
  555.         '\x99': '™',
  556.         '\x9a': 'š',
  557.         '\x9b': '>',
  558.         '\x9c': 'œ',
  559.         '\x9d': '?',
  560.         '\x9e': 'z',
  561.         '\x9f': 'Ÿ' }
  562.     PARSER_MASSAGE = [
  563.         (re.compile('(<[^<>]*)/>'), (lambda x: x.group(1) + ' />')),
  564.         (re.compile('<!\\s+([^<>]*)>'), (lambda x: '<!' + x.group(1) + '>')),
  565.         (re.compile('([\x80-\x9f])'), (lambda x: BeautifulStoneSoup.MS_CHARS.get(x.group(1))))]
  566.     ROOT_TAG_NAME = '[document]'
  567.     
  568.     def __init__(self, text = None, avoidParserProblems = True, initialTextIsEverything = True):
  569.         Tag.__init__(self, self.ROOT_TAG_NAME)
  570.         if avoidParserProblems and not isList(avoidParserProblems):
  571.             avoidParserProblems = self.PARSER_MASSAGE
  572.         
  573.         self.avoidParserProblems = avoidParserProblems
  574.         SGMLParser.__init__(self)
  575.         self.quoteStack = []
  576.         self.hidden = 1
  577.         self.reset()
  578.         if hasattr(text, 'read'):
  579.             text = text.read()
  580.         
  581.         if text:
  582.             self.feed(text)
  583.         
  584.         if initialTextIsEverything:
  585.             self.done()
  586.         
  587.  
  588.     
  589.     def __getattr__(self, methodName):
  590.         if methodName.find('start_') == 0 and methodName.find('end_') == 0 or methodName.find('do_') == 0:
  591.             return SGMLParser.__getattr__(self, methodName)
  592.         if methodName.find('__') != 0:
  593.             return Tag.__getattr__(self, methodName)
  594.         raise AttributeError
  595.  
  596.     
  597.     def feed(self, text):
  598.         if self.avoidParserProblems:
  599.             for fix, m in self.avoidParserProblems:
  600.                 text = fix.sub(m, text)
  601.             
  602.         
  603.         SGMLParser.feed(self, text)
  604.  
  605.     
  606.     def done(self):
  607.         self.endData()
  608.         while self.currentTag.name != self.ROOT_TAG_NAME:
  609.             self.popTag()
  610.  
  611.     
  612.     def reset(self):
  613.         SGMLParser.reset(self)
  614.         self.currentData = []
  615.         self.currentTag = None
  616.         self.tagStack = []
  617.         self.pushTag(self)
  618.  
  619.     
  620.     def popTag(self):
  621.         tag = self.tagStack.pop()
  622.         if len(self.currentTag.contents) == 1 and isinstance(self.currentTag.contents[0], NavigableText):
  623.             self.currentTag.string = self.currentTag.contents[0]
  624.         
  625.         if self.tagStack:
  626.             self.currentTag = self.tagStack[-1]
  627.         
  628.         return self.currentTag
  629.  
  630.     
  631.     def pushTag(self, tag):
  632.         if self.currentTag:
  633.             self.currentTag.append(tag)
  634.         
  635.         self.tagStack.append(tag)
  636.         self.currentTag = self.tagStack[-1]
  637.  
  638.     
  639.     def endData(self):
  640.         currentData = ''.join(self.currentData)
  641.         if currentData:
  642.             if not currentData.strip():
  643.                 if '\n' in currentData:
  644.                     currentData = '\n'
  645.                 else:
  646.                     currentData = ' '
  647.             
  648.             c = NavigableString
  649.             if type(currentData) == types.UnicodeType:
  650.                 c = NavigableUnicodeString
  651.             
  652.             o = c(currentData)
  653.             o.setup(self.currentTag, self.previous)
  654.             if self.previous:
  655.                 self.previous.next = o
  656.             
  657.             self.previous = o
  658.             self.currentTag.contents.append(o)
  659.         
  660.         self.currentData = []
  661.  
  662.     
  663.     def _popToTag(self, name, inclusivePop = True):
  664.         if name == self.ROOT_TAG_NAME:
  665.             return None
  666.         numPops = 0
  667.         mostRecentTag = None
  668.         for i in range(len(self.tagStack) - 1, 0, -1):
  669.             if name == self.tagStack[i].name:
  670.                 numPops = len(self.tagStack) - i
  671.                 break
  672.                 continue
  673.             name == self.ROOT_TAG_NAME
  674.         
  675.         if not inclusivePop:
  676.             numPops = numPops - 1
  677.         
  678.         for i in range(0, numPops):
  679.             mostRecentTag = self.popTag()
  680.         
  681.         return mostRecentTag
  682.  
  683.     
  684.     def _smartPop(self, name):
  685.         nestingResetTriggers = self.NESTABLE_TAGS.get(name)
  686.         isNestable = nestingResetTriggers != None
  687.         isResetNesting = self.RESET_NESTING_TAGS.has_key(name)
  688.         popTo = None
  689.         inclusive = True
  690.         for i in range(len(self.tagStack) - 1, 0, -1):
  691.             p = self.tagStack[i]
  692.             if (not p or p.name == name) and not isNestable:
  693.                 popTo = name
  694.                 break
  695.             
  696.             if (nestingResetTriggers != None or p.name in nestingResetTriggers or nestingResetTriggers == None) and isResetNesting and self.RESET_NESTING_TAGS.has_key(p.name):
  697.                 popTo = p.name
  698.                 inclusive = False
  699.                 break
  700.             
  701.             p = p.parent
  702.         
  703.         if popTo:
  704.             self._popToTag(popTo, inclusive)
  705.         
  706.  
  707.     
  708.     def unknown_starttag(self, name, attrs, selfClosing = 0):
  709.         if self.quoteStack:
  710.             attrs = ''.join(map((lambda .0: (x, y) = .0' %s="%s"' % (x, y)), attrs))
  711.             self.handle_data('<%s%s>' % (name, attrs))
  712.             return None
  713.         self.endData()
  714.         if name not in self.SELF_CLOSING_TAGS and not selfClosing:
  715.             self._smartPop(name)
  716.         
  717.         tag = Tag(name, attrs, self.currentTag, self.previous)
  718.         if self.previous:
  719.             self.previous.next = tag
  720.         
  721.         self.previous = tag
  722.         self.pushTag(tag)
  723.         if selfClosing or name in self.SELF_CLOSING_TAGS:
  724.             self.popTag()
  725.         
  726.         if name in self.QUOTE_TAGS:
  727.             self.quoteStack.append(name)
  728.             self.literal = 1
  729.         
  730.  
  731.     
  732.     def unknown_endtag(self, name):
  733.         if self.quoteStack and self.quoteStack[-1] != name:
  734.             self.handle_data('</%s>' % name)
  735.             return None
  736.         self.endData()
  737.         self._popToTag(name)
  738.         if self.quoteStack and self.quoteStack[-1] == name:
  739.             self.quoteStack.pop()
  740.             self.literal = len(self.quoteStack) > 0
  741.         
  742.  
  743.     
  744.     def handle_data(self, data):
  745.         self.currentData.append(data)
  746.  
  747.     
  748.     def handle_pi(self, text):
  749.         self.handle_data('<?%s>' % text)
  750.  
  751.     
  752.     def handle_comment(self, text):
  753.         self.handle_data('<!--%s-->' % text)
  754.  
  755.     
  756.     def handle_charref(self, ref):
  757.         self.handle_data('&#%s;' % ref)
  758.  
  759.     
  760.     def handle_entityref(self, ref):
  761.         self.handle_data('&%s;' % ref)
  762.  
  763.     
  764.     def handle_decl(self, data):
  765.         self.handle_data('<!%s>' % data)
  766.  
  767.     
  768.     def parse_declaration(self, i):
  769.         j = None
  770.         if self.rawdata[i:i + 9] == '<![CDATA[':
  771.             k = self.rawdata.find(']]>', i)
  772.             if k == -1:
  773.                 k = len(self.rawdata)
  774.             
  775.             self.handle_data(self.rawdata[i + 9:k])
  776.             j = k + 3
  777.         else:
  778.             
  779.             try:
  780.                 j = SGMLParser.parse_declaration(self, i)
  781.             except SGMLParseError:
  782.                 toHandle = self.rawdata[i:]
  783.                 self.handle_data(toHandle)
  784.                 j = i + len(toHandle)
  785.  
  786.         return j
  787.  
  788.  
  789.  
  790. class BeautifulSoup(BeautifulStoneSoup):
  791.     SELF_CLOSING_TAGS = buildTagMap(None, [
  792.         'br',
  793.         'hr',
  794.         'input',
  795.         'img',
  796.         'meta',
  797.         'spacer',
  798.         'link',
  799.         'frame',
  800.         'base'])
  801.     QUOTE_TAGS = {
  802.         'script': None }
  803.     NESTABLE_INLINE_TAGS = [
  804.         'span',
  805.         'font',
  806.         'q',
  807.         'object',
  808.         'bdo',
  809.         'sub',
  810.         'sup',
  811.         'center']
  812.     NESTABLE_BLOCK_TAGS = [
  813.         'blockquote',
  814.         'div',
  815.         'fieldset',
  816.         'ins',
  817.         'del']
  818.     NESTABLE_LIST_TAGS = {
  819.         'ol': [],
  820.         'ul': [],
  821.         'li': [
  822.             'ul',
  823.             'ol'],
  824.         'dl': [],
  825.         'dd': [
  826.             'dl'],
  827.         'dt': [
  828.             'dl'] }
  829.     NESTABLE_TABLE_TAGS = {
  830.         'table': [],
  831.         'tr': [
  832.             'table',
  833.             'tbody',
  834.             'tfoot',
  835.             'thead'],
  836.         'td': [
  837.             'tr'],
  838.         'th': [
  839.             'tr'] }
  840.     NON_NESTABLE_BLOCK_TAGS = [
  841.         'address',
  842.         'form',
  843.         'p',
  844.         'pre']
  845.     RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript', NON_NESTABLE_BLOCK_TAGS, NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS)
  846.     NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS, NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS)
  847.  
  848.  
  849. class ICantBelieveItsBeautifulSoup(BeautifulSoup):
  850.     I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = [
  851.         'em',
  852.         'big',
  853.         'i',
  854.         'small',
  855.         'tt',
  856.         'abbr',
  857.         'acronym',
  858.         'strong',
  859.         'cite',
  860.         'code',
  861.         'dfn',
  862.         'kbd',
  863.         'samp',
  864.         'strong',
  865.         'var',
  866.         'b',
  867.         'big']
  868.     I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = [
  869.         'noscript']
  870.     NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS, I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS, I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS)
  871.  
  872.  
  873. class BeautifulSOAP(BeautifulStoneSoup):
  874.     
  875.     def popTag(self):
  876.         if len(self.tagStack) > 1:
  877.             tag = self.tagStack[-1]
  878.             parent = self.tagStack[-2]
  879.             parent._getAttrMap()
  880.             if isinstance(tag, Tag) and len(tag.contents) == 1 and isinstance(tag.contents[0], NavigableText) and not parent.attrMap.has_key(tag.name):
  881.                 parent[tag.name] = tag.contents[0]
  882.             
  883.         
  884.         BeautifulStoneSoup.popTag(self)
  885.  
  886.  
  887.  
  888. class RobustXMLParser(BeautifulStoneSoup):
  889.     pass
  890.  
  891.  
  892. class RobustHTMLParser(BeautifulSoup):
  893.     pass
  894.  
  895.  
  896. class RobustWackAssHTMLParser(ICantBelieveItsBeautifulSoup):
  897.     pass
  898.  
  899.  
  900. class SimplifyingSOAPParser(BeautifulSOAP):
  901.     pass
  902.  
  903. if __name__ == '__main__':
  904.     import sys
  905.     soup = BeautifulStoneSoup(sys.stdin.read())
  906.     print soup.prettify()
  907.  
  908.