FDO API Reference Feature Data Objects

Writer.h

Go to the documentation of this file.
00001 #ifndef FDO_XML_WRITER_H
00002 #define FDO_XML_WRITER_H
00003 // 
00004 
00005 //
00006 // Copyright (C) 2004-2006  Autodesk, Inc.
00007 // 
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of version 2.1 of the GNU Lesser
00010 // General Public License as published by the Free Software Foundation.
00011 // 
00012 // This library is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 // Lesser General Public License for more details.
00016 // 
00017 // You should have received a copy of the GNU Lesser General Public
00018 // License along with this library; if not, write to the Free Software
00019 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 //
00021 
00022 
00023 #include <FdoCommon.h>
00024 
00025 /// \brief
00026 /// FdoXmlWriter writes an XML document to a text or binary stream. 
00027 /// \note
00028 /// The XML document is not completely written until this object
00029 /// is destroyed by releasing all references to it. Therefore, this object
00030 /// must be destroyed before reading back the document being written.
00031 class FdoXmlWriter : public FdoDisposable
00032 {
00033 public:
00034 
00035     /// \brief
00036     /// Specifies whether the output XML document
00037     /// has line breaks or indentation.
00038     enum LineFormat {
00039         /// The document is written without line breaks or element indentation.
00040         LineFormat_None,
00041         /// The document is written with a line break after:
00042         /// <ul>
00043         /// <li>every end element tag</li>
00044         /// <li>every start tag for elements with complex content (sub-elements)</li>
00045         /// </ul>
00046         /// Elements are not indented.
00047         LineFormat_Break,
00048         /// Same as LineFormat_Break, except that each element immediately following 
00049         /// a line break is indented by a certain number of spaces. The number of
00050         /// spaces is the element's nesting level within the document X 3. The root
00051         /// element has nesting level 0.
00052         LineFormat_Indent
00053     };
00054 
00055     /// \brief
00056     /// Constructs an XML writer on a file
00057     /// 
00058     /// \param fileName 
00059     /// Input name of the file to write.
00060     /// \param defaultRoot 
00061     /// true: all elements written are wrapped in a default root element, named "DataStore".
00062     /// false: the default root element is not written. In this case, the first 
00063     /// element written (via  WriteStartElement() ) becomes the root element. 
00064     /// The caller is responsible for ensuring that only one root element is written 
00065     /// (the XML standard disallows multiple root elements).
00066     /// \param lineFormat 
00067     /// Input Line break and indentation options 
00068     /// for the output document.
00069     /// \param lineLength 
00070     /// Input maximum line length. If 0 there is 
00071     /// no maximum. Otherwise, a line break is added before an XML attribute is
00072     /// written, if the attribute would have caused the current line to exceed
00073     /// this length.
00074     /// 
00075     /// \return
00076     /// Returns FdoXmlWriter
00077     /// 
00078     FDO_API_COMMON static FdoXmlWriter* Create( 
00079         FdoString* fileName, 
00080         FdoBoolean defaultRoot = true,
00081         LineFormat lineFormat = LineFormat_None,
00082         FdoSize    lineLength = 0
00083     );
00084 
00085     /// \brief
00086     /// Constructs an XML writer on a stream
00087     /// 
00088     /// \param stream 
00089     /// Input the stream to write.
00090     /// \param defaultRoot 
00091     /// true: all elements written are wrapped in a default root element, named "DataStore".
00092     /// false: the default root element is not written. In this case, the first 
00093     /// element written (via  WriteStartElement() ) becomes the root element. 
00094     /// The caller is responsible for ensuring that only one root element is written 
00095     /// (the XML standard disallows multiple root elements).
00096     /// \param lineFormat 
00097     /// Input Line break and indentation options 
00098     /// for the output document.
00099     /// \param lineLength 
00100     /// Input maximum line length. If 0 there is 
00101     /// no maximum. Otherwise, a line break is added before an XML attribute is
00102     /// written, if the attribute would have caused the current line to exceed
00103     /// this length.
00104     /// 
00105     /// \return
00106     /// Returns FdoXmlWriter
00107     /// 
00108     FDO_API_COMMON static FdoXmlWriter* Create( 
00109         FdoIoStream* stream, 
00110         FdoBoolean defaultRoot = true,
00111         LineFormat lineFormat = LineFormat_None,
00112         FdoSize    lineLength = 0
00113     );
00114 
00115     /// \brief
00116     /// Constructs an XML writer on a text writer
00117     /// 
00118     /// \param writer 
00119     /// Input the text writer.
00120     /// \param defaultRoot 
00121     /// true: all elements written are wrapped in a default root element, named "DataStore".
00122     /// false: the default root element is not written. In this case, the first 
00123     /// element written (via  WriteStartElement() ) becomes the root element. 
00124     /// The caller is responsible for ensuring that only one root element is written 
00125     /// (the XML standard disallows multiple root elements).
00126     /// \param lineFormat 
00127     /// Input Line break and indentation options 
00128     /// for the output document.
00129     /// \param lineLength 
00130     /// Input maximum line length. If 0 there is 
00131     /// no maximum. Otherwise, a line break is added before an XML attribute is
00132     /// written, if the attribute would have caused the current line to exceed
00133     /// this length.
00134     /// 
00135     /// \return
00136     /// Returns FdoXmlWriter
00137     /// 
00138     FDO_API_COMMON static FdoXmlWriter* Create( 
00139         FdoIoTextWriter* writer,
00140         FdoBoolean defaultRoot = true,
00141         LineFormat lineFormat = LineFormat_None,
00142         FdoSize    lineLength = 0
00143     );
00144 
00145     /// \brief
00146     /// Gets the underlying text writer. If a text writer was passed to this object
00147     /// then this text writer is returned.
00148     /// Otherwise, an auto-generated text writer is returned (a text writer
00149     /// wrapped around the file name or stream that was passed to this object)
00150     /// 
00151     /// \return
00152     /// Returns the underlying text writer
00153     /// 
00154     FDO_API_COMMON FdoIoTextWriter* GetTextWriter();
00155 
00156     /// \brief
00157     /// Gets the underlying stream. If a text writer was passed to this object
00158     /// then the stream for this text writer is returned.
00159     /// If a stream was passed to this object then this stream is returned.
00160     /// If a file name as passed then a auto-generated stream (wrapped around
00161     /// the file) is returned.
00162     /// 
00163     /// \return
00164     /// Returns the underlying stream
00165     /// 
00166     FDO_API_COMMON FdoIoStream* GetStream()
00167     {
00168         return mTextWriter->GetStream();
00169     }
00170 
00171     /// \brief
00172     /// Gets the current default root state.
00173     /// 
00174     /// \return
00175     /// Returns true if the default root element will be written, false otherwise.
00176     /// 
00177     FDO_API_COMMON FdoBoolean GetDefaultRoot()
00178     {
00179         return mbDefaultRoot;
00180     }
00181 
00182     /// \brief
00183     /// Closes this XML Writer by writing end tags for all
00184     /// elements currently open. Once this function is called, no more
00185     /// elements can be added to the output document.
00186     /// 
00187     FDO_API_COMMON void Close();
00188 
00189     /// \brief
00190     /// Sets whether to write the default root element.
00191     /// Must be called before the first element is written,
00192     /// otherwise an exception is thrown
00193     /// 
00194     /// \param defaultRoot 
00195     /// true: use the default root element ("DataStore") as the root element.
00196     /// false: caller is responsible for writing the root element.
00197     /// 
00198     FDO_API_COMMON void SetDefaultRoot( FdoBoolean defaultRoot );
00199 
00200     /// \brief
00201     /// Writes an element start tag to the document
00202     /// 
00203     /// \param elementName 
00204     /// Input the element name. Must be a valid
00205     /// XML 1.0 element name.
00206     /// 
00207     FDO_API_COMMON void WriteStartElement( FdoString* elementName );
00208 
00209     /// \brief
00210     /// Writes the end tag for the current element to the document.
00211     /// A FdoXmlException is thrown if there is no element to end.
00212     /// 
00213     FDO_API_COMMON void WriteEndElement();
00214 
00215     /// \brief
00216     /// Writes an attribute to the current element.
00217     /// A FdoXmlException is thrown if this function is called immediately after
00218     /// WriteEndElement().
00219     /// 
00220     /// \param attributeName 
00221     /// Input the element name. Must be a valid
00222     /// XML 1.0 attribute name.
00223     /// \param attributeValue 
00224     /// Input the element value.
00225     /// 
00226     FDO_API_COMMON void WriteAttribute( FdoString* attributeName, FdoString* attributeValue );
00227 
00228     /// \brief
00229     /// Writes simple (character) content for the current element. This function
00230     /// can be called multiple times for the same element. The characters are appended
00231     /// to the element's content. A FdoXmlException is thrown if there is no current 
00232     /// element.
00233     /// 
00234     /// \param characters 
00235     /// Input characters to append to the element content.
00236     /// 
00237     FDO_API_COMMON void WriteCharacters( FdoString* characters );
00238 
00239     /// \brief
00240     /// Writes arbitrary bytes to the XML Writer. Caller is responsible
00241     /// for ensuring that the text does not introduce any errors into the 
00242     /// XML document.
00243     ///
00244     /// \param bytes
00245     /// Input bytes to write.
00246     ///
00247     /// \param count
00248     /// Input count of bytes to write.
00249     /// 
00250     FDO_API_COMMON void WriteBytes( FdoByte* bytes, FdoSize count );
00251 
00252     /// \brief
00253     /// utility function that converts FDO element names to valid XML
00254     /// element or attribute names. Conversion is done by changing each invalid 
00255     /// character to a hex pattern ( "-xnnnn-" ).
00256     /// 
00257     /// \param name 
00258     /// Input the name to encode (convert).
00259     /// 
00260     /// \return
00261     /// Returns the encoded name.
00262     /// 
00263     FDO_API_COMMON virtual FdoStringP EncodeName ( FdoStringP name ) = 0;
00264 
00265     /// \brief
00266     /// Checks if a string is a valid XML 1.0 element or attribute name.
00267     /// 
00268     /// \param name 
00269     /// Input the string to check.
00270     /// 
00271     /// \return
00272     /// Returns true if the string is a valid name, false otherwise.
00273     /// 
00274     FDO_API_COMMON virtual FdoBoolean IsValidName ( FdoStringP name ) = 0;
00275 
00276     /// \brief
00277     ///    Given an element's or attribute's globally unique name ( uri and local name ),
00278     ///    this function returns its fully qualified name as per the
00279     ///    XML document being written, or the unqualified name if the uri is 
00280     ///    the default namespace. This is done by searching for the current 
00281     ///    namespace declaration that references the uri. 
00282     /// 
00283     /// \remarks
00284     ///    If a matching default namespace declaration ( "xmlns=<uri>" ) was
00285     ///    found and the name is for an element then the localName is returned.
00286     ///    \note
00287     ///    According to the XML 1.0 specification, default namespaces do 
00288     ///    not apply to attribute names, so the default namespace is ignored when the 
00289     ///    given name is not for an element.
00290     /// \n
00291     ///    Otherwise, if a matching namespace declaration was found then 
00292     ///    "[namespace]:[localName]" is returned.
00293     /// \n
00294     ///    Otherwise, L"" is returned (unable to determine qualified name).
00295     /// 
00296     /// \param uri 
00297     /// Input the URI corresponding to an element.
00298     /// \param localName 
00299     /// Input the local name corresponding to an element.
00300     /// \param isElement 
00301     /// Input a boolean flag indicating that the URI corresponds to an element.
00302     /// 
00303     /// \return
00304     ///    Returns the fully qualified name corresponding to the uri.
00305     /// 
00306     FDO_API_COMMON FdoStringP UriToQName( FdoString* uri, FdoString* localName, FdoBoolean isElement = true );
00307 
00308 /// \cond DOXYGEN-IGNORE
00309 protected:
00310     FdoXmlWriter() {}
00311     FdoXmlWriter( FdoIoTextWriter* writer, FdoBoolean defaultRoot, LineFormat lineFormat, FdoSize lineLength );
00312 
00313     virtual ~FdoXmlWriter(void);
00314 
00315     /// Write the prologue when needed
00316     void WritePrologue();
00317 /// \endcond
00318 
00319 private:
00320     /// XML Element stack element, representing a currently open XML element.
00321     class StackElement : public FdoDisposable 
00322     {
00323     public:
00324         static StackElement* Create( FdoStringP elementName, FdoXmlWriter* writer)
00325         {
00326             return new StackElement(elementName, writer);
00327         }
00328 
00329         FdoStringP GetName()
00330         {
00331             return mName;
00332         }
00333     
00334         /// returns true if this element declares any namespaces.
00335         bool GetHasNsDecl();
00336 
00337         /// set an attribute value for this element.
00338         void SetAttribute( FdoString* attributeName, FdoString* attributeValue );
00339         
00340         /// Flush all the attributes to the output document
00341         void FlushAttributes( FdoIoTextWriterP pWriter );
00342 
00343         /// Generates fully qualified name for the given element from
00344         /// namespace declarations in this element.
00345         FdoStringP UriToQName( FdoString* uri, FdoString* localName, FdoBoolean isElement );
00346 
00347         static FdoStringP EncodeValue ( FdoStringP value );
00348 
00349     protected:
00350         StackElement();
00351         StackElement( FdoStringP elementName, FdoXmlWriter* writer);
00352         virtual ~StackElement() {}
00353 
00354     private:
00355         FdoStringP mName;
00356         FdoXmlAttributesP mAtts;
00357         bool mHasNsDecl;
00358         FdoXmlWriter* mWriter;
00359 
00360     };
00361 
00362     typedef FdoPtr<StackElement> StackElementP;
00363 
00364     /// Stack of all currently open XML elements. 
00365     class ElementStack : public FdoStack<StackElement,FdoXmlException>
00366     {
00367     public:
00368         static ElementStack* Create() {return new ElementStack();}
00369 
00370         /// Generates fully qualified name for the given element or attribute from
00371         /// namespace declarations in the stacked elements.
00372         FdoStringP UriToQName( FdoString* uri, FdoString* localName, FdoBoolean isElement );
00373 
00374     protected:
00375         ElementStack() {}
00376         ~ElementStack() {}
00377         virtual void Dispose()
00378         {
00379             delete this;
00380         }
00381 
00382     };
00383 
00384     /// Close the currently open start element tag.
00385     void CloseStartElementTag();
00386 
00387     void WriteIndent();
00388 
00389     /// Underlying test writer
00390     FdoIoTextWriterP mTextWriter;
00391 
00392     /// true if automatically writing default root element.
00393     FdoBoolean       mbDefaultRoot;
00394 
00395     /// Tracks whether current element start tag is still open 
00396     /// (attributes can be added )
00397     FdoBoolean       mbTagOpen;
00398 
00399     /// Tracks whether the document prologue has been written.
00400     FdoBoolean       mbPrologueWritten;
00401 
00402     /// Tracks whether an element has been written.
00403     FdoBoolean       mbElementWritten;
00404 
00405     FdoBoolean       mbCharsWritten;
00406 
00407     /// Stack containing all elements whose end tag has not yet been written.
00408     /// The current (innermost) element is at the top of the stack.
00409     FdoPtr<ElementStack>      mElementStack;
00410 
00411     FdoStringP  mIndent;
00412     FdoInt32    mIndentLevel;
00413     LineFormat  mLineFormat;
00414     FdoSize     mLineLength;
00415 
00416     FdoSize     mCharWritten;
00417 };
00418 
00419 /// \ingroup (typedefs)
00420 /// \brief
00421 /// FdoXmlWriterP is a FdoPtr on FdoXmlWriter, provided for convenience.
00422 typedef FdoPtr<FdoXmlWriter> FdoXmlWriterP;
00423 
00424 #endif
00425 
00426 

Comments or suggestions? Send us feedback.