6 """ |
6 """ |
7 Module implementing a class to read XBEL bookmark files. |
7 Module implementing a class to read XBEL bookmark files. |
8 """ |
8 """ |
9 |
9 |
10 from PyQt6.QtCore import ( |
10 from PyQt6.QtCore import ( |
11 QXmlStreamReader, QXmlStreamEntityResolver, QIODevice, QFile, |
11 QXmlStreamReader, |
12 QCoreApplication, QXmlStreamNamespaceDeclaration, QDateTime, Qt |
12 QXmlStreamEntityResolver, |
|
13 QIODevice, |
|
14 QFile, |
|
15 QCoreApplication, |
|
16 QXmlStreamNamespaceDeclaration, |
|
17 QDateTime, |
|
18 Qt, |
13 ) |
19 ) |
14 |
20 |
15 from .BookmarkNode import BookmarkNode |
21 from .BookmarkNode import BookmarkNode |
16 |
22 |
17 |
23 |
18 class XmlEntityResolver(QXmlStreamEntityResolver): |
24 class XmlEntityResolver(QXmlStreamEntityResolver): |
19 """ |
25 """ |
20 Class implementing an XML entity resolver for bookmark files. |
26 Class implementing an XML entity resolver for bookmark files. |
21 """ |
27 """ |
|
28 |
22 def resolveUndeclaredEntity(self, entity): |
29 def resolveUndeclaredEntity(self, entity): |
23 """ |
30 """ |
24 Public method to resolve undeclared entities. |
31 Public method to resolve undeclared entities. |
25 |
32 |
26 @param entity entity to be resolved (string) |
33 @param entity entity to be resolved (string) |
27 @return resolved entity (string) |
34 @return resolved entity (string) |
28 """ |
35 """ |
29 if entity == "nbsp": |
36 if entity == "nbsp": |
30 return " " |
37 return " " |
58 f = QFile(fileNameOrDevice) |
66 f = QFile(fileNameOrDevice) |
59 if not f.exists(): |
67 if not f.exists(): |
60 return BookmarkNode(BookmarkNode.Root) |
68 return BookmarkNode(BookmarkNode.Root) |
61 f.open(QIODevice.OpenModeFlag.ReadOnly) |
69 f.open(QIODevice.OpenModeFlag.ReadOnly) |
62 self.setDevice(f) |
70 self.setDevice(f) |
63 |
71 |
64 root = BookmarkNode(BookmarkNode.Root) |
72 root = BookmarkNode(BookmarkNode.Root) |
65 while not self.atEnd(): |
73 while not self.atEnd(): |
66 self.readNext() |
74 self.readNext() |
67 if self.isStartElement(): |
75 if self.isStartElement(): |
68 version = self.attributes().value("version") |
76 version = self.attributes().value("version") |
69 if ( |
77 if self.name() == "xbel" and (not version or version == "1.0"): |
70 self.name() == "xbel" and |
|
71 (not version or version == "1.0") |
|
72 ): |
|
73 self.__readXBEL(root) |
78 self.__readXBEL(root) |
74 else: |
79 else: |
75 self.raiseError(QCoreApplication.translate( |
80 self.raiseError( |
76 "XbelReader", |
81 QCoreApplication.translate( |
77 "The file is not an XBEL version 1.0 file.")) |
82 "XbelReader", "The file is not an XBEL version 1.0 file." |
78 |
83 ) |
|
84 ) |
|
85 |
79 return root |
86 return root |
80 |
87 |
81 def __readXBEL(self, node): |
88 def __readXBEL(self, node): |
82 """ |
89 """ |
83 Private method to read and parse the XBEL file. |
90 Private method to read and parse the XBEL file. |
84 |
91 |
85 @param node reference to the node to attach to (BookmarkNode) |
92 @param node reference to the node to attach to (BookmarkNode) |
86 """ |
93 """ |
87 if not self.isStartElement() and self.name() != "xbel": |
94 if not self.isStartElement() and self.name() != "xbel": |
88 return |
95 return |
89 |
96 |
90 while not self.atEnd(): |
97 while not self.atEnd(): |
91 self.readNext() |
98 self.readNext() |
92 if self.isEndElement(): |
99 if self.isEndElement(): |
93 break |
100 break |
94 |
101 |
95 if self.isStartElement(): |
102 if self.isStartElement(): |
96 if self.name() == "folder": |
103 if self.name() == "folder": |
97 self.__readFolder(node) |
104 self.__readFolder(node) |
98 elif self.name() == "bookmark": |
105 elif self.name() == "bookmark": |
99 self.__readBookmarkNode(node) |
106 self.__readBookmarkNode(node) |
100 elif self.name() == "separator": |
107 elif self.name() == "separator": |
101 self.__readSeparator(node) |
108 self.__readSeparator(node) |
102 else: |
109 else: |
103 self.__skipUnknownElement() |
110 self.__skipUnknownElement() |
104 |
111 |
105 def __readFolder(self, node): |
112 def __readFolder(self, node): |
106 """ |
113 """ |
107 Private method to read and parse a folder subtree. |
114 Private method to read and parse a folder subtree. |
108 |
115 |
109 @param node reference to the node to attach to (BookmarkNode) |
116 @param node reference to the node to attach to (BookmarkNode) |
110 """ |
117 """ |
111 if not self.isStartElement() and self.name() != "folder": |
118 if not self.isStartElement() and self.name() != "folder": |
112 return |
119 return |
113 |
120 |
114 folder = BookmarkNode(BookmarkNode.Folder, node) |
121 folder = BookmarkNode(BookmarkNode.Folder, node) |
115 folder.expanded = self.attributes().value("folded") == "no" |
122 folder.expanded = self.attributes().value("folded") == "no" |
116 folder.added = QDateTime.fromString( |
123 folder.added = QDateTime.fromString( |
117 self.attributes().value("added"), Qt.DateFormat.ISODate) |
124 self.attributes().value("added"), Qt.DateFormat.ISODate |
118 |
125 ) |
119 while not self.atEnd(): |
126 |
120 self.readNext() |
127 while not self.atEnd(): |
121 if self.isEndElement(): |
128 self.readNext() |
122 break |
129 if self.isEndElement(): |
123 |
130 break |
|
131 |
124 if self.isStartElement(): |
132 if self.isStartElement(): |
125 if self.name() == "title": |
133 if self.name() == "title": |
126 self.__readTitle(folder) |
134 self.__readTitle(folder) |
127 elif self.name() == "desc": |
135 elif self.name() == "desc": |
128 self.__readDescription(folder) |
136 self.__readDescription(folder) |
134 self.__readSeparator(folder) |
142 self.__readSeparator(folder) |
135 elif self.name() == "info": |
143 elif self.name() == "info": |
136 self.__readInfo() |
144 self.__readInfo() |
137 else: |
145 else: |
138 self.__skipUnknownElement() |
146 self.__skipUnknownElement() |
139 |
147 |
140 def __readTitle(self, node): |
148 def __readTitle(self, node): |
141 """ |
149 """ |
142 Private method to read the title element. |
150 Private method to read the title element. |
143 |
151 |
144 @param node reference to the bookmark node title belongs to |
152 @param node reference to the bookmark node title belongs to |
145 (BookmarkNode) |
153 (BookmarkNode) |
146 """ |
154 """ |
147 if not self.isStartElement() and self.name() != "title": |
155 if not self.isStartElement() and self.name() != "title": |
148 return |
156 return |
149 |
157 |
150 node.title = self.readElementText() |
158 node.title = self.readElementText() |
151 |
159 |
152 def __readDescription(self, node): |
160 def __readDescription(self, node): |
153 """ |
161 """ |
154 Private method to read the desc element. |
162 Private method to read the desc element. |
155 |
163 |
156 @param node reference to the bookmark node desc belongs to |
164 @param node reference to the bookmark node desc belongs to |
157 (BookmarkNode) |
165 (BookmarkNode) |
158 """ |
166 """ |
159 if not self.isStartElement() and self.name() != "desc": |
167 if not self.isStartElement() and self.name() != "desc": |
160 return |
168 return |
161 |
169 |
162 node.desc = self.readElementText() |
170 node.desc = self.readElementText() |
163 |
171 |
164 def __readSeparator(self, node): |
172 def __readSeparator(self, node): |
165 """ |
173 """ |
166 Private method to read a separator element. |
174 Private method to read a separator element. |
167 |
175 |
168 @param node reference to the bookmark node the separator belongs to |
176 @param node reference to the bookmark node the separator belongs to |
169 (BookmarkNode) |
177 (BookmarkNode) |
170 """ |
178 """ |
171 sep = BookmarkNode(BookmarkNode.Separator, node) |
179 sep = BookmarkNode(BookmarkNode.Separator, node) |
172 sep.added = QDateTime.fromString( |
180 sep.added = QDateTime.fromString( |
173 self.attributes().value("added"), Qt.DateFormat.ISODate) |
181 self.attributes().value("added"), Qt.DateFormat.ISODate |
174 |
182 ) |
|
183 |
175 # empty elements have a start and end element |
184 # empty elements have a start and end element |
176 while not self.atEnd(): |
185 while not self.atEnd(): |
177 self.readNext() |
186 self.readNext() |
178 if self.isEndElement(): |
187 if self.isEndElement(): |
179 break |
188 break |
180 |
189 |
181 if self.isStartElement(): |
190 if self.isStartElement(): |
182 if self.name() == "info": |
191 if self.name() == "info": |
183 self.__readInfo() |
192 self.__readInfo() |
184 else: |
193 else: |
185 self.__skipUnknownElement() |
194 self.__skipUnknownElement() |
186 |
195 |
187 def __readBookmarkNode(self, node): |
196 def __readBookmarkNode(self, node): |
188 """ |
197 """ |
189 Private method to read and parse a bookmark subtree. |
198 Private method to read and parse a bookmark subtree. |
190 |
199 |
191 @param node reference to the node to attach to (BookmarkNode) |
200 @param node reference to the node to attach to (BookmarkNode) |
192 """ |
201 """ |
193 if not self.isStartElement() and self.name() != "bookmark": |
202 if not self.isStartElement() and self.name() != "bookmark": |
194 return |
203 return |
195 |
204 |
196 bookmark = BookmarkNode(BookmarkNode.Bookmark, node) |
205 bookmark = BookmarkNode(BookmarkNode.Bookmark, node) |
197 bookmark.url = self.attributes().value("href") |
206 bookmark.url = self.attributes().value("href") |
198 bookmark.added = QDateTime.fromString( |
207 bookmark.added = QDateTime.fromString( |
199 self.attributes().value("added"), Qt.DateFormat.ISODate) |
208 self.attributes().value("added"), Qt.DateFormat.ISODate |
|
209 ) |
200 bookmark.modified = QDateTime.fromString( |
210 bookmark.modified = QDateTime.fromString( |
201 self.attributes().value("modified"), Qt.DateFormat.ISODate) |
211 self.attributes().value("modified"), Qt.DateFormat.ISODate |
|
212 ) |
202 bookmark.visited = QDateTime.fromString( |
213 bookmark.visited = QDateTime.fromString( |
203 self.attributes().value("visited"), Qt.DateFormat.ISODate) |
214 self.attributes().value("visited"), Qt.DateFormat.ISODate |
|
215 ) |
204 try: |
216 try: |
205 bookmark.visitCount = int(self.attributes().value("visitCount")) |
217 bookmark.visitCount = int(self.attributes().value("visitCount")) |
206 except ValueError: |
218 except ValueError: |
207 bookmark.visitCount = 0 |
219 bookmark.visitCount = 0 |
208 |
220 |
209 while not self.atEnd(): |
221 while not self.atEnd(): |
210 self.readNext() |
222 self.readNext() |
211 if self.isEndElement(): |
223 if self.isEndElement(): |
212 break |
224 break |
213 |
225 |
214 if self.isStartElement(): |
226 if self.isStartElement(): |
215 if self.name() == "title": |
227 if self.name() == "title": |
216 self.__readTitle(bookmark) |
228 self.__readTitle(bookmark) |
217 elif self.name() == "desc": |
229 elif self.name() == "desc": |
218 self.__readDescription(bookmark) |
230 self.__readDescription(bookmark) |
219 elif self.name() == "info": |
231 elif self.name() == "info": |
220 self.__readInfo() |
232 self.__readInfo() |
221 else: |
233 else: |
222 self.__skipUnknownElement() |
234 self.__skipUnknownElement() |
223 |
235 |
224 if not bookmark.title: |
236 if not bookmark.title: |
225 bookmark.title = QCoreApplication.translate( |
237 bookmark.title = QCoreApplication.translate("XbelReader", "Unknown title") |
226 "XbelReader", "Unknown title") |
238 |
227 |
|
228 def __readInfo(self): |
239 def __readInfo(self): |
229 """ |
240 """ |
230 Private method to read and parse an info subtree. |
241 Private method to read and parse an info subtree. |
231 """ |
242 """ |
232 self.addExtraNamespaceDeclaration(QXmlStreamNamespaceDeclaration( |
243 self.addExtraNamespaceDeclaration( |
233 "bookmark", "http://www.python.org")) |
244 QXmlStreamNamespaceDeclaration("bookmark", "http://www.python.org") |
|
245 ) |
234 self.skipCurrentElement() |
246 self.skipCurrentElement() |
235 |
247 |
236 def __skipUnknownElement(self): |
248 def __skipUnknownElement(self): |
237 """ |
249 """ |
238 Private method to skip over all unknown elements. |
250 Private method to skip over all unknown elements. |
239 """ |
251 """ |
240 self.skipCurrentElement() |
252 self.skipCurrentElement() |