9220702c24ee433d60dd104d5c494e7518a930af
[WebKit-https.git] / atomstyler.py
1 from xml.dom import minidom, Node
2 from urlparse import urlparse, urlunparse
3 from xml.parsers.expat import ExpatError
4 from htmlentitydefs import name2codepoint
5 import re
6
7 # select and apply an xml:base for this entry
8 class relativize:
9   def __init__(self, parent):
10     self.score = {}
11     self.links = []
12     self.collect_and_tally(parent)
13     self.base = self.select_optimal_base()
14     if self.base:
15       if not parent.hasAttribute('xml:base'):
16         self.rebase(parent)
17         parent.setAttribute('xml:base', self.base)
18
19   # collect and tally cite, href and src attributes
20   def collect_and_tally(self,parent):
21     uri = None
22     if parent.hasAttribute('cite'): uri=parent.getAttribute('cite')
23     if parent.hasAttribute('href'): uri=parent.getAttribute('href')
24     if parent.hasAttribute('src'): uri=parent.getAttribute('src')
25
26     if uri:
27       parts=urlparse(uri)
28       if parts[0].lower() == 'http':
29         parts = (parts[1]+parts[2]).split('/')
30         base = None
31         for i in range(1,len(parts)):
32           base = tuple(parts[0:i])
33           self.score[base] = self.score.get(base,0) + len(base)
34         if base and base not in self.links: self.links.append(base)
35
36     for node in parent.childNodes:
37       if node.nodeType == Node.ELEMENT_NODE:
38         self.collect_and_tally(node)
39     
40   # select the xml:base with the highest score
41   def select_optimal_base(self):
42     if not self.score: return None
43     for link in self.links:
44       self.score[link] = 0
45     winner = max(self.score.values())
46     if not winner: return None
47     for key in self.score.keys():
48       if self.score[key] == winner:
49         if winner == len(key): return None
50         return urlunparse(('http', key[0], '/'.join(key[1:]), '', '', '')) + '/'
51     
52   # rewrite cite, href and src attributes using this base
53   def rebase(self,parent):
54     uri = None
55     if parent.hasAttribute('cite'): uri=parent.getAttribute('cite')
56     if parent.hasAttribute('href'): uri=parent.getAttribute('href')
57     if parent.hasAttribute('src'): uri=parent.getAttribute('src')
58     if uri and uri.startswith(self.base):
59       uri = uri[len(self.base):] or '.'
60       if parent.hasAttribute('href'): uri=parent.setAttribute('href', uri)
61       if parent.hasAttribute('src'): uri=parent.setAttribute('src', uri)
62
63     for node in parent.childNodes:
64       if node.nodeType == Node.ELEMENT_NODE:
65         self.rebase(node)
66
67 # convert type="html" to type="plain" or type="xhtml" as appropriate
68 def retype(parent):
69   for node in parent.childNodes:
70     if node.nodeType == Node.ELEMENT_NODE:
71
72       if node.hasAttribute('type') and node.getAttribute('type') == 'html':
73         if len(node.childNodes)==0:
74           node.removeAttribute('type')
75         elif len(node.childNodes)==1:
76
77           # replace html entity defs with utf-8
78           chunks=re.split('&(\w+);', node.childNodes[0].nodeValue)
79           for i in range(1,len(chunks),2):
80              if chunks[i] in ['amp', 'lt', 'gt', 'apos', 'quot']:
81                chunks[i] ='&' + chunks[i] +';'
82              elif chunks[i] in name2codepoint:
83                chunks[i]=unichr(name2codepoint[chunks[i]])
84              else:
85                chunks[i]='&' + chunks[i] + ';'
86           text = u"".join(chunks)
87
88           try:
89             # see if the resulting text is a well-formed XML fragment
90             div = '<div xmlns="http://www.w3.org/1999/xhtml">%s</div>'
91             data = minidom.parseString((div % text.encode('utf-8')))
92
93             if text.find('<') < 0:
94               # plain text
95               node.removeAttribute('type')
96               text = data.documentElement.childNodes[0].nodeValue
97               node.childNodes[0].replaceWholeText(text)
98
99             elif len(text) > 80:
100               # xhtml
101               node.setAttribute('type', 'xhtml')
102               node.removeChild(node.childNodes[0])
103               node.appendChild(data.documentElement)
104
105           except ExpatError:
106             # leave as html
107             pass
108
109       else:
110         # recurse
111         retype(node)
112
113   if parent.nodeName == 'entry':
114     relativize(parent)
115
116 if __name__ == '__main__':
117
118   # run styler on each file mention on the command line
119   import sys
120   for feed in sys.argv[1:]:
121     doc = minidom.parse(feed)
122     doc.normalize()
123     retype(doc.documentElement)
124     open(feed,'w').write(doc.toxml('utf-8'))