]> git.phdru.name Git - bookmarks_db.git/blob - bkmk_parser.py
Added __all__.
[bookmarks_db.git] / bkmk_parser.py
1 """Parser for Netscape Navigator's and Mozilla's bookmarks.html
2
3 This file is a part of Bookmarks database and Internet robot.
4 """
5
6 __version__ = "$Revision$"[11:-2]
7 __revision__ = "$Id$"[5:-2]
8 __date__ = "$Date$"[7:-2]
9 __author__ = "Oleg Broytman <phd@phdru.name>"
10 __copyright__ = "Copyright (C) 1997-2011 PhiloSoft Design"
11 __license__ = "GNU GPL"
12
13 __all__ = ['BkmkParser']
14
15
16 import sys, os
17 from m_lib.net.www.html import HTMLParser
18 from bkmk_objects import Folder, Bookmark, Ruler
19
20
21 DEBUG = os.environ.has_key("BKMK_DEBUG")
22
23 if DEBUG:
24    def debug(note):
25       print note
26
27    def dump_names(folder_stack):
28       l = []
29       for object in folder_stack:
30          if object.isFolder:
31             l.append(object.name)
32       return "'%s'" % "' '".join(l)
33
34 else:
35    def debug(note):
36       pass
37    dump_names = debug
38
39
40 DEFAULT_CHARSET = None
41
42 class BkmkParser(HTMLParser):
43    def __init__(self):
44       HTMLParser.__init__(self)
45
46       self.urls = 0
47       self.objects = 0
48
49       self.charset = ""
50       self.recode = None
51
52    def handle_data(self, data):
53       if data:
54          if DEFAULT_CHARSET:
55             data = unicode(data, self.charset, "replace").encode(DEFAULT_CHARSET, "xmlcharrefreplace")
56          self.accumulator += data
57
58    # Mozilla - get charset
59    def do_meta(self, attrs):
60       http_equiv = ""
61       content = ""
62
63       for attrname, value in attrs:
64          value = value.strip()
65          if attrname == 'http-equiv':
66             http_equiv = value.lower()
67          elif attrname == 'content':
68             content = value
69
70       if http_equiv == "content-type":
71          try:
72             # extract charset from "text/html; charset=UTF-8"
73             self.charset = content.split('=')[1]
74          except IndexError:
75             pass
76          else:
77             global DEFAULT_CHARSET
78             DEFAULT_CHARSET = sys.getdefaultencoding()
79             if DEFAULT_CHARSET == "ascii":
80                try:
81                   import locale
82                except ImportError:
83                   pass
84                else:
85                   DEFAULT_CHARSET = locale.getpreferredencoding()
86
87    def start_title(self, attrs):
88       if DEFAULT_CHARSET:
89          self.accumulator += '<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=%s">\n' % DEFAULT_CHARSET
90       self.accumulator += "<TITLE>"
91
92    def end_title(self):
93       self.accumulator += "</TITLE>"
94
95    # Start root folder
96    def start_h1(self, attrs):
97       root_folder = Folder()
98       self.current_object = root_folder
99       self.root_folder = root_folder
100       self.current_folder = root_folder
101       self.folder_stack = [root_folder]
102
103       self.root_folder.header = self.accumulator.strip()
104       self.accumulator = ''
105
106    def end_h1(self):
107       accumulator = self.accumulator
108       self.accumulator = ''
109
110       debug("Root folder name: `%s'" % accumulator)
111       self.root_folder.name = accumulator
112
113    # Start a folder
114    def start_h3(self, attrs):
115       last_modified = None
116       for attrname, value in attrs:
117          value = value.strip()
118          if attrname == 'add_date':
119             add_date = value
120          elif attrname == 'last_modified':
121             last_modified = value
122
123       debug("New folder...")
124       folder = Folder(add_date, last_modified=last_modified)
125       self.current_object = folder
126       self.current_folder.append(folder)
127       self.folder_stack.append(folder) # push new folder
128       self.current_folder = folder
129       self.objects += 1
130
131    def end_h3(self):
132       accumulator = self.accumulator
133       self.accumulator = ''
134
135       debug("Folder name: `%s'" % accumulator)
136       self.current_folder.name = accumulator
137
138    # Start a bookmark
139    def start_a(self, attrs):
140       add_date = None
141       last_visit = None
142       last_modified = None
143       keyword = None
144       icon = None
145       charset = None
146
147       for attrname, value in attrs:
148          value = value.strip()
149          if attrname == "href":
150             href = value
151          elif attrname == "add_date":
152             add_date = value
153          elif attrname == "last_visit":
154             last_visit = value
155          elif attrname == "last_modified":
156             last_modified = value
157          elif attrname == "shortcuturl":
158             keyword = value
159          elif attrname == "icon":
160             icon = value
161          elif attrname == "last_charset":
162             charset = value
163
164       debug("Bookmark points to: `%s'" % href)
165       bookmark = Bookmark(href, add_date, last_visit, last_modified,
166          keyword or '', '', icon, charset)
167       self.current_object = bookmark
168       self.current_folder.append(bookmark)
169       self.urls += 1
170       self.objects += 1
171
172    def end_a(self):
173       accumulator = self.accumulator
174       self.accumulator = ''
175
176       debug("Bookmark name: `%s'" % accumulator)
177       bookmark = self.current_folder[-1]
178       bookmark.name = accumulator
179
180    def flush(self):
181       accumulator = self.accumulator
182
183       if accumulator:
184          self.accumulator = ''
185
186          current_object = self.current_object
187          if current_object:
188             current_object.comment += accumulator.strip()
189             debug("Comment: `%s'" % current_object.comment)
190
191    def start_dl(self, attrs):
192       self.flush()
193
194    do_dt = start_dl
195
196    # End of folder
197    def end_dl(self):
198       self.flush()
199       debug("End folder")
200       debug("Folder stack: %s" % dump_names(self.folder_stack))
201       if self.folder_stack:
202          del self.folder_stack[-1] # pop last folder
203          if self.folder_stack:
204             self.current_folder = self.folder_stack[-1]
205          else:
206             debug("FOLDER STACK is EMPTY!!! (1)")
207       else:
208          debug("FOLDER STACK is EMPTY!!! (2)")
209       self.current_object = None
210
211    def close(self):
212       HTMLParser.close(self)
213       if self.folder_stack:
214          raise ValueError, "wrong folder stack: %s" % self.folder_stack
215
216    def do_dd(self, attrs):
217       pass
218
219    do_p = do_dd
220
221    # Start ruler
222    def do_hr(self, attrs):
223       self.flush()
224       debug("Ruler")
225       self.current_folder.append(Ruler())
226       self.current_object = None
227       self.objects += 1
228
229    # BR in comment
230    def do_br(self, attrs):
231       self.accumulator += "<BR>"
232
233    # Allow < in the text
234    def unknown_starttag(self, tag, attrs):
235       self.accumulator += "<%s>" % tag
236
237    # Do not allow unknow end tags
238    def unknown_endtag(self, tag):
239       raise NotImplementedError("Unknow end tag `%s'" % tag)