]> git.phdru.name Git - bookmarks_db.git/blob - bkmk_parser.py
Moved DEFAULT_CHARSET to bkmk_objects.py.
[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 DEFAULT_CHARSET, 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 class BkmkParser(HTMLParser):
41    def __init__(self):
42       HTMLParser.__init__(self)
43
44       self.urls = 0
45       self.objects = 0
46
47       self.charset = None
48       self.recode = None
49
50    def handle_data(self, data):
51       if data:
52          if self.charset and DEFAULT_CHARSET:
53             data = unicode(data, self.charset, "replace").encode(DEFAULT_CHARSET, "xmlcharrefreplace")
54          self.accumulator += data
55
56    # Mozilla - get charset
57    def do_meta(self, attrs):
58       http_equiv = ""
59       content = ""
60
61       for attrname, value in attrs:
62          value = value.strip()
63          if attrname == 'http-equiv':
64             http_equiv = value.lower()
65          elif attrname == 'content':
66             content = value
67
68       if http_equiv == "content-type":
69          try:
70             # extract charset from "text/html; charset=UTF-8"
71             self.charset = content.split('=')[1]
72          except IndexError:
73             pass
74
75    def start_title(self, attrs):
76       if DEFAULT_CHARSET:
77          self.accumulator += '<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=%s">\n' % DEFAULT_CHARSET
78       self.accumulator += "<TITLE>"
79
80    def end_title(self):
81       self.accumulator += "</TITLE>"
82
83    # Start root folder
84    def start_h1(self, attrs):
85       root_folder = Folder()
86       self.current_object = root_folder
87       self.root_folder = root_folder
88       self.current_folder = root_folder
89       self.folder_stack = [root_folder]
90
91       self.root_folder.header = self.accumulator.strip()
92       self.accumulator = ''
93
94    def end_h1(self):
95       accumulator = self.accumulator
96       self.accumulator = ''
97
98       debug("Root folder name: `%s'" % accumulator)
99       self.root_folder.name = accumulator
100
101    # Start a folder
102    def start_h3(self, attrs):
103       last_modified = None
104       for attrname, value in attrs:
105          value = value.strip()
106          if attrname == 'add_date':
107             add_date = value
108          elif attrname == 'last_modified':
109             last_modified = value
110
111       debug("New folder...")
112       folder = Folder(add_date, last_modified=last_modified)
113       self.current_object = folder
114       self.current_folder.append(folder)
115       self.folder_stack.append(folder) # push new folder
116       self.current_folder = folder
117       self.objects += 1
118
119    def end_h3(self):
120       accumulator = self.accumulator
121       self.accumulator = ''
122
123       debug("Folder name: `%s'" % accumulator)
124       self.current_folder.name = accumulator
125
126    # Start a bookmark
127    def start_a(self, attrs):
128       add_date = None
129       last_visit = None
130       last_modified = None
131       keyword = None
132       icon = None
133       charset = None
134
135       for attrname, value in attrs:
136          value = value.strip()
137          if attrname == "href":
138             href = value
139          elif attrname == "add_date":
140             add_date = value
141          elif attrname == "last_visit":
142             last_visit = value
143          elif attrname == "last_modified":
144             last_modified = value
145          elif attrname == "shortcuturl":
146             keyword = value
147          elif attrname == "icon":
148             icon = value
149          elif attrname == "last_charset":
150             charset = value
151
152       debug("Bookmark points to: `%s'" % href)
153       bookmark = Bookmark(href, add_date, last_visit, last_modified,
154          keyword or '', '', icon, charset)
155       self.current_object = bookmark
156       self.current_folder.append(bookmark)
157       self.urls += 1
158       self.objects += 1
159
160    def end_a(self):
161       accumulator = self.accumulator
162       self.accumulator = ''
163
164       debug("Bookmark name: `%s'" % accumulator)
165       bookmark = self.current_folder[-1]
166       bookmark.name = accumulator
167
168    def flush(self):
169       accumulator = self.accumulator
170
171       if accumulator:
172          self.accumulator = ''
173
174          current_object = self.current_object
175          if current_object:
176             current_object.comment += accumulator.strip()
177             debug("Comment: `%s'" % current_object.comment)
178
179    def start_dl(self, attrs):
180       self.flush()
181
182    do_dt = start_dl
183
184    # End of folder
185    def end_dl(self):
186       self.flush()
187       debug("End folder")
188       debug("Folder stack: %s" % dump_names(self.folder_stack))
189       if self.folder_stack:
190          del self.folder_stack[-1] # pop last folder
191          if self.folder_stack:
192             self.current_folder = self.folder_stack[-1]
193          else:
194             debug("FOLDER STACK is EMPTY!!! (1)")
195       else:
196          debug("FOLDER STACK is EMPTY!!! (2)")
197       self.current_object = None
198
199    def close(self):
200       HTMLParser.close(self)
201       if self.folder_stack:
202          raise ValueError, "wrong folder stack: %s" % self.folder_stack
203
204    def do_dd(self, attrs):
205       pass
206
207    do_p = do_dd
208
209    # Start ruler
210    def do_hr(self, attrs):
211       self.flush()
212       debug("Ruler")
213       self.current_folder.append(Ruler())
214       self.current_object = None
215       self.objects += 1
216
217    # BR in comment
218    def do_br(self, attrs):
219       self.accumulator += "<BR>"
220
221    # Allow < in the text
222    def unknown_starttag(self, tag, attrs):
223       self.accumulator += "<%s>" % tag
224
225    # Do not allow unknow end tags
226    def unknown_endtag(self, tag):
227       raise NotImplementedError("Unknow end tag `%s'" % tag)