1 | /* This file is part of the KDE project |
2 | Copyright (C) 2005-2006 Ariya Hidayat <ariya@kde.org> |
3 | |
4 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2 of the License, or (at your option) any later version. |
8 | |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Library General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Library General Public License |
15 | along with this library; see the file COPYING.LIB. If not, write to |
16 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
17 | Boston, MA 02110-1301, USA. |
18 | */ |
19 | |
20 | #ifndef KO_XMLREADER_H |
21 | #define KO_XMLREADER_H |
22 | |
23 | // KOXML_USE_QDOM is defined there |
24 | #include "KoXmlReaderForward.h" |
25 | |
26 | #include "koodf_export.h" |
27 | |
28 | #include <QPair> |
29 | #include <QtXml> |
30 | #include <QDomDocument> |
31 | |
32 | class QIODevice; |
33 | class QTextDecoder; |
34 | |
35 | #ifdef KOXML_USE_QDOM |
36 | |
37 | typedef QDomNode KoXmlNode; |
38 | typedef QDomElement KoXmlElement; |
39 | typedef QDomText KoXmlText; |
40 | typedef QDomCDATASection KoXmlCDATASection; |
41 | typedef QDomDocumentType KoXmlDocumentType; |
42 | typedef QDomDocument KoXmlDocument; |
43 | |
44 | #else |
45 | |
46 | class QString; |
47 | class QXmlStreamReader; |
48 | |
49 | class KoXmlNode; |
50 | class KoXmlText; |
51 | class KoXmlCDATASection; |
52 | class KoXmlDocumentType; |
53 | class KoXmlDocument; |
54 | class KoXmlNodeData; |
55 | |
56 | /** |
57 | * The office-text-content-prelude type. |
58 | */ |
59 | enum KoXmlNamedItemType { |
60 | KoXmlTextContentPrelude ///< office-text-content-prelude |
61 | //KoXmlTextContentMain, ///< office-text-content-main |
62 | //KoXmlTextContentEpilogue ///< office-text-content-epilogue |
63 | }; |
64 | |
65 | /** |
66 | * KoXmlNode represents a node in a DOM tree. |
67 | * |
68 | * KoXmlNode is a base class for KoXmlElement, KoXmlText. |
69 | * Often, these subclasses are used for getting the data instead of KoXmlNode. |
70 | * However, as base class, KoXmlNode is very helpful when for example iterating |
71 | * all child nodes within one parent node. |
72 | * |
73 | * KoXmlNode implements an explicit sharing, a node shares its data with |
74 | * other copies (if exist). |
75 | * |
76 | * XXX: DO NOT ADD CONVENIENCE API HERE BECAUSE THIS CLASS MUST REMAIN COMPATIBLE WITH QDOMNODE! |
77 | * |
78 | * @author Ariya Hidayat <ariya@kde.org> |
79 | */ |
80 | class KOODF_EXPORT KoXmlNode |
81 | { |
82 | public: |
83 | |
84 | enum NodeType { |
85 | NullNode = 0, |
86 | ElementNode, |
87 | TextNode, |
88 | CDATASectionNode, |
89 | ProcessingInstructionNode, |
90 | DocumentNode, |
91 | DocumentTypeNode |
92 | }; |
93 | |
94 | KoXmlNode(); |
95 | KoXmlNode(const KoXmlNode& node); |
96 | KoXmlNode& operator=(const KoXmlNode& node); |
97 | bool operator== (const KoXmlNode&) const; |
98 | bool operator!= (const KoXmlNode&) const; |
99 | virtual ~KoXmlNode(); |
100 | |
101 | virtual KoXmlNode::NodeType nodeType() const; |
102 | virtual bool isNull() const; |
103 | virtual bool isElement() const; |
104 | virtual bool isText() const; |
105 | virtual bool isCDATASection() const; |
106 | virtual bool isDocument() const; |
107 | virtual bool isDocumentType() const; |
108 | |
109 | virtual void clear(); |
110 | KoXmlElement toElement() const; |
111 | KoXmlText toText() const; |
112 | KoXmlCDATASection toCDATASection() const; |
113 | KoXmlDocument toDocument() const; |
114 | |
115 | virtual QString nodeName() const; |
116 | virtual QString namespaceURI() const; |
117 | virtual QString prefix() const; |
118 | virtual QString localName() const; |
119 | |
120 | KoXmlDocument ownerDocument() const; |
121 | KoXmlNode parentNode() const; |
122 | |
123 | bool hasChildNodes() const; |
124 | KoXmlNode firstChild() const; |
125 | KoXmlNode lastChild() const; |
126 | KoXmlNode nextSibling() const; |
127 | KoXmlNode previousSibling() const; |
128 | |
129 | KoXmlElement firstChildElement() const; |
130 | |
131 | // equivalent to node.childNodes().count() if node is a QDomNode instance |
132 | int childNodesCount() const; |
133 | |
134 | // workaround to get and iterate over all attributes |
135 | QStringList attributeNames() const; |
136 | QList< QPair<QString, QString> > attributeFullNames() const; |
137 | |
138 | KoXmlNode namedItem(const QString& name) const; |
139 | KoXmlNode namedItemNS(const QString& nsURI, const QString& name) const; |
140 | KoXmlNode namedItemNS(const QString& nsURI, const QString& name, KoXmlNamedItemType type) const; |
141 | |
142 | /** |
143 | * Loads all child nodes (if any) of this node. Normally you do not need |
144 | * to call this function as the child nodes will be automatically |
145 | * loaded when necessary. |
146 | */ |
147 | void load(int depth = 1); |
148 | |
149 | /** |
150 | * Releases all child nodes of this node. |
151 | */ |
152 | void unload(); |
153 | |
154 | // compatibility |
155 | /** |
156 | * @internal do not call directly |
157 | * Use KoXml::asQDomDocument(), KoXml::asQDomElement() or KoXml::asQDomNode() instead |
158 | */ |
159 | void asQDomNode(QDomDocument& ownerDoc) const; |
160 | |
161 | protected: |
162 | KoXmlNodeData* d; |
163 | explicit KoXmlNode(KoXmlNodeData*); |
164 | }; |
165 | |
166 | /** |
167 | * KoXmlElement represents a tag element in a DOM tree. |
168 | * |
169 | * KoXmlElement holds information about an XML tag, along with its attributes. |
170 | * |
171 | * @author Ariya Hidayat <ariya@kde.org> |
172 | */ |
173 | |
174 | class KOODF_EXPORT KoXmlElement: public KoXmlNode |
175 | { |
176 | public: |
177 | KoXmlElement(); |
178 | KoXmlElement(const KoXmlElement& element); |
179 | KoXmlElement& operator=(const KoXmlElement& element); |
180 | virtual ~KoXmlElement(); |
181 | bool operator== (const KoXmlElement&) const; |
182 | bool operator!= (const KoXmlElement&) const; |
183 | |
184 | QString tagName() const; |
185 | QString text() const; |
186 | |
187 | QString attribute(const QString& name) const; |
188 | QString attribute(const QString& name, const QString& defaultValue) const; |
189 | QString attributeNS(const QString& namespaceURI, const QString& localName, |
190 | const QString& defaultValue = QString()) const; |
191 | bool hasAttribute(const QString& name) const; |
192 | bool hasAttributeNS(const QString& namespaceURI, const QString& localName) const; |
193 | |
194 | private: |
195 | friend class KoXmlNode; |
196 | friend class KoXmlDocument; |
197 | explicit KoXmlElement(KoXmlNodeData*); |
198 | }; |
199 | |
200 | /** |
201 | * KoXmlText represents a text in a DOM tree. |
202 | * @author Ariya Hidayat <ariya@kde.org> |
203 | */ |
204 | class KOODF_EXPORT KoXmlText: public KoXmlNode |
205 | { |
206 | public: |
207 | KoXmlText(); |
208 | KoXmlText(const KoXmlText& text); |
209 | KoXmlText& operator=(const KoXmlText& text); |
210 | virtual ~KoXmlText(); |
211 | |
212 | QString data() const; |
213 | void setData(const QString& data); |
214 | virtual bool isText() const; |
215 | |
216 | private: |
217 | friend class KoXmlNode; |
218 | friend class KoXmlCDATASection; |
219 | friend class KoXmlDocument; |
220 | explicit KoXmlText(KoXmlNodeData*); |
221 | }; |
222 | |
223 | /** |
224 | * KoXmlCDATASection represents a CDATA section in a DOM tree. |
225 | * @author Ariya Hidayat <ariya@kde.org> |
226 | */ |
227 | class KOODF_EXPORT KoXmlCDATASection: public KoXmlText |
228 | { |
229 | public: |
230 | KoXmlCDATASection(); |
231 | KoXmlCDATASection(const KoXmlCDATASection& cdata); |
232 | KoXmlCDATASection& operator=(const KoXmlCDATASection& cdata); |
233 | virtual ~KoXmlCDATASection(); |
234 | |
235 | virtual bool isCDATASection() const; |
236 | |
237 | private: |
238 | friend class KoXmlNode; |
239 | friend class KoXmlDocument; |
240 | explicit KoXmlCDATASection(KoXmlNodeData*); |
241 | }; |
242 | |
243 | /** |
244 | * KoXmlDocumentType represents the DTD of the document. At the moment, |
245 | * it can used only to get the document type, i.e. no support for |
246 | * entities etc. |
247 | * |
248 | * @author Ariya Hidayat <ariya@kde.org> |
249 | */ |
250 | |
251 | class KOODF_EXPORT KoXmlDocumentType: public KoXmlNode |
252 | { |
253 | public: |
254 | KoXmlDocumentType(); |
255 | KoXmlDocumentType(const KoXmlDocumentType&); |
256 | KoXmlDocumentType& operator=(const KoXmlDocumentType&); |
257 | virtual ~KoXmlDocumentType(); |
258 | |
259 | QString name() const; |
260 | |
261 | private: |
262 | friend class KoXmlNode; |
263 | friend class KoXmlDocument; |
264 | explicit KoXmlDocumentType(KoXmlNodeData*); |
265 | }; |
266 | |
267 | |
268 | /** |
269 | * KoXmlDocument represents an XML document, structured in a DOM tree. |
270 | * |
271 | * KoXmlDocument is designed to be memory efficient. Unlike QDomDocument from |
272 | * Qt's XML module, KoXmlDocument does not store all nodes in the DOM tree. |
273 | * Some nodes will be loaded and parsed on-demand only. |
274 | * |
275 | * KoXmlDocument is read-only, you can not modify its content. |
276 | * |
277 | * @author Ariya Hidayat <ariya@kde.org> |
278 | */ |
279 | |
280 | class KOODF_EXPORT KoXmlDocument: public KoXmlNode |
281 | { |
282 | public: |
283 | explicit KoXmlDocument(bool stripSpaces = false); |
284 | KoXmlDocument(const KoXmlDocument& node); |
285 | KoXmlDocument& operator=(const KoXmlDocument& node); |
286 | bool operator==(const KoXmlDocument&) const; |
287 | bool operator!=(const KoXmlDocument&) const; |
288 | virtual ~KoXmlDocument(); |
289 | |
290 | KoXmlElement documentElement() const; |
291 | |
292 | KoXmlDocumentType doctype() const; |
293 | |
294 | virtual QString nodeName() const; |
295 | virtual void clear(); |
296 | |
297 | bool setContent(QIODevice* device, bool namespaceProcessing, |
298 | QString* errorMsg = 0, int* errorLine = 0, int* errorColumn = 0); |
299 | bool setContent(QIODevice* device, |
300 | QString* errorMsg = 0, int* errorLine = 0, int* errorColumn = 0); |
301 | bool setContent(QXmlStreamReader *reader, |
302 | QString* errorMsg = 0, int* errorLine = 0, int* errorColumn = 0); |
303 | bool setContent(const QByteArray& text, bool namespaceProcessing, |
304 | QString *errorMsg = 0, int *errorLine = 0, int *errorColumn = 0); |
305 | bool setContent(const QString& text, bool namespaceProcessing, |
306 | QString *errorMsg = 0, int *errorLine = 0, int *errorColumn = 0); |
307 | |
308 | // no namespace processing |
309 | bool setContent(const QString& text, |
310 | QString *errorMsg = 0, int *errorLine = 0, int *errorColumn = 0); |
311 | /** |
312 | * Change the way an XMLDocument will be read: <a> <b/> <a/> |
313 | * if stripSpaces = true then a will only have one child |
314 | * if stripSpaces = false then a will have 3 children. |
315 | */ |
316 | void setWhitespaceStripping(bool stripSpaces); |
317 | |
318 | private: |
319 | friend class KoXmlNode; |
320 | KoXmlDocumentType dt; |
321 | explicit KoXmlDocument(KoXmlNodeData*); |
322 | }; |
323 | |
324 | #endif // KOXML_USE_QDOM |
325 | |
326 | /** |
327 | * This namespace contains a few convenience functions to simplify code using QDom |
328 | * (when loading OASIS documents, in particular). |
329 | * |
330 | * To find the child element with a given name, use KoXml::namedItemNS. |
331 | * |
332 | * To find all child elements with a given name, use |
333 | * QDomElement e; |
334 | * forEachElement( e, parent ) |
335 | * { |
336 | * if ( e.localName() == "..." && e.namespaceURI() == KoXmlNS::... ) |
337 | * { |
338 | * ... |
339 | * } |
340 | * } |
341 | * Note that this means you don't ever need to use QDomNode nor toElement anymore! |
342 | * Also note that localName is the part without the prefix, this is the whole point |
343 | * of namespace-aware methods. |
344 | * |
345 | * To find the attribute with a given name, use QDomElement::attributeNS. |
346 | * |
347 | * Do not use getElementsByTagNameNS, it's recursive (which is never needed in Calligra). |
348 | * Do not use tagName() or nodeName() or prefix(), since the prefix isn't fixed. |
349 | * |
350 | * @author David Faure <faure@kde.org> |
351 | */ |
352 | namespace KoXml |
353 | { |
354 | |
355 | /** |
356 | * A namespace-aware version of QDomNode::namedItem(), |
357 | * which also takes care of casting to a QDomElement. |
358 | * |
359 | * Use this when a domelement is known to have only *one* child element |
360 | * with a given tagname. |
361 | * |
362 | * Note: do *NOT* use getElementsByTagNameNS, it's recursive! |
363 | */ |
364 | KOODF_EXPORT KoXmlElement namedItemNS(const KoXmlNode& node, |
365 | const QString& nsURI, const QString& localName); |
366 | |
367 | /** |
368 | * A namespace-aware version of QDomNode::namedItem(). |
369 | * which also takes care of casting to a QDomElement. |
370 | * |
371 | * Use this when you like to return the first or an invalid |
372 | * KoXmlElement with a known type. |
373 | * |
374 | * This is an optimized version of the namedItemNS above to |
375 | * give fast access to certain sections of the document using |
376 | * the office-text-content-prelude condition as @a KoXmlNamedItemType . |
377 | */ |
378 | KOODF_EXPORT KoXmlElement namedItemNS(const KoXmlNode& node, |
379 | const QString& nsURI, const QString& localName, |
380 | KoXmlNamedItemType type); |
381 | |
382 | /** |
383 | * Explicitly load child nodes of specified node, up to given depth. |
384 | * This function has no effect if QDom is used. |
385 | */ |
386 | KOODF_EXPORT void load(KoXmlNode& node, int depth = 1); |
387 | |
388 | /** |
389 | * Unload child nodes of specified node. |
390 | * This function has no effect if QDom is used. |
391 | */ |
392 | KOODF_EXPORT void unload(KoXmlNode& node); |
393 | |
394 | /** |
395 | * Get the number of child nodes of specified node. |
396 | */ |
397 | KOODF_EXPORT int childNodesCount(const KoXmlNode& node); |
398 | |
399 | /** |
400 | * Return the name of all attributes of specified node. |
401 | */ |
402 | KOODF_EXPORT QStringList attributeNames(const KoXmlNode& node); |
403 | |
404 | /** |
405 | * Convert KoXmlNode classes to the corresponding QDom classes, which has |
406 | * @p ownerDoc as the owner document (QDomDocument instance). |
407 | * The converted @p node (and its children) are added to ownerDoc. |
408 | * |
409 | * NOTE: |
410 | * - If ownerDoc is not empty, this may fail, @see QDomDocument |
411 | * - @p node must not be a KoXmlDocument, use asQDomDocument() |
412 | * |
413 | * @see asQDomDocument, asQDomElement |
414 | */ |
415 | KOODF_EXPORT void asQDomNode(QDomDocument& ownerDoc, const KoXmlNode& node); |
416 | |
417 | /** |
418 | * Convert KoXmlNode classes to the corresponding QDom classes, which has |
419 | * @p ownerDoc as the owner document (QDomDocument instance). |
420 | * The converted @p element (and its children) is added to ownerDoc. |
421 | * |
422 | * NOTE: If ownerDoc is not empty, this may fail, @see QDomDocument |
423 | * |
424 | */ |
425 | KOODF_EXPORT void asQDomElement(QDomDocument& ownerDoc, const KoXmlElement& element); |
426 | |
427 | /** |
428 | * Converts the whole @p document into a QDomDocument |
429 | * If KOXML_USE_QDOM is defined, just returns @p document |
430 | */ |
431 | KOODF_EXPORT QDomDocument asQDomDocument(const KoXmlDocument& document); |
432 | |
433 | /* |
434 | * Load an XML document from specified device to a document. You can of |
435 | * course use it with QFile (which inherits QIODevice). |
436 | * This is much more memory efficient than standard QDomDocument::setContent |
437 | * because the data from the device is buffered, unlike |
438 | * QDomDocument::setContent which just loads everything in memory. |
439 | * |
440 | * Note: it is assumed that the XML uses UTF-8 encoding. |
441 | */ |
442 | KOODF_EXPORT bool setDocument(KoXmlDocument& doc, QIODevice* device, |
443 | bool namespaceProcessing, QString* errorMsg = 0, |
444 | int* errorLine = 0, int* errorColumn = 0); |
445 | } |
446 | |
447 | /** |
448 | * \def forEachElement( elem, parent ) |
449 | * \brief Loop through all child elements of \parent. |
450 | * This convenience macro is used to implement the forEachElement loop. |
451 | * The \elem parameter is a name of a QDomElement variable and the \parent |
452 | * is the name of the parent element. For example: |
453 | * |
454 | * QDomElement e; |
455 | * forEachElement( e, parent ) |
456 | * { |
457 | * kDebug() << e.localName() << " element found."; |
458 | * ... |
459 | * } |
460 | */ |
461 | #define forEachElement( elem, parent ) \ |
462 | for ( KoXmlNode _node = parent.firstChild(); !_node.isNull(); _node = _node.nextSibling() ) \ |
463 | if ( ( elem = _node.toElement() ).isNull() ) {} else |
464 | |
465 | |
466 | #endif // KO_XMLREADER_H |
467 | |