home *** CD-ROM | disk | FTP | other *** search
/ Chip 2006 June / CHIP 2006-06.2.iso / program / freeware / Democracy-0.8.2.exe / xulrunner / python / xhtmltools.py < prev    next >
Encoding:
Python Source  |  2006-04-10  |  4.4 KB  |  134 lines

  1. import xml.sax.saxutils
  2. import xml.dom
  3. import re
  4. from urllib import quote
  5. from HTMLParser import HTMLParser
  6.  
  7. ##
  8. # very simple parser to convert HTML to XHTML
  9. class XHTMLifier(HTMLParser):
  10.     def convert(self,data, addTopTags=False):
  11.         if addTopTags:
  12.             self.output = '<html><head></head><body>'
  13.         else:
  14.             self.output = ''
  15.     self.stack = []
  16.     self.feed(data)
  17.     self.close()
  18.     while len(self.stack) > 0:
  19.         temp = self.stack.pop()
  20.         self.output += '</'+temp+'>'
  21.         if addTopTags:
  22.             self.output += '</body></html>'
  23.     return self.output
  24.     def handle_starttag(self, tag, attrs):
  25.     if tag.lower() == 'br':
  26.         self.output += '<br/>'
  27.     else:
  28.         self.output += '<'+tag
  29.         for attr in attrs:
  30.         if attr[1] == None:
  31.             self.output += ' '+attr[0]+'='+xml.sax.saxutils.quoteattr(attr[0])
  32.         else:
  33.             self.output += ' '+attr[0]+'='+xml.sax.saxutils.quoteattr(attr[1])
  34.         self.output += '>'
  35.         self.stack.append(tag)
  36.     def handle_endtag(self, tag):
  37.     if tag.lower() != 'br' and len(self.stack) > 1:
  38.         temp = self.stack.pop()
  39.         self.output += '</'+temp+'>'
  40.         while temp != tag and len(self.stack) > 1:
  41.         temp = self.stack.pop()
  42.         self.output += '</'+temp+'>'        
  43.     def handle_startendtag(self, tag, attrs):
  44.     self.output += '<'+tag+'/>'
  45.     def handle_data(self, data):
  46.     data = data.replace('&','&')
  47.     data = data.replace('<','<')
  48.     self.output += data
  49.     def handle_charref(self, name):
  50.     self.output += '&#'+name+';'
  51.     def handle_entityref(self, name):
  52.     self.output += '&'+name+';'
  53.  
  54. ##
  55. # Parses HTML entities in data
  56. def unescape(data):
  57.     return xml.sax.saxutils.unescape(data)
  58.  
  59. #
  60. # encodes string for use in a URL
  61. def urlencode(data):
  62.     return quote(data.encode('utf-8'), '')
  63.  
  64. ##
  65. # Returns XHTMLified version of HTML document
  66. def xhtmlify(data,addTopTags = False):
  67.     x = XHTMLifier()
  68.     return x.convert(data, addTopTags)
  69.  
  70. xmlheaderRE = re.compile("^\<\?xml\s*(.*?)\s*\?\>(.*)", re.S)
  71. ##
  72. # Adds a <?xml ?> header to the given xml data or replaces an
  73. # existing one without a charset with one that has a charset
  74. def fixXMLHeader(data,charset):
  75.     header = xmlheaderRE.match(data)
  76.     if header is None:
  77.         #print "Adding header %s" % charset
  78.         return '<?xml version="1.0" encoding="%s"?>%s' % (charset,data)
  79.     else:
  80.         xmlDecl = header.expand('\\1')
  81.         theRest = header.expand('\\2')
  82.         if xmlDecl.find('encoding'):
  83.             return data
  84.         else:
  85.             #print "Changing header to include charset"
  86.             return '<?xml %s encoding="%s"?>%s' % (xmlDecl,charset,theRest)
  87.  
  88.  
  89. HTMLHeaderRE = re.compile("^(.*)\<\s*head\s*(.*?)\s*\>(.*?)\</\s*head\s*\>(.*)",re.I | re.S)
  90.  
  91. ##
  92. # Adds a <meta http-equiv="Content-Type" content="text/html;
  93. # charset=blah"> tag to an HTML document
  94. #
  95. # Since we're only feeding this to our own HTML Parser anyway, we
  96. # don't care that it might bung up XHTML
  97. def fixHTMLHeader(data,charset):
  98.     header = HTMLHeaderRE.match(data)
  99.     if header is None:
  100.         #Something is very wrong with this HTML
  101.         return data
  102.     else:
  103.         headTags = header.expand('\\3')
  104.         #This isn't exactly robust, but neither is scraping HTML
  105.         if headTags.lower().find('content-type') != -1:
  106.             return data
  107.         else:
  108.             #print " adding %s Content-Type to HTML" % charset
  109.             return header.expand('\\1<head \\2><meta http-equiv="Content-Type" content="text/html; charset=')+charset+header.expand('">\\3</head>\\4')
  110.  
  111. # Takes a string and do whatever needs to be done to make it into a
  112. # UTF-8 string. If a Unicode string is given, it is just encoded in
  113. # UTF-8. Otherwise, if an encoding hint is given, first try to decode
  114. # the string as if it were in that encoding; if that fails (or the
  115. # hint isn't given), liberally (if necessary lossily) interpret it as
  116. # defaultEncoding, as declared on the next line:
  117. defaultEncoding = "iso-8859-1" # aka Latin-1
  118. def toUTF8Bytes(string, encoding=None):
  119.     # If we got a Unicode string, half of our work is already done.
  120.     if type(string) == unicode:
  121.         return string.encode('utf-8')
  122.  
  123.     # If we knew the encoding of the string, try that.
  124.     try:
  125.         if encoding is not None:
  126.             return string.decode(encoding).encode('utf-8')
  127.     except UnicodeDecodeError:
  128.         # string is not really encoded in 'encoding'.
  129.         pass
  130.  
  131.     # Encoding wasn't provided, or it was wrong. Interpret provided string
  132.     # liberally as a fixed defaultEncoding (see above.)
  133.     return string.decode(defaultEncoding, 'replace').encode('utf-8')
  134.