Warning, file /office/calligra/libs/store/KoXmlWriter.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002    Copyright (C) 2004 David Faure <faure@kde.org>
0003    Copyright (C) 2007 Thomas Zander <zander@kde.org>
0004    Copyright (C) 2011 Lukáš Tvrdý <lukas.tvrdy@ixonos.com>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #ifndef XMLWRITER_H
0023 #define XMLWRITER_H
0024 
0025 #include <QMap>
0026 #include <QIODevice>
0027 #include "kostore_export.h"
0028 
0029 /**
0030  * A class for writing out XML (to any QIODevice), with a special attention on performance.
0031  * The XML is being written out along the way, which avoids requiring the entire
0032  * document in memory (like QDom does), and avoids using QTextStream at all
0033  * (which in Qt3 has major performance issues when converting to utf8).
0034  */
0035 class KOSTORE_EXPORT KoXmlWriter
0036 {
0037 public:
0038     /**
0039      * Create a KoXmlWriter instance to write out an XML document into
0040      * the given QIODevice.
0041      */
0042     explicit KoXmlWriter(QIODevice* dev, int indentLevel = 0);
0043 
0044     /// Destructor
0045     ~KoXmlWriter();
0046 
0047     QIODevice *device() const;
0048 
0049     /**
0050      * Start the XML document.
0051      * This writes out the \<?xml?\> tag with utf8 encoding, and the DOCTYPE.
0052      * @param rootElemName the name of the root element, used in the DOCTYPE tag.
0053      * @param publicId the public identifier, e.g. "-//OpenOffice.org//DTD OfficeDocument 1.0//EN"
0054      * @param systemId the system identifier, e.g. "office.dtd" or a full URL to it.
0055      */
0056     void startDocument(const char* rootElemName, const char* publicId = 0, const char* systemId = 0);
0057 
0058     /// Call this to terminate an XML document.
0059     void endDocument();
0060 
0061     /**
0062      * Start a new element, as a child of the current element.
0063      * @param tagName the name of the tag. Warning: this string must
0064      * remain alive until endElement, no copy is internally made.
0065      * Usually tagName is a string constant so this is no problem anyway.
0066      * @param indentInside if set to false, there will be no indentation inside
0067      * this tag. This is useful for elements where whitespace matters.
0068      */
0069     void startElement(const char* tagName, bool indentInside = true);
0070 
0071     /**
0072      * Overloaded version of addAttribute( const char*, const char* ),
0073      * which is a bit slower because it needs to convert @p value to utf8 first.
0074      */
0075     inline void addAttribute(const char* attrName, const QString& value) {
0076         addAttribute(attrName, value.toUtf8());
0077     }
0078     /**
0079      * Add an attribute whose value is an integer
0080      */
0081     inline void addAttribute(const char* attrName, int value) {
0082         addAttribute(attrName, QByteArray::number(value));
0083     }
0084     /**
0085      * Add an attribute whose value is an unsigned integer
0086      */
0087     inline void addAttribute(const char* attrName, uint value) {
0088         addAttribute(attrName, QByteArray::number(value));
0089     }
0090     /**
0091      * Add an attribute whose value is an bool
0092      * It is written as "true" or "false" based on value
0093      */
0094     inline void addAttribute(const char* attrName, bool value) {
0095         addAttribute(attrName, value ? "true" : "false");
0096     }
0097     /**
0098      * Add an attribute whose value is a floating point number
0099      * The number is written out with the highest possible precision
0100      * (unlike QString::number and setNum, which default to 6 digits)
0101      */
0102     void addAttribute(const char* attrName, double value);
0103     /**
0104      * Add an attribute whose value is a floating point number
0105      * The number is written out with the highest possible precision
0106      * (unlike QString::number and setNum, which default to 6 digits)
0107      */
0108     void addAttribute(const char* attrName, float value);
0109     /**
0110      * Add an attribute which represents a distance, measured in pt
0111      * The number is written out with the highest possible precision
0112      * (unlike QString::number and setNum, which default to 6 digits),
0113      * and the unit name ("pt") is appended to it.
0114      */
0115     void addAttributePt(const char* attrName, double value);
0116     /**
0117      * Add an attribute which represents a distance, measured in pt
0118      * The number is written out with the highest possible precision
0119      * (unlike QString::number and setNum, which default to 6 digits),
0120      * and the unit name ("pt") is appended to it.
0121      */
0122     void addAttributePt(const char* attrName, float value);
0123 
0124     /// Overloaded version of the one taking a const char* argument, for convenience
0125     void addAttribute(const char* attrName, const QByteArray& value);
0126 
0127     /**
0128      * Add an attribute to the current element.
0129      */
0130     void addAttribute(const char* attrName, const char* value);
0131     /**
0132      * Terminate the current element. After this you should start a new one (sibling),
0133      * add a sibling text node, or close another one (end of siblings).
0134      */
0135     void endElement();
0136     /**
0137      * Overloaded version of addTextNode( const char* ),
0138      * which is a bit slower because it needs to convert @p str to utf8 first.
0139      */
0140     inline void addTextNode(const QString& str) {
0141         addTextNode(str.toUtf8());
0142     }
0143     /// Overloaded version of the one taking a const char* argument
0144     void addTextNode(const QByteArray& cstr);
0145     /**
0146      * @brief Adds a text node as a child of the current element.
0147      *
0148      * This is appends the literal content of @p str to the contents of the element.
0149      * E.g. addTextNode( "foo" ) inside a \<p\> element gives \<p\>foo\</p\>,
0150      * and startElement( "b" ); endElement( "b" ); addTextNode( "foo" ) gives \<p\>\<b/\>foo\</p\>
0151      */
0152     void addTextNode(const char* cstr);
0153 
0154     /**
0155      * @brief Adds a processing instruction
0156      *
0157      * This writes a processing instruction, like <?foo bar blah?>, where foo
0158      * is the target, and the rest is the data.
0159      *
0160      * Processing instructions are used in XML to keep processor-specific
0161      * information in the text of the document.
0162      */
0163     void addProcessingInstruction(const char* cstr);
0164 
0165     /**
0166      * This is quite a special-purpose method, not for everyday use.
0167      * It adds a complete element (with its attributes and child elements)
0168      * as a child of the current element. The string is supposed to be escaped
0169      * for XML already, so it will usually come from another KoXmlWriter.
0170      */
0171     void addCompleteElement(const char* cstr);
0172 
0173     /**
0174      * This is quite a special-purpose method, not for everyday use.
0175      * It adds a complete element (with its attributes and child elements)
0176      * as a child of the current element. The iodevice is supposed to be escaped
0177      * for XML already, so it will usually come from another KoXmlWriter.
0178      * This is usually used with KTempFile.
0179      */
0180     void addCompleteElement(QIODevice* dev);
0181 
0182     // #### Maybe we want to subclass KoXmlWriter for manifest files.
0183     /**
0184      * Special helper for writing "manifest" files
0185      * This is equivalent to startElement/2*addAttribute/endElement
0186      * This API will probably have to change (or not be used anymore)
0187      * when we add support for encrypting/signing.
0188      * @note OASIS-specific
0189      */
0190     void addManifestEntry(const QString& fullPath, const QString& mediaType);
0191 
0192     /**
0193      * Special helper for writing config item into settings.xml
0194      * @note OASIS-specific
0195      */
0196     void addConfigItem(const QString & configName, const QString& value);
0197     /// @note OASIS-specific
0198     void addConfigItem(const QString & configName, bool value);
0199     /// @note OASIS-specific
0200     void addConfigItem(const QString & configName, int value);
0201     /// @note OASIS-specific
0202     void addConfigItem(const QString & configName, double value);
0203     /// @note OASIS-specific
0204     void addConfigItem(const QString & configName, float value);
0205     /// @note OASIS-specific
0206     void addConfigItem(const QString & configName, long value);
0207     /// @note OASIS-specific
0208     void addConfigItem(const QString & configName, short value);
0209 
0210     // TODO addConfigItem for datetime and base64Binary
0211 
0212     /**
0213      * @brief Adds a text span as nodes of the current element.
0214      *
0215      * Unlike KoXmlWriter::addTextNode it handles tabulations, linebreaks,
0216      * and multiple spaces by using the appropriate OASIS tags.
0217      *
0218      * @param text the text to write
0219      *
0220      * @note OASIS-specific
0221      */
0222     void addTextSpan(const QString& text);
0223     /**
0224      * Overloaded version of addTextSpan which takes an additional tabCache map.
0225      * @param text the text to write
0226      * @param tabCache optional map allowing to find a tab for a given character index
0227      * @note OASIS-specific
0228      */
0229     void addTextSpan(const QString& text, const QMap<int, int>& tabCache);
0230 
0231     /**
0232      * @return the current indentation level.
0233      * Useful when creating a sub-KoXmlWriter (see addCompleteElement)
0234      */
0235     int indentLevel() const;
0236 
0237     /**
0238      * Return all the open tags at this time, root element first.
0239      */
0240     QList<const char*> tagHierarchy() const;
0241 
0242     /**
0243      * Return the so far written XML as string for debugging purposes.
0244      */
0245     QString toString() const;
0246 
0247 private:
0248     struct Tag {
0249         Tag(const char* t = 0, bool ind = true)
0250                 : tagName(t), hasChildren(false), lastChildIsText(false),
0251                 openingTagClosed(false), indentInside(ind) {}
0252         Tag(const Tag &original)
0253         {
0254             tagName = original.tagName;
0255             hasChildren = original.hasChildren;
0256             lastChildIsText = original.lastChildIsText;
0257             openingTagClosed = original.openingTagClosed;
0258             indentInside = original.indentInside;
0259         }
0260         const char* tagName;
0261         bool hasChildren : 1; ///< element or text children
0262         bool lastChildIsText : 1; ///< last child is a text node
0263         bool openingTagClosed : 1; ///< true once the '\>' in \<tag a="b"\> is written out
0264         bool indentInside : 1; ///< whether to indent the contents of this tag
0265     };
0266 
0267     /// Write out \n followed by the number of spaces required.
0268     void writeIndent();
0269 
0270     // writeCString is much faster than writeString.
0271     // Try to use it as much as possible, especially with constants.
0272     void writeString(const QString& str);
0273 
0274     // TODO check return value!!!
0275     inline void writeCString(const char* cstr) {
0276         device()->write(cstr, qstrlen(cstr));
0277     }
0278     inline void writeChar(char c) {
0279         device()->putChar(c);
0280     }
0281     inline void closeStartElement(Tag& tag) {
0282         if (!tag.openingTagClosed) {
0283             tag.openingTagClosed = true;
0284             writeChar('>');
0285         }
0286     }
0287     char* escapeForXML(const char* source, int length) const;
0288     bool prepareForChild();
0289     void prepareForTextNode();
0290     void init();
0291 
0292     class Private;
0293     Private * const d;
0294 
0295     KoXmlWriter(const KoXmlWriter &);   // forbidden
0296     KoXmlWriter& operator=(const KoXmlWriter &);   // forbidden
0297 };
0298 
0299 #endif /* XMLWRITER_H */
0300