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