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