xmlwriter.h

Go to the documentation of this file.
00001 /*
00002  * The information in this file is
00003  * Copyright(c) 2007 Ball Aerospace & Technologies Corporation
00004  * and is subject to the terms and conditions of the
00005  * GNU Lesser General Public License Version 2.1
00006  * The license text is available from   
00007  * http://www.gnu.org/licenses/lgpl.html
00008  */
00009 
00010 #ifndef XMLWRITER_H
00011 #define XMLWRITER_H
00012 
00013 #include "StringUtilities.h"
00014 #include "XercesIncludes.h"
00015 #include "xmlbase.h"
00016 
00017 #include <algorithm>
00018 #include <iterator>
00019 #include <sstream>
00020 #include <stack>
00021 #include <string>
00022 #include <vector>
00023 
00024 class Font;
00025 
00026 /** @file xmlwriter.h
00027  *  @brief XML utilities and functionality for writing/generating a DOM
00028  */
00029 
00030 /**
00031  * This class generates a DOM tree and associated XML.
00032  * Many of the functions in this class use the \b current DOM node.
00033  * The \b current DOM node is determined as follows:
00034  * <ul>
00035  *  <li> If the function takes a \e pOwner argument and one is specified, this is the \b current DOM node.
00036  *  <li> If the \b addpoint stack is not empty, the top of the stack is the \b current DOM node.
00037  *  <li> Finally, the root element of the DOM tree is used as the \b current DOM node.
00038  * </ul>
00039  * This allows a caller to extend the depth of the DOM tree by pushing and popping DOM elements
00040  * to the \b addpoint stack. The following example code generates this DOM tree.
00041  *
00042  * @code
00043  *   <topLevel>
00044  *     <child a="42" b="This is an attribute">
00045  *       <grandchild>
00046  *          Here is some text.
00047  *       </grandchild>
00048  *     </child>
00049  *     <anotherchild val="1 2 3 4"/>
00050  *   </topLevel>
00051  * @endcode
00052  *
00053  * @code
00054  *   XMLWriter xml("topLevel");
00055  *   xml.pushAddPoint(xml.addElement("child"));
00056  *   xml.addAttr("a", 42);
00057  *   xml.addAttr("b", "This is an attribute");
00058  *   xml.pushAddPoint(xml.addElement("grandchild"));
00059  *   xml.addText("Here is some text.");
00060  *   xml.popAddPoint();
00061  *   xml.popAddPoint();
00062  *   vector<int> intVect;
00063  *   intVect.push_back(1);
00064  *   intVect.push_back(2);
00065  *   intVect.push_back(3);
00066  *   intVect.push_back(4);
00067  *   xml.pushAddPoint(xml.addElement("anotherchild"));
00068  *   xml.addAttr("val", intVect);
00069  *   string xmlString = xml.writeToString();
00070  * @endcode
00071  *
00072  * @ingroup app_xml
00073  *
00074  * @par requirements
00075  * Apache Xerces-C++ version 3.1.1
00076  */
00077 class XMLWriter : public XmlBase
00078 {
00079 public:
00080    //@{
00081    /**
00082     * Create an %XMLWriter.
00083     *
00084     * @param pRootElementName
00085     *        The name of the top level element
00086     *
00087     * @param pLog
00088     *        Optional MessageLog to be passed to XmlBase
00089     *
00090     * @param useNamespace
00091     *        If \c true, the app namespace will be exported, if \c false, no namespace will be exported.
00092     *
00093     * @throw XmlBase::XmlException
00094     *        When unable to create the Xerces DOM document.
00095     */
00096    XMLWriter(const char* pRootElementName, MessageLog* pLog = NULL, bool useNamespace = true);
00097 
00098    /**
00099     * Create an %XMLWriter.
00100     *
00101     * @param rootElementName
00102     *        The name of the top level element
00103     *
00104     * @param xmlNamespace
00105     *        Use this namespace instead of the default one.
00106     *
00107     * @param pLog
00108     *        Optional MessageLog to be passed to XmlBase
00109     *
00110     * @param useNamespace
00111     *        If \c true, the app namespace will be exported, if \c false, no namespace will be exported.
00112     *
00113     * @throw XmlBase::XmlException
00114     *        When unable to create the Xerces DOM document.
00115     */
00116    XMLWriter(const std::string& rootElementName, const std::string& xmlNamespace, MessageLog* pLog = NULL,
00117       bool useNamespace = true);
00118 
00119    /**
00120     * Destroy and cleanup the %XMLWriter object.
00121     */
00122    ~XMLWriter();
00123    //@}
00124 
00125    //@{
00126    /**
00127     * Add an attribute to the current DOM node
00128     * This templated class converts \e value to
00129     * a string using a std::stringstream.
00130     *
00131     * @param pName
00132     *        The name of the attribute.
00133     *
00134     * @param value
00135     *        The value of the attribute. \b T
00136     *        must have \e operator<< defined for
00137     *        a std::stringstream.
00138     *
00139     * @return Returns \c true on success and \c false on failure.
00140     *
00141     * @see std::stringstream
00142     */
00143    template <class T>
00144    bool addAttr(const char* pName, T value)
00145    {
00146       return addAttr(pName, static_cast<std::string>(StringUtilities::toXmlString(value)), NULL);
00147    }
00148 
00149    /**
00150     * Add a vector attribute to the current DOM node
00151     * This templated class converts \e value to
00152     * an XML list of strings using a std::stringstream.
00153     *
00154     * @param pName
00155     *        The name of the attribute.
00156     *
00157     * @param value
00158     *        The value of the attribute. \b T
00159     *        must have \e operator<< defined for
00160     *        a std::stringstream.
00161     *
00162     * @return Returns \c true on success and \c false on failure.
00163     *
00164     * @see std::stringstream
00165     */
00166    template<class T>
00167    bool addAttr(const char* pName, std::vector<T> value)
00168    {
00169       std::stringstream buf;
00170       std::copy(value.begin(), value.end(), std::ostream_iterator<T>(buf, " "));
00171       return addAttr(pName, buf.str(), NULL);
00172    }
00173 
00174    /**
00175     * Add a string attribute to the specified DOM node.
00176     *
00177     * @param pName
00178     *        The name of the attribute.
00179     *
00180     * @param pValue
00181     *        The value of the attribute.
00182     *
00183     * @param pOwner
00184     *        The DOM node which will have the attribute.
00185     *
00186     * @return Returns \c true on success and \c false on failure.
00187     */
00188    bool addAttr(const char* pName, const char* pValue, XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* pOwner);
00189 
00190    /**
00191     * Add a string attribute to the specified DOM node.
00192     *
00193     * @param pName
00194     *        The name of the attribute.
00195     *
00196     * @param value
00197     *        The value of the attribute.
00198     *
00199     * @param pOwner
00200     *        The DOM node which will have the attribute.
00201     *
00202     * @return Returns \c true on success and \c false on failure.
00203     */
00204    bool addAttr(const char* pName, const std::string value, XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* pOwner)
00205    {
00206       return addAttr(pName, value.c_str(), pOwner);
00207    }
00208    //@}
00209 
00210    //@{
00211    /**
00212     * Add an element DOM node.
00213     *
00214     * @param pName
00215     *        The name of the element.
00216     * @param pOwner
00217     *        The optional DOM node which will be the parent
00218     *        of this element. If not specified, the current
00219     *        DOM node is used as the parent.
00220     *
00221     * @return The new DOM element or \c NULL on failure.
00222     */
00223    XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* addElement(const char* pName,
00224       XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pOwner = NULL);
00225    //@}
00226 
00227    //@{
00228    /**
00229     * Add an element DOM node.
00230     *
00231     * @param name
00232     *        The name of the element.
00233     *
00234     * @param pOwner
00235     *        The optional DOM node which will be the parent
00236     *        of this element. If not specified, the current
00237     *        DOM node is used as the parent.
00238     *
00239     * @return The new DOM element or \c NULL on failure.
00240     */
00241    XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* addElement(const std::string& name,
00242       XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pOwner = NULL)
00243    {
00244       return addElement(name.c_str(), pOwner);
00245    }
00246    //@}
00247 
00248    //@{
00249    /**
00250     * Add an element DOM node.
00251     *
00252     * @param pName
00253     *        The name of the element.
00254     *
00255     * @param font
00256     *        The font specification to be written in the XMLWriter.
00257     *
00258     * @param pOwner
00259     *        The optional DOM node which will be the parent
00260     *        of this element. If not specified, the current
00261     *        DOM node is used as the parent.
00262     *
00263     * @return The new DOM element or \c NULL on failure.
00264     */
00265    XERCES_CPP_NAMESPACE_QUALIFIER DOMElement* addFontElement(const char* pName, const Font& font,
00266       XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pOwner = NULL);
00267    //@}
00268 
00269    //@{
00270    /**
00271     * Add a value as a text DOM node.
00272     * This templated class converts \e value to
00273     * a string using a std::stringstream.
00274     *
00275     * @param value
00276     *        The value of the text node. \b T must
00277     *        have \e operator<< defined on std::stringstream.
00278     *
00279     * @param pOwner
00280     *        The optional DOM node which will be the parent
00281     *        of this element. If not specified, the current
00282     *        DOM node is used as the parent.
00283     *
00284     * @see std::stringstream
00285     *
00286     * @return The new DOM text node or \c NULL on failure.
00287     */
00288    template<class T>
00289    XERCES_CPP_NAMESPACE_QUALIFIER DOMText* addText(T value, XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pOwner = NULL)
00290    {
00291       std::stringstream buf;
00292       buf << value;
00293       return addText(buf.str(), pOwner);
00294    }
00295 
00296    /**
00297     * Add a vector of values as a text DOM node.
00298     * This templated class converts \e value to
00299     * an XML list of strings using a std::stringstream.
00300     *
00301     * @param value
00302     *        The value of the text node. \b T must
00303     *        have \e operator<< defined on std::stringstream.
00304     *
00305     * @param pOwner
00306     *        The optional DOM node which will be the parent
00307     *        of this element. If not specified, the current
00308     *        DOM node is used as the parent.
00309     *
00310     * @return The new DOM text node or \c NULL on failure.
00311     *
00312     * @see std::stringstream
00313     */
00314    template<class T>
00315    XERCES_CPP_NAMESPACE_QUALIFIER DOMText* addText(std::vector<T> value,
00316       XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pOwner = NULL)
00317    {
00318       std::stringstream buf;
00319       std::copy(value.begin(), value.end(), std::ostream_iterator<T>(buf, " "));
00320       return addText(buf.str(), pOwner);
00321    }
00322 
00323    /**
00324     * Add a string value as a text DOM node.
00325     *
00326     * @param pValue
00327     *        The value of the text node.
00328     *
00329     * @param pOwner
00330     *        The optional DOM node which will be the parent
00331     *        of this element. If not specified, the current
00332     *        DOM node is used as the parent.
00333     *
00334     * @return The new DOM text node or \c NULL on failure.
00335     */
00336    XERCES_CPP_NAMESPACE_QUALIFIER DOMText* addText(const char* pValue,
00337       XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pOwner = NULL);
00338 
00339    /**
00340     * Add a string value as a text DOM node.
00341     *
00342     * @param value
00343     *        The value of the text node.
00344     *
00345     * @param pOwner
00346     *        The optional DOM node which will be the parent
00347     *        of this element. If not specified, the current
00348     *        DOM node is used as the parent.
00349     *
00350     * @return The new DOM text node or \c NULL on failure.
00351     */
00352    XERCES_CPP_NAMESPACE_QUALIFIER DOMText* addText(const std::string& value,
00353       XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pOwner = NULL)
00354    {
00355       return addText(value.c_str(),pOwner);
00356    }
00357    //@}
00358 
00359    //@{
00360    /**
00361     * Determine if a named element exists.
00362     * This will check descendents of \e pOwner, if
00363     * specified or descendents of the current DOM node.
00364     *
00365     * @param pName
00366     *        The name of the element to find.
00367     *
00368     * @param pOwner
00369     *        The optional DOM node which will be searched.
00370     *        If not specified, the current DOM node is used
00371     *        as the parent.
00372     *
00373     * @return Returns \c true if the element exists and \c false if it does not exist.
00374     */
00375    bool elementExists(const char* pName, XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pOwner = NULL);
00376 
00377    /**
00378     * Remove a named element from a DOM tree.
00379     * This will remove an element if it is a child of
00380     * \e pOwner, if specified or if it is a child of
00381     * the current DOM node otherwise.
00382     *
00383     * @param pName
00384     *        The name of the element to remove.
00385     *
00386     * @param pOwner
00387     *        The optional DOM node which will be searched.
00388     *        If not specified, the current DOM node is used
00389     *        as the parent.
00390     */
00391    void removeElement(const char* pName, XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pOwner = NULL);
00392 
00393    /**
00394     * Remove a specified node from a DOM tree.
00395     * This will remove a node if it is a child of
00396     * \e pOwner, if specified or if it is a child of
00397     * the current DOM node otherwise.
00398     *
00399     * @param pChild
00400     *        The DOM node to remove.
00401     *
00402     * @param pOwner
00403     *        The optional DOM node which will be searched.
00404     *        If not specified, the current DOM node is used
00405     *        as the parent.
00406     */
00407    void removeChild(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pChild,
00408       XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pOwner = NULL);
00409    //@}
00410 
00411    //@{
00412    /**
00413     * This flag determines if only a single child DOM node
00414     * with a name can be added. If set, child DOM nodes with
00415     * the name of a newly added DOM node are removed. If clear,
00416     * multiple DOM nodes with the same name may be added.
00417     *
00418     * @param v
00419     *        The new value of the flag.
00420     *
00421     * @return The old value of the flag.
00422     */
00423    bool setSingleChildInstance(bool v)
00424    {
00425       bool r(mSingleChildInstance);
00426       mSingleChildInstance = v;
00427       return r;
00428    }
00429    //@}
00430 
00431    //@{
00432    /**
00433     * Write a DOM tree to a file as XML.
00434     *
00435     * @param pFp
00436     *        File pointer that the DOM tree will be written to.
00437     *
00438     * @throw XmlBase::XmlException
00439     *        When Xerces is not able to generate the XML.
00440     */
00441    void writeToFile(FILE* pFp);
00442 
00443    /**
00444     * Write a DOM tree to a string as XML.
00445     *
00446     * @return The DOM tree as a string of XML.
00447     *
00448     * @throw XmlBase::XmlException
00449     *        When Xerces is not able to generate the XML;
00450     *        or when the \e char type is not 1 byte in size.
00451     *        (this should not occur on any modern computer)
00452     */
00453    std::string writeToString();
00454    //@}
00455 
00456    //@{
00457    /**
00458     * Push a new current DOM node to the add point stack.
00459     * See the class documentation for XMLWriter for further
00460     * information on add points.
00461     *
00462     * @param pNode
00463     *        The new current DOM node. If this is \c NULL, the document
00464     *        root is pushed onto the stack.
00465     *
00466     * @see XMLWriter
00467     */
00468    void pushAddPoint(XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* pNode = NULL);
00469 
00470    /**
00471     * Pop the current DOM node from the add point stack.
00472     * See the class documentation for XMLWriter for further
00473     * information on add points.
00474     *
00475     * @return The DOM node which was just popped from the stack.
00476     *
00477     * @see XMLWriter
00478     */
00479    XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* popAddPoint();
00480 
00481    /**
00482     * Find out what DOM node is on top of the add point stack without removing the node.
00483     * See the class documentation for XMLWriter for further
00484     * information on add points.
00485     *
00486     * @return The DOM node which is on the top of the stack.
00487     *
00488     * @see XMLWriter
00489     */
00490    XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* peekAddPoint();
00491    //@}
00492 
00493 private:
00494    XERCES_CPP_NAMESPACE_QUALIFIER DOMDocument* mpDoc;
00495    std::stack<XERCES_CPP_NAMESPACE_QUALIFIER DOMNode*> mpAddPoint;
00496    XERCES_CPP_NAMESPACE_QUALIFIER DOMImplementation* mpImpl;
00497    bool mSingleChildInstance;
00498    XMLCh* mpWithNamespace;
00499 };
00500 
00501 /** Explicit template specializations can not go in the class declaration
00502     as this is not supported in Studio 11.
00503  **/
00504 
00505 template<> bool XMLWriter::addAttr<std::string>(const char* pName, std::string value);
00506 template<> bool XMLWriter::addAttr<char*>(const char* pName, char* pValue);
00507 template<> bool XMLWriter::addAttr<const char*>(const char* pName, const char* pValue);
00508 
00509 /**
00510  *  This class is intended to be used by the XML_ADD_POINT macro and should not
00511  *  be used directly.
00512  */
00513 class XmlAddPoint
00514 {
00515 public:
00516    XmlAddPoint(XMLWriter& writer, const std::string& name) :
00517       mWriter(writer),
00518       mFirstTime(true)
00519    {
00520       writer.pushAddPoint(writer.addElement(name.c_str()));
00521    }
00522    ~XmlAddPoint()
00523    {
00524       mWriter.popAddPoint();
00525    }
00526    bool isFirstTime()
00527    {
00528       bool firstTime = mFirstTime;
00529       mFirstTime = false;
00530       return firstTime;
00531    }
00532 private:
00533    XmlAddPoint& operator=(const XmlAddPoint& rhs);
00534 
00535    XMLWriter& mWriter;
00536    bool mFirstTime;
00537 };
00538 
00539 /**
00540  *  Adds an add-point to the XML and to the C++ stack.
00541  * 
00542  *  This macro causes an add-point to be inserted into the writer, and 
00543  *  simultaneously added to an RAII object on the C++ stack. This causes the
00544  *  indentation of the C++ writing code to match the indentation of the 
00545  *  resulting XML. This in turn makes it easier to visualize the structure of
00546  *  the resulting XML and makes it impossible mismatch the pushing and popping
00547  *  of add points.
00548  *
00549  *  @code
00550  *  XML_ADD_POINT (writer, my_add_point) // pushes an add point on the writer
00551  *  {
00552  *     writer.addAttribute("my_attr", myValue);
00553  *  } // pops the add point from the writer
00554  *  @endcode
00555  * 
00556  *  @param writer
00557  *             The XMLWriter to push the new element / add-point on to.
00558  *
00559  *  @param name
00560  *             The name for the new element.
00561  */
00562 #define XML_ADD_POINT(writer, name) \
00563    for (XmlAddPoint name(writer, #name); name.isFirstTime(); )
00564 
00565 /**
00566  *  This method is intended to be called from the XML_ADD_CONTAINER macro and 
00567  *  should not be called directly.
00568  */
00569 template <class Iter>
00570 void writeContainerElements(XMLWriter& writer, Iter pStartIter, Iter pStopIter)
00571 {
00572    for (Iter pIter = pStartIter; pIter != pStopIter; ++pIter)
00573    {
00574       XML_ADD_POINT (writer, element)
00575       {
00576          writer.addAttr("value", *pIter);
00577       }
00578    }
00579 }
00580 
00581 /**
00582  *  Writes a container of data to the specified XMLWriter
00583  * 
00584  *  @code
00585  *  XML_ADD_POINT (writer, my_data)
00586  *  {
00587  *     vector<int> v(12, 65); // a vector of 12 65's
00588  *     XML_ADD_CONTAINER(writer, value, v.begin(), v.end());
00589  *  }
00590  *  @endcode
00591  *  The above code will write out the vector of 12 values to the specified
00592  *  XMLWriter. The data can be read back in later with readContainerElements.
00593  *
00594  *  @param writer
00595  *             The XMLWriter to write the data to.
00596  *
00597  *  @param name
00598  *             The name to give each value.
00599  *
00600  *  @param startIter
00601  *             A container iterator specifying the first element to write.
00602  *
00603  *  @param stopIter
00604  *             A container iterator specifying where to stop writing.
00605  */
00606 #define XML_ADD_CONTAINER(writer, name, startIter, stopIter) \
00607    XML_ADD_POINT (writer, name) \
00608    { \
00609       writeContainerElements(writer, startIter, stopIter); \
00610    }
00611 
00612 #endif

Software Development Kit - Opticks 4.9.0 Build 16218