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
32class QIODevice;
33class QTextDecoder;
34
35#ifdef KOXML_USE_QDOM
36
37typedef QDomNode KoXmlNode;
38typedef QDomElement KoXmlElement;
39typedef QDomText KoXmlText;
40typedef QDomCDATASection KoXmlCDATASection;
41typedef QDomDocumentType KoXmlDocumentType;
42typedef QDomDocument KoXmlDocument;
43
44#else
45
46class QString;
47class QXmlStreamReader;
48
49class KoXmlNode;
50class KoXmlText;
51class KoXmlCDATASection;
52class KoXmlDocumentType;
53class KoXmlDocument;
54class KoXmlNodeData;
55
56/**
57 * The office-text-content-prelude type.
58 */
59enum 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*/
80class KOODF_EXPORT KoXmlNode
81{
82public:
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
161protected:
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
174class KOODF_EXPORT KoXmlElement: public KoXmlNode
175{
176public:
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
194private:
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*/
204class KOODF_EXPORT KoXmlText: public KoXmlNode
205{
206public:
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
216private:
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*/
227class KOODF_EXPORT KoXmlCDATASection: public KoXmlText
228{
229public:
230 KoXmlCDATASection();
231 KoXmlCDATASection(const KoXmlCDATASection& cdata);
232 KoXmlCDATASection& operator=(const KoXmlCDATASection& cdata);
233 virtual ~KoXmlCDATASection();
234
235 virtual bool isCDATASection() const;
236
237private:
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
251class KOODF_EXPORT KoXmlDocumentType: public KoXmlNode
252{
253public:
254 KoXmlDocumentType();
255 KoXmlDocumentType(const KoXmlDocumentType&);
256 KoXmlDocumentType& operator=(const KoXmlDocumentType&);
257 virtual ~KoXmlDocumentType();
258
259 QString name() const;
260
261private:
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
280class KOODF_EXPORT KoXmlDocument: public KoXmlNode
281{
282public:
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
318private:
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 */
352namespace 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 */
364KOODF_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 */
378KOODF_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 */
386KOODF_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 */
392KOODF_EXPORT void unload(KoXmlNode& node);
393
394/**
395 * Get the number of child nodes of specified node.
396 */
397KOODF_EXPORT int childNodesCount(const KoXmlNode& node);
398
399/**
400 * Return the name of all attributes of specified node.
401 */
402KOODF_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 */
415KOODF_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 */
425KOODF_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 */
431KOODF_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 */
442KOODF_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