Working on prologue/epilogue for xml

This commit is contained in:
Shane Grant
2013-07-02 15:05:25 -07:00
parent 6e7c922623
commit 58e707a40e
2 changed files with 153 additions and 22 deletions

View File

@@ -30,13 +30,35 @@
#include <cereal/cereal.hpp> #include <cereal/cereal.hpp>
#include <cereal/external/rapidxml/rapidxml.hpp> #include <cereal/external/rapidxml/rapidxml.hpp>
#include <cereal/external/rapidxml/rapidxml_print.hpp> #include <cereal/external/rapidxml/rapidxml_print.hpp>
#include <cereal/external/base64.hpp>
#include <sstream> #include <sstream>
#include <stack> #include <stack>
#include <string> #include <string>
#include <iostream>
namespace cereal namespace cereal
{ {
namespace detail
{
struct XMLHelper
{
const char * popName()
{
if( names.empty() )
return nullptr;
else
{
auto name = names.top();
names.pop();
return name;
}
}
std::stack<const char *> names;
};
}
// ###################################################################### // ######################################################################
//! An output archive designed to save data to XML //! An output archive designed to save data to XML
class XMLOutputArchive : public OutputArchive<XMLOutputArchive, AllowEmptyClassElision> class XMLOutputArchive : public OutputArchive<XMLOutputArchive, AllowEmptyClassElision>
@@ -44,11 +66,11 @@ namespace cereal
public: public:
//! Construct, outputting to the provided stream //! Construct, outputting to the provided stream
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or /*! @param stream The stream to output to. Can be a stringstream, a file stream, or
even cout! */ even cout!
XMLOutputArchive(std::ostream & stream) : @param precision The precision for floating point output */
XMLOutputArchive(std::ostream & stream, size_t precision = 10 ) :
OutputArchive<XMLOutputArchive, AllowEmptyClassElision>(this), OutputArchive<XMLOutputArchive, AllowEmptyClassElision>(this),
itsStream(stream), itsStream(stream)
itsUnnamedCounter( 0 )
{ {
// rapidxml will delete all allocations when xml_document is cleared // rapidxml will delete all allocations when xml_document is cleared
auto node = itsXML.allocate_node( rapidxml::node_declaration ); auto node = itsXML.allocate_node( rapidxml::node_declaration );
@@ -58,7 +80,12 @@ namespace cereal
auto root = itsXML.allocate_node( rapidxml::node_element, "cereal" ); auto root = itsXML.allocate_node( rapidxml::node_element, "cereal" );
itsXML.append_node( root ); itsXML.append_node( root );
itsNodes.push( root ); itsNodes.emplace( root );
// testing
itsStream << std::boolalpha;
itsStream.precision( precision );
//itsStream.setf( std::ios::floatfield, std::ios::fixed );
} }
//! Destructor, flushes the XML //! Destructor, flushes the XML
@@ -68,15 +95,6 @@ namespace cereal
itsXML.clear(); itsXML.clear();
} }
//! Writes size bytes of data to the output stream
void saveBinary( const void * data, size_t size )
{
size_t const writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
if(writtenSize != size)
throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
}
void createNode( std::string const & name ) void createNode( std::string const & name )
{ {
createNode( name.c_str() ); createNode( name.c_str() );
@@ -85,16 +103,104 @@ namespace cereal
void createNode( char const * name ) void createNode( char const * name )
{ {
auto node = itsXML.allocate_node( rapidxml::node_element, name ); auto node = itsXML.allocate_node( rapidxml::node_element, name );
itsNodes.top()->append_node( node ); itsNodes.top().node->append_node( node );
itsNodes.push( node ); itsNodes.emplace( node );
++itsUnnamedCounter;
node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, "5432" ) );
} }
//! Saves some data, encoded as a string
/*! The data will be be named with the most recent name if one exists,
otherwise it will be given some default delimited value that depends upon
the parent node */
template <class T> inline
void saveValue( T const & value )
{
os.clear(); os.seekp(0);
os << value << std::ends;
//std::cout << ".... " << os.str().c_str() << std::endl;
insertValueNode( os.str().c_str() );
itsStream << value << std::endl;
}
//! Appends a named node to the current top node with some data
/*! The name is generated by calling the top node's getValueName(),
which will generate an incremental value name if one has not been set
prior to calling this */
void insertValueNode( const char * data )
{
//const auto nameString = itsNodes.top().getValueName();
// allocate strings for all of the data in the XML object
//auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
auto dataPtr = itsXML.allocate_string( data );
// insert into the XML
itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
//itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_element, namePtr, dataPtr, nameString.size() ) );
}
void startNode()
{
const auto nameString = itsNodes.top().getValueName();
// allocate strings for all of the data in the XML object
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
// insert into the XML
auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
itsNodes.top().node->append_node( node );
itsNodes.emplace( node );
}
void finishNode()
{
itsNodes.pop();
}
//! Saves some binary data, encoded as a base64 string
void saveBinaryValue( const void * data, size_t size )
{
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
saveValue( base64string );
//auto decoded = base64::decode(base64string);
//int const * zz = (int const*)decoded.data();
//std::cout << zz[0] << " " << zz[1] << " " << zz[2] << std::endl;
};
struct NodeInfo
{
NodeInfo( rapidxml::xml_node<> * n = nullptr,
const char * nm = nullptr ) :
node( n ),
counter( 0 ),
name( nm )
{ }
rapidxml::xml_node<> * node;
size_t counter;
const char * name;
std::string getValueName()
{
if( name )
{
auto n = name;
name = nullptr;
return {n};
}
else
{
return "value" + std::to_string( counter++ ) + "\0";
}
}
};
private: private:
std::ostream & itsStream; std::ostream & itsStream;
rapidxml::xml_document<> itsXML; //!< The XML document rapidxml::xml_document<> itsXML; //!< The XML document
std::stack<rapidxml::xml_node<>*> itsNodes; //!< Stack of nodes, bottom one will always be the root std::stack<NodeInfo> itsNodes;
size_t itsUnnamedCounter; //!< Used to give names to un-named values std::ostringstream os;
}; };
struct XMLInputArchive; struct XMLInputArchive;
@@ -108,10 +214,31 @@ namespace cereal
//ar( t.value ); //ar( t.value );
} }
//! Saving for POD types to xml
template<class T> inline
typename std::enable_if<std::is_arithmetic<T>::value, void>::type
save(XMLOutputArchive & ar, T const & t)
{
ar.saveValue( t );
}
//! saving string to xml
template<class CharT, class Traits, class Alloc> inline template<class CharT, class Traits, class Alloc> inline
void save(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str) void save(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
{ {
ar.createNode( str ); ar.saveValue( str );
}
template <class T>
void prologue( XMLOutputArchive & ar, T const & data )
{
ar.startNode();
}
template <class T>
void epilogue( XMLOutputArchive & ar, T const & data )
{
ar.finishNode();
} }
// ###################################################################### // ######################################################################

View File

@@ -295,14 +295,18 @@ int main()
assert(e_in == e_out); assert(e_in == e_out);
auto x = cereal::make_nvp( "a", cereal::make_nvp("b", 5) );
{ {
//std::stringstream os; //std::stringstream os;
cereal::XMLOutputArchive oar( std::cout ); cereal::XMLOutputArchive oar( std::cout );
oar( cereal::make_nvp("hello", 5 ) ); oar( cereal::make_nvp("hello", 5 ) );
std::string bla("bla"); std::string bla("bla");
oar( bla ); oar( bla );
oar( 5 );
oar( 3.3 );
oar( 3.2f );
oar( true );
//int xxx[] = {-1, 95, 3};
//oar.saveBinaryValue( xxx, sizeof(int)*3);
} }