from htmlentitydefs import entitydefs import formatter, re, StringIO htmltag = re.compile('<.*?>', re.S) ######################################################################### # Convert html entity defs to xml # ######################################################################### def html2xml(html): chunks=re.split('&(\w+);',html) for i in range(1,len(chunks),2): if chunks[i] in ['amp', 'lt', 'gt', 'apos', 'quot']: chunks[i] ='&' + chunks[i] +';' elif chunks[i] in entitydefs: chunks[i]=entitydefs[chunks[i]] if len(chunks[i])==1: chunks[i]='&#'+str(ord(chunks[i]))+';' else: chunks[i]='?' return str("".join(chunks)) ######################################################################### # Remove html from string # ######################################################################### def dehtml(html): s=StringIO.StringIO() f=formatter.AbstractFormatter(formatter.DumbWriter(s)) f.add_flowing_data(html2xml(htmltag.sub('',html))) s.seek(0) return s.read() ######################################################################### # Convert high bit characters to numeric equivalents # ######################################################################### def xmlchars(text): if not isinstance(text,unicode): try: text = text.decode('utf-8') except: text = text.decode('iso-8859-1') text=re.compile(u"[\x00-\x08\x0B\x0C\x0E-\x1F\ud800-\udfff\ufffe-\uffff]"). \ sub(lambda c: u'' % hex(ord(c.group(0)))[2:].rjust(4,'0').upper(),text) for i in range(len(text)-1,-1,-1): if text[i] not in ('\r','\n') and not ord(text[i]) in range(32,128): text = '%s&#%d;%s' % (text[:i], ord(text[i]), text[i+1:]) return text ######################################################################### # Determine the author of a given item # ######################################################################### def authorFor(body): patterns = [ '(.*)\s
\s
\sPosted by (.*?)$', '(.*)\s
\s
\sPosted by (.*?)$', '(.*)\sPosted by (.*?)$', '(.*)\sPosted by (.*?)$', '(.*)

Trackback from (.*?)', '(.*)

Trackback from (.*?)$', '(.*)

Pingback from (.*?)$', '(.*)\s

Excerpt from (.*?)$', '(.*)\s

Emailed by (.*?)$', '(.*)\sEmailed by (.*?)$', '(.*)\s

Message from (.*?)$', '(.*)\s

Message from (.*?)$', '(.*)\sMessage from (.*?)$', '(.*)\sMessage from (.*?)$' ] match=None for pattern in patterns: match=match or re.search(pattern,body) if match: return match.groups()[1] ######################################################################### # Determine the id for a given link # ######################################################################### def idFor(link): (id,ext)=link.split('.',1) if ext.find('#')>=0: id+='-'+ext.split('#',1)[1][1:] return id ######################################################################### # Wrap content as appropriate # ######################################################################### def content(html, tag="content"): result=('<%s type="application/xhtml+xml" mode="xml">' '
%s
' % (tag, html2xml(html), tag)) try: from xml.dom import minidom minidom.parseString(result) except: result='<%s type="text/html" mode="escaped">' % tag if html.find(']]>')<0: result += '' else: from xml.sax.saxutils import escape result += escape(html) result += '' % tag return result ######################################################################### # Wrap description in xhtml:body or content:encoded as appropriate # ######################################################################### def bodyOrEncoded(description,attr=''): from xml.sax.saxutils import escape validBodyChildren =["p", "h1", "h2", "h3", "h4", "h5", "h6", "div", "pre", "address", "fieldset", "ins", "del"] from xml.dom import Node, minidom try: data=html2xml(description) body='' result=body + data + '' dom = minidom.parseString(result) for child in dom.documentElement.childNodes: if child.nodeName in validBodyChildren: continue if child.nodeType == Node.TEXT_NODE and child.data.isspace(): continue return body + '
' + data + '
' return result except: return '' + escape(description) + '' ######################################################################### # Wrap description in p:payload or content:encoded as appropriate # ######################################################################### def payloadOrEncoded(description,attr=''): from xml.sax.saxutils import escape from xml.dom import minidom try: result = '' result += html2xml(description) + '' minidom.parseString('%s' % result) return result except: return '' + escape(description) + '' ######################################################################### # Dynamically apply a compiled template # ######################################################################### def apply(flavor, data): try: try: exec 'from template.%s import %s as template' % (flavor,flavor) except: raise ImportError return template(searchList=data) except ImportError: from template.fof import fof as template return template(searchList=data) ######################################################################### # Format whatever portion of a date can be found in a path # ######################################################################### def format_date(path): import time date=map(int,filter(str.isdigit,path)) if not date: return None format='%d %b %Y'[(3-len(date))*3:] try: return time.strftime(format, date+[0,1,1, 0,0,0, 0,1,0][len(date):]) except ValueError, message: return message ######################################################################### # Format date per iso8601 # ######################################################################### def iso8601(date=0): import time if not date: date=time.localtime() base=time.strftime("%Y-%m-%dT%H:%M:%S",date or time.localtime()) return base + '%+.2d:00'%(-(date[-1] and time.altzone or time.timezone)/3600) ######################################################################### # Format date per rfc822 # ######################################################################### def rfc822_local(date=0): import time, rfc822 if not date: date=time.localtime() zone=time.tzname[date[-1]] if zone in rfc822._timezones.keys(): date=time.localtime(time.mktime(date)-time.timezone) return rfc822.formatdate(time.mktime(date)).replace("GMT",zone) else: return rfc822.formatdate(time.mktime(date)) ######################################################################### # Parse date per iso8601 # ######################################################################### def parseDate(input): import re,time if not input: return time.localtime() (date,zone)=re.findall('^(.*?)(?:Z|([+-]\d\d):)',input)[0] date=time.strptime(date,"%Y-%m-%dT%H:%M:%S") zone = int(zone or 0)*3600 + (date[-1] and time.altzone or time.timezone) return time.localtime(time.mktime(date)-zone) ######################################################################### # Parse href and link text from the content # ######################################################################### from sgmllib import SGMLParser class SNParser(SGMLParser): def __init__(self,text): SGMLParser.__init__(self) self.attrs=[] self.text='' self.links={} self.feed(text) def handle_data(self,data): self.text+=data def start_a(self,attrs): self.text='' self.attrs=dict(attrs) def end_a(self): if 'href' in self.attrs: self.links[self.attrs['href']]=self.text ######################################################################### # generate a css id from a name # ######################################################################### nonalpha=re.compile('\W+',re.UNICODE) def cssid(name): """ generate a css id from a name """ try: name = nonalpha.sub('-',name.decode('utf-8')).lower().encode('utf-8') except: name = nonalpha.sub('-',name).lower() return name.strip('-')