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