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