working on input xml

This commit is contained in:
Shane Grant
2013-07-03 12:08:47 -07:00
parent 002b1ceeb1
commit 5cecbdf08f
3 changed files with 211 additions and 175 deletions

View File

@@ -28,49 +28,35 @@
#define CEREAL_ARCHIVES_XML_HPP_ #define CEREAL_ARCHIVES_XML_HPP_
#include <cereal/cereal.hpp> #include <cereal/cereal.hpp>
#include <cereal/details/util.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 <cereal/external/base64.hpp>
#include <sstream> #include <sstream>
#include <stack> #include <stack>
#include <vector>
#include <string> #include <string>
#include <iostream> #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>
{ {
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!
@param precision The precision for floating point output */ @param precision The precision for floating point output
XMLOutputArchive(std::ostream & stream, size_t precision = 10 ) : @param outputType Controls whether type information will be printed in attributes */
OutputArchive<XMLOutputArchive, AllowEmptyClassElision>(this), XMLOutputArchive(std::ostream & stream, size_t precision = 10, bool outputType = false ) :
itsStream(stream) OutputArchive<XMLOutputArchive>(this),
itsStream(stream),
itsOutputType( outputType )
{ {
// 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 );
@@ -97,20 +83,6 @@ namespace cereal
itsXML.clear(); itsXML.clear();
} }
void createNode( std::string const & name )
{
createNode( name.c_str() );
}
void createNode( char const * name )
{
auto node = itsXML.allocate_node( rapidxml::node_element, name );
itsNodes.top().node->append_node( node );
itsNodes.emplace( node );
node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, "5432" ) );
}
//! Saves some data, encoded as a string //! Saves some data, encoded as a string
/*! The data will be be named with the most recent name if one exists, /*! 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 otherwise it will be given some default delimited value that depends upon
@@ -120,13 +92,9 @@ namespace cereal
{ {
itsOS.clear(); itsOS.seekp(0); itsOS.clear(); itsOS.seekp(0);
itsOS << value << std::ends; itsOS << value << std::ends;
insertValueNode( itsOS.str().c_str() );
}
void insertValueNode( const char * data )
{
// allocate strings for all of the data in the XML object // allocate strings for all of the data in the XML object
auto dataPtr = itsXML.allocate_string( data ); auto dataPtr = itsXML.allocate_string( itsOS.str().c_str() );
// insert into the XML // 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_data, nullptr, dataPtr ) );
@@ -151,6 +119,22 @@ namespace cereal
itsNodes.emplace( node ); itsNodes.emplace( node );
} }
//! Causes the type to be appended to the most recently made node if output type is set to true
template <class T> inline
void insertType()
{
if( !itsOutputType )
return;
// generate a name for this new node
const auto nameString = util::demangledName<T>();
// allocate strings for all of the data in the XML object
auto namePtr = itsXML.allocate_string( nameString.data(), nameString.size() );
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
}
//! Designates the most recently added node as finished //! Designates the most recently added node as finished
void finishNode() void finishNode()
{ {
@@ -163,14 +147,22 @@ namespace cereal
itsNodes.top().name = name; itsNodes.top().name = name;
} }
//! Saves some binary data, encoded as a base64 string //! Saves some binary data, encoded as a base64 string, with an optional name
void saveBinaryValue( const void * data, size_t size ) /*! This will create a new node, optionally named, and insert a value that consists of
the data encoded as a base64 string */
void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
{ {
itsNodes.top().name = name;
startNode();
auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size ); auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
saveValue( base64string ); saveValue( base64string );
//auto decoded = base64::decode(base64string);
//int const * zz = (int const*)decoded.data(); if( itsOutputType )
//std::cout << zz[0] << " " << zz[1] << " " << zz[2] << std::endl; itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
finishNode();
}; };
//! A struct that contains metadata about a node //! A struct that contains metadata about a node
@@ -209,9 +201,41 @@ namespace cereal
rapidxml::xml_document<> itsXML; //!< The XML document rapidxml::xml_document<> itsXML; //!< The XML document
std::stack<NodeInfo> itsNodes; //!< A stack of nodes added to the document std::stack<NodeInfo> itsNodes; //!< A stack of nodes added to the document
std::ostringstream itsOS; //!< Used to format strings internally std::ostringstream itsOS; //!< Used to format strings internally
bool itsOutputType; //!< Controls whether type information is printed
}; // XMLOutputArchive }; // XMLOutputArchive
struct XMLInputArchive; // ######################################################################
//! An output archive designed to save data to XML
class XMLInputArchive : public InputArchive<XMLInputArchive>
{
public:
//! Construct, reading in from the provided stream
/*! Reads in an entire XML document from some stream and parses it as soon
as serialization starts
@param stream The stream to read from. Can be a stringstream or a file. */
XMLInputArchive( std::istream & stream ) :
InputArchive<XMLInputArchive>( this ),
itsStream( stream ),
itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
{
try
{
itsXML.parse<rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
}
catch( rapidxml::parse_error const & e )
{
throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
//std::cout << e.what() << std::endl;
//std::cout << e.where<char>() << std::endl;
}
}
//private:
std::istream & itsStream;
std::vector<uint8_t> itsData; //!< The raw data loaded
rapidxml::xml_document<> itsXML; //!< The XML document
};
// ###################################################################### // ######################################################################
// XMLArchive prologue and epilogue functions // XMLArchive prologue and epilogue functions
@@ -247,6 +271,7 @@ namespace cereal
void prologue( XMLOutputArchive & ar, T const & data ) void prologue( XMLOutputArchive & ar, T const & data )
{ {
ar.startNode(); ar.startNode();
ar.insertType<T>();
} }
//! Epilogue for all other types other for XML archives //! Epilogue for all other types other for XML archives

View File

@@ -299,7 +299,8 @@ int main()
{ {
//std::stringstream os; //std::stringstream os;
cereal::XMLOutputArchive oar( std::cout ); std::ofstream os("out.xml");
cereal::XMLOutputArchive oar( os );
oar( cereal::make_nvp("hello", 5 ) ); oar( cereal::make_nvp("hello", 5 ) );
std::string bla("bla"); std::string bla("bla");
oar( bla ); oar( bla );
@@ -318,13 +319,23 @@ int main()
"there", "there",
"buddy"}; "buddy"};
std::vector<std::vector<std::string>> vec2 = {vec, vec, vec};
Everything e; Everything e;
oar( cereal::make_nvp("EVERYTHING?!", e) ); oar( cereal::make_nvp("EVERYTHING", e) );
oar( vec ); oar( vec );
//int xxx[] = {-1, 95, 3}; oar( vec2 );
//oar.saveBinaryValue( xxx, sizeof(int)*3);
int xxx[] = {-1, 95, 3};
oar.saveBinaryValue( xxx, sizeof(int)*3, "xxxbinary" );
oar.saveBinaryValue( xxx, sizeof(int)*3 );
} }
{
std::ifstream is("out.xml");
cereal::XMLInputArchive oar( is );
std::cout << oar.itsData.size() << std::endl;
}