Orb/Doxygen/src/xmlwriter.h
changeset 3 d8fccb2cd802
child 4 468f4c8d3d5b
equal deleted inserted replaced
2:932c358ece3e 3:d8fccb2cd802
       
     1 /******************************************************************************
       
     2  *
       
     3  * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4  *
       
     5  * Permission to use, copy, modify, and distribute this software and its
       
     6  * documentation under the terms of the GNU General Public License is hereby 
       
     7  * granted. No representations are made about the suitability of this software 
       
     8  * for any purpose. It is provided "as is" without express or implied warranty.
       
     9  * See the GNU General Public License for more details.
       
    10  *
       
    11  */
       
    12 
       
    13 
       
    14 #ifndef _XMLWRITER_H
       
    15 #define _XMLWRITER_H
       
    16 
       
    17 #include <qdir.h>
       
    18 #include <qfile.h>
       
    19 #include <qtextstream.h>
       
    20 #include <qmap.h>
       
    21 #include <qdict.h>
       
    22 #include <qstack.h>
       
    23 
       
    24 typedef QMap<QString, QString> AttributeMap;
       
    25 typedef QMapConstIterator<QString, QString> AttributeMapIter;
       
    26 
       
    27 static QString XML_INDENT("\t");
       
    28 static QString XML_OUTPUT_ENDL("\n");
       
    29 
       
    30 // TODO: If the output file fails to open then write to an internal string that can be
       
    31 // accessed by the caller after they call close(). This might be useful for internal
       
    32 // XML snippets.
       
    33 
       
    34 /**
       
    35 Class that handles writing to an XML file. It guarentees well-formedness,
       
    36 handles the encoding of PCDATA and indents the output.
       
    37 
       
    38 Individual elements are created as objects, they are written to the file on
       
    39 creation and closed when the element is destroyed.
       
    40 */
       
    41 class XmlStream
       
    42 {
       
    43 	friend class XmlElement;
       
    44 public:
       
    45 	/// Create an XML stream that writes to a file with the given encoding
       
    46 	XmlStream(const QString &fileName,
       
    47 				const QString &aEncoding="UTF-8",
       
    48 				const QString &aStandalone="no",
       
    49 				const QString &doctypeStr="");
       
    50 	/// Returns true of the file tha tthis stream is writing to is currently open.
       
    51 	bool isOpen() const { return mIsOpen; }
       
    52 	/// Write PCDATA to the output file, entities will be translated
       
    53 	void characters(const QString &aText);
       
    54 	void characters(char c);
       
    55 	/// Write a processing instruction to the output file.
       
    56 	void processingInstruction(const QString &aText);
       
    57 	/// Write a comment to the output file.
       
    58 	void comment(const QString &aText);
       
    59 	/// Output operator overloading, these equate to calling characters()
       
    60 	XmlStream& operator<<(const QCString &s);
       
    61 	XmlStream& operator<<(const char *s);
       
    62 	XmlStream& operator<<(char s);
       
    63 	/// Write a unicode character to the stream
       
    64 	XmlStream& writeUnicode(const QCString &s);
       
    65 	/// Close the XML file (if open), this will flush any unclosed elements
       
    66 	void close();
       
    67 	/// Get the file name
       
    68 	QString getFileName() const { return mFile.name(); }
       
    69 	/// Suspend and resume output
       
    70 	void outputSuspend();
       
    71 	void outputResume();
       
    72 	/// Destructor, this will call close()
       
    73 	~XmlStream();
       
    74 private:
       
    75 	QDict<char> unicodeCharTable;
       
    76 	/// Write out the start of element and register that element name on the stack
       
    77 	void startElement(const QString &aElemName, const AttributeMap &aAttrs);
       
    78 	/// Write out the end of element and remove that element name on the stack
       
    79 	void endElement(const QString &aElemName);
       
    80 	void closeElementDeclIfOpen();
       
    81 	void indent(unsigned int aInitVal=0);
       
    82 	inline bool isLegalXmlChar(QChar c) const;
       
    83 	QString encodeText(const QString &aStr) const;
       
    84 	QString encodeChar(char c) const;
       
    85 	bool mustEncodeChar(char c) const;
       
    86 	bool canIndent();
       
    87 	void setLastIndent(bool theB);
       
    88 private:
       
    89 	QFile mFile;
       
    90 	QTextStream *mStreamP;
       
    91 	QStack<QString> mElemStack;
       
    92 	QList<bool> mCanIndentList;
       
    93 	bool mInElement;
       
    94 	//bool mCanIndent;
       
    95 	bool mIsOpen;
       
    96 	bool mCanWrite;
       
    97 private:
       
    98 	// Private cctor and op=
       
    99 	XmlStream (const XmlStream &rhs);
       
   100 	XmlStream& operator=(const XmlStream &rhs);
       
   101 };
       
   102 
       
   103 /**
       
   104 XmlElement
       
   105 
       
   106 Usage example:
       
   107 @code
       
   108 // Start an XML file
       
   109 XmlStream t(fileName);
       
   110 if (!t.isOpen()) {
       
   111   err("Cannot open file %s for writing!\n", fileName.data());
       
   112   return;
       
   113 }
       
   114 // Create and persist a root element with no attributes
       
   115 XmlElement elemRoot(t, QString("root"), AttributeMap());
       
   116 // Note the use of {} that causes elem to go out of scope an thus
       
   117 // its destructor will be called so closing the element
       
   118 {
       
   119 	// Create and persist a root element with attributes
       
   120 	// First create the attributes
       
   121 	AttributeMap attrs;
       
   122 	attrs["attr_1"]	= "value_1";
       
   123 	attrs["attr_2"]	= "value_2";
       
   124 	// Create the element
       
   125 	XmlElement elem(t, "Element", attrs);
       
   126 	// Write some text
       
   127 	t.characters("Some stuff");
       
   128 	// Now elem is going out of scope
       
   129 }
       
   130 // Open and close and element
       
   131 XmlElement(t, "OpenClose");
       
   132 // Open and close and element with one attribute
       
   133 XmlElement(t, "WhatsForDinner", "spam", "eggs");
       
   134 // t goes out of scope and will close the file
       
   135 @endcode
       
   136 
       
   137 The result is:
       
   138 @verbatim
       
   139 <?xml version='1.0' encoding='UTF-8' standalone='no'?>
       
   140 <root>
       
   141 	<Element attr_1="value_1" attr_2="value_2">Some stuff</Element>
       
   142 	<OpenClose/>
       
   143 	<WhatsForDinner spam="eggs"/>
       
   144 </root>
       
   145 @endverbatim
       
   146 
       
   147 */
       
   148 class XmlElement
       
   149 {
       
   150 public:
       
   151 	/// Constructor with no attributes
       
   152 	XmlElement(XmlStream &aStream, const QString &aElemName);
       
   153 	/// Constructor with one attribute
       
   154 	XmlElement(XmlStream &aStream, const QString &aElemName, const QString &aAttr, const QString &aAttrValue);
       
   155 	/// Constructor with one attribute the values of which is a char
       
   156 	XmlElement(XmlStream &aStream, const QString &aElemName, const QString &aAttr, char aAttrValue);
       
   157 	/// Constructor with any number of attributes
       
   158 	XmlElement(XmlStream &aStream, const QString &aElemName, AttributeMap &aAttrs);
       
   159 	const QString& getElemName() const { return mElemName; }
       
   160 	/// Destructor, this closes the element on the stream
       
   161 	~XmlElement();
       
   162 private:
       
   163 	XmlStream& mStream;
       
   164 	QString mElemName;
       
   165 private:
       
   166 	// Private cctor and op=
       
   167 	XmlElement (const XmlElement &rhs);
       
   168 	XmlElement& operator=(const XmlElement &rhs);
       
   169 };
       
   170 
       
   171 /*
       
   172 This can be used in the case that elements need to persist over scope.
       
   173 
       
   174 So given this kind of code:
       
   175 void XmlDocVisitor::visitPre(DocHtmlDescTitle *)
       
   176 {
       
   177   if (m_hide) return;
       
   178   m_t << "<varlistentry><term>";
       
   179 }
       
   180 
       
   181 void XmlDocVisitor::visitPost(DocHtmlDescTitle *) 
       
   182 {
       
   183   if (m_hide) return;
       
   184   m_t << "</term></varlistentry>\n";
       
   185 }
       
   186 
       
   187 It can be replaced by this (assuming XmlDocVisitor has a member XmlElementStack m_es;):
       
   188 void XmlDocVisitor::visitPre(DocHtmlDescTitle *)
       
   189 {
       
   190   if (m_hide) return;
       
   191   m_es.push("varlistentry", AttributeMap());
       
   192   m_es.push("term", AttributeMap());
       
   193 }
       
   194 
       
   195 void XmlDocVisitor::visitPost(DocHtmlDescTitle *) 
       
   196 {
       
   197   if (m_hide) return;
       
   198   m_es.pop();
       
   199   m_es.pop();
       
   200 }
       
   201 
       
   202 */
       
   203 class XmlElementStack
       
   204 {
       
   205 public:
       
   206 	XmlElementStack(XmlStream &aStream);
       
   207 	/// Push element with no attributes
       
   208 	void push(const QString &aElemName);
       
   209 	/// Constructor with one attribute
       
   210 	void push(const QString &aElemName, const QString &aAttr, const QString &aAttrValue);
       
   211 	/// Push element with any number of attributes
       
   212 	void push(const QString &aElementName, AttributeMap &aAttrs);
       
   213 	/// Method that will check the element name matches
       
   214 	void pop(const QString &aElementName);
       
   215 	/// Push and pop an element with no attributes
       
   216 	void pushpop(const QString &aElemName);
       
   217 	/// Push and pop an element with no attributes but with some content
       
   218 	void pushpop(const QString &aElemName, const QString &aText);
       
   219 	/// Add attribute to item currently on top of the stack
       
   220 	void addAttribute(const QString &name, const QString &value);
       
   221 	/// Return a reference to the top of the stack. The stack is not modified.
       
   222 	const XmlElement& peek() const;
       
   223 	/// Return true if the stack is empty
       
   224 	bool isEmpty() const;
       
   225 	void close();
       
   226 	~XmlElementStack();
       
   227 private:
       
   228 	XmlStream& mStream;
       
   229 	QStack<XmlElement> mElemStack;
       
   230 private:
       
   231 	// Private cctor and op=
       
   232 	XmlElementStack (const XmlElementStack &rhs);
       
   233 	XmlElementStack& operator=(const XmlElementStack &rhs);
       
   234 	// Used by destructor
       
   235 	void pop();
       
   236 };
       
   237 
       
   238 #endif // _XMLWRITER_H