214 lines
8.1 KiB
C++
214 lines
8.1 KiB
C++
|
/*
|
||
|
* Portable Agile C++ Classes (PACC)
|
||
|
* Copyright (C) 2001-2003 by Marc Parizeau
|
||
|
* http://manitou.gel.ulaval.ca/~parizeau/PACC
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2.1 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*
|
||
|
* Contact:
|
||
|
* Laboratoire de Vision et Systemes Numeriques
|
||
|
* Departement de genie electrique et de genie informatique
|
||
|
* Universite Laval, Quebec, Canada, G1K 7P4
|
||
|
* http://vision.gel.ulaval.ca
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/*!
|
||
|
* \file PACC/XML/Streamer.hpp
|
||
|
* \brief Class definition for the %XML streamer.
|
||
|
* \author Marc Parizeau, Laboratoire de vision et systèmes numériques, Université Laval
|
||
|
* $Revision: 1.10.2.1 $
|
||
|
* $Date: 2007/09/10 18:24:10 $
|
||
|
*/
|
||
|
|
||
|
#ifndef PACC_XML_Streamer_hpp_
|
||
|
#define PACC_XML_Streamer_hpp_
|
||
|
|
||
|
#include "Util/Assert.hpp"
|
||
|
#include <iostream>
|
||
|
#include <sstream>
|
||
|
#include <string>
|
||
|
#include <stack>
|
||
|
|
||
|
namespace PACC {
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
namespace XML {
|
||
|
|
||
|
/*! \brief Simple document streamer.
|
||
|
\author Marc Parizeau, Laboratoire de vision et systèmes numériques, Université Laval
|
||
|
\ingroup XML
|
||
|
|
||
|
This class is for streaming %XML markup with automatic indentation. To
|
||
|
add a new markup tag, use method Streamer::openTag, followed by calls to
|
||
|
Streamer::insertAttribute to add attributes. Then call again Streamer::openTag
|
||
|
to insert any embedded markup. Don't forget to close each tag by calling
|
||
|
Streamer::closeTag. Here is a simple usage example:
|
||
|
\code
|
||
|
Streamer lStream(cout);
|
||
|
lStream.insertHeader();
|
||
|
lStream.openTag("MyTag");
|
||
|
lStream.insertAttribute("name", "value");
|
||
|
lStream.openTag("MySubTag1");
|
||
|
lStream.insertAttribute("x", 10);
|
||
|
lStream.insertAttribute("y", 20);
|
||
|
lStream.closeTag();
|
||
|
lStream.openTag("MySubTag2", false);
|
||
|
lStream.insertStringContent("this is my sub-tag number 2!");
|
||
|
lStream.closeTag();
|
||
|
lStream.closeTag();
|
||
|
\endcode
|
||
|
which will produce the following result:
|
||
|
\code
|
||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||
|
<MyTag name="value">
|
||
|
<MySubTag1 x="10" y="20"/>
|
||
|
<MySubTag2>this is my sub-tag number 2!</MySubTag2>
|
||
|
</MyTag>
|
||
|
\endcode
|
||
|
*/
|
||
|
class Streamer {
|
||
|
public:
|
||
|
//! Constructs object for streaming %XML markup into output stream \c inStream using an indentation width of \c inWidth.
|
||
|
Streamer(ostream& inStream, unsigned int inWidth=2) : mStream(inStream), mIndentWidth(inWidth), mClosed(true), mOneAttribute(false), mIndentAttributes(false) {}
|
||
|
|
||
|
//! Close the last opened markup tag.
|
||
|
void closeTag(void);
|
||
|
|
||
|
//! Convert special xml characters to quotes.
|
||
|
static string& convertToQuotes(string& ioString, const char* inQuotes="<>&'\"");
|
||
|
|
||
|
//! Return precision of output stream for double values.
|
||
|
unsigned int getPrecision(void) {return mStream.precision();}
|
||
|
|
||
|
//!Return output stream of streamer.
|
||
|
ostream& getStream(void) {return mStream;}
|
||
|
|
||
|
//! Insert a string attribute with name \c inName and value \c inValue into the current start tag.
|
||
|
void insertAttribute(const string& inName, const char* inValue);
|
||
|
|
||
|
//! Insert a string attribute with name \c inName and value \c inValue into the current start tag.
|
||
|
void insertAttribute(const string& inName, const string& inValue) {
|
||
|
insertAttribute(inName, inValue.c_str());
|
||
|
}
|
||
|
|
||
|
/*!
|
||
|
Insert a template attribute with name \c inName and value \c inValue into the current start tag.
|
||
|
|
||
|
This method assumes that typename \c Type knows how to insert itself into a stream using \c operator<<.
|
||
|
*/
|
||
|
template <typename Type>
|
||
|
void insertAttribute(const string& inName, Type inValue) {
|
||
|
if(mIndentAttributes && mTags.top().second) {
|
||
|
mStream << endl << std::string(mTags.size()*mIndentWidth, ' ');
|
||
|
} else mStream << " ";
|
||
|
mStream << inName << "=\"" << inValue << "\"";
|
||
|
mOneAttribute = true;
|
||
|
}
|
||
|
|
||
|
//! Insert CDATA section \c inCDATA (cannot contain any "]]>" substring).
|
||
|
void insertCDATA(const string& inCDATA) {
|
||
|
PACC_AssertM(inCDATA.find("]]>",0)==string::npos, "an XML CDATA cannot contain any ']]>' substring!");
|
||
|
insertStringContent(string("<![CDATA[")+inCDATA+string("]]>"), false);
|
||
|
}
|
||
|
|
||
|
//! Insert comment \c inComment (cannot contain any "--" substring).
|
||
|
void insertComment(const string& inComment) {
|
||
|
PACC_AssertM(inComment.find("--",0)==string::npos, "an XML comment cannot contain any '--' substring!");
|
||
|
insertStringContent(string("<!--")+inComment+string("-->"), false);
|
||
|
}
|
||
|
|
||
|
/*! \brief Insert STL container \c inObject into this streamer, using tag name \c inName.
|
||
|
|
||
|
If no tag name is specified, the container's content is inserted into the current tag. Assumes that the container's elements can insert themselves into a streamer using \c operator<<.
|
||
|
*/
|
||
|
template <typename Container>
|
||
|
void insertContainer(const Container& inObject, const string& inName="") {
|
||
|
// insert optional tag name
|
||
|
if(inName != "") openTag(inName);
|
||
|
// iterate through container
|
||
|
for(typename Container::const_iterator i = inObject.begin(); i != inObject.end(); ++i) {
|
||
|
(*this) << (*i);
|
||
|
}
|
||
|
if(inName != "") closeTag();
|
||
|
}
|
||
|
|
||
|
//! Insert a valid xml declarative tag with encoding \c inEncoding (default is ISO-8859-1).
|
||
|
void insertHeader(const string& inEncoding = "ISO-8859-1");
|
||
|
|
||
|
/*! Insert a primitive tag with tag name \c inTagName, attribute name \c inAttName, and value \c inValue.
|
||
|
|
||
|
The format for this primitive tag is <inTagName inAttName="inValue"/>. This method assumes that typename \c Type knows how to insert itself into a stream using \c operator<<.
|
||
|
*/
|
||
|
template <typename Type>
|
||
|
void insertPrimitiveTag(Type inValue, const string& inTagName, const string& inAttName="v") {
|
||
|
openTag(inTagName);
|
||
|
insertAttribute(inAttName, inValue);
|
||
|
closeTag();
|
||
|
}
|
||
|
|
||
|
//! Insert string \c inString as content of current markup.
|
||
|
void insertStringContent(const string& inContent, bool inConvert=true);
|
||
|
|
||
|
//! Open new markup tag using name \c inName.
|
||
|
void openTag(const string& inName, bool inIndent=true);
|
||
|
|
||
|
//! Set attribute indentation mode if argument \c inValue is true.
|
||
|
void setAttributeIndentation(bool inValue) {mIndentAttributes = inValue;}
|
||
|
|
||
|
//! Set precision of output stream to \c inValue digits for double values.
|
||
|
void setPrecision(unsigned int inValue) {mStream.precision(inValue);}
|
||
|
|
||
|
//! Insert an integer markup with value \c inValue into this streamer.
|
||
|
Streamer& operator<<(int inValue) {
|
||
|
insertPrimitiveTag(inValue, "Integer");
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
//! Insert a float markup with value \c inValue into this streamer.
|
||
|
Streamer& operator<<(double inValue) {
|
||
|
insertPrimitiveTag(inValue, "Float");
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
//! Insert a string markup with value \c inValue into this streamer.
|
||
|
Streamer& operator<<(const string& inValue) {
|
||
|
insertPrimitiveTag(inValue, "String");
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
//! Insert object \c inObject into this stream, assuming that it defines a write function.
|
||
|
template<typename Type>
|
||
|
Streamer& operator<<(const Type& inObject) {
|
||
|
inObject.write(*this);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
protected:
|
||
|
ostream& mStream; //!< Output stream
|
||
|
stack< pair<string, bool> > mTags; //!< Stack of opened tags
|
||
|
unsigned int mIndentWidth; //!< Width of markup indentation
|
||
|
bool mClosed; //!< Indicates whether start tag has been closed
|
||
|
bool mOneAttribute; //!< Indicates whether the tag contains at least one attribute
|
||
|
bool mIndentAttributes; //!< Indicates whether attributes should also be indented
|
||
|
};
|
||
|
|
||
|
} // end of XML namespace
|
||
|
|
||
|
} // end of PACC namespace
|
||
|
|
||
|
#endif // PACC_XML_Streamer_hpp_
|