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_
#include <cereal/cereal.hpp>
#include <cereal/details/util.hpp>
#include <cereal/external/rapidxml/rapidxml.hpp>
#include <cereal/external/rapidxml/rapidxml_print.hpp>
#include <cereal/external/base64.hpp>
#include <sstream>
#include <stack>
#include <vector>
#include <string>
#include <iostream>
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
class XMLOutputArchive : public OutputArchive<XMLOutputArchive, AllowEmptyClassElision>
class XMLOutputArchive : public OutputArchive<XMLOutputArchive>
{
public:
//! Construct, outputting to the provided stream
/*! @param stream The stream to output to. Can be a stringstream, a file stream, or
even cout!
@param precision The precision for floating point output */
XMLOutputArchive(std::ostream & stream, size_t precision = 10 ) :
OutputArchive<XMLOutputArchive, AllowEmptyClassElision>(this),
itsStream(stream)
@param precision The precision for floating point output
@param outputType Controls whether type information will be printed in attributes */
XMLOutputArchive(std::ostream & stream, size_t precision = 10, bool outputType = false ) :
OutputArchive<XMLOutputArchive>(this),
itsStream(stream),
itsOutputType( outputType )
{
// rapidxml will delete all allocations when xml_document is cleared
auto node = itsXML.allocate_node( rapidxml::node_declaration );
@@ -97,20 +83,6 @@ namespace cereal
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
/*! 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
@@ -120,13 +92,9 @@ namespace cereal
{
itsOS.clear(); itsOS.seekp(0);
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
auto dataPtr = itsXML.allocate_string( data );
auto dataPtr = itsXML.allocate_string( itsOS.str().c_str() );
// insert into the XML
itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
@@ -151,6 +119,22 @@ namespace cereal
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
void finishNode()
{
@@ -163,14 +147,22 @@ namespace cereal
itsNodes.top().name = name;
}
//! Saves some binary data, encoded as a base64 string
void saveBinaryValue( const void * data, size_t size )
//! Saves some binary data, encoded as a base64 string, with an optional name
/*! 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 );
saveValue( base64string );
//auto decoded = base64::decode(base64string);
//int const * zz = (int const*)decoded.data();
//std::cout << zz[0] << " " << zz[1] << " " << zz[2] << std::endl;
if( itsOutputType )
itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
finishNode();
};
//! A struct that contains metadata about a node
@@ -209,9 +201,41 @@ namespace cereal
rapidxml::xml_document<> itsXML; //!< The XML document
std::stack<NodeInfo> itsNodes; //!< A stack of nodes added to the document
std::ostringstream itsOS; //!< Used to format strings internally
bool itsOutputType; //!< Controls whether type information is printed
}; // 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
@@ -247,6 +271,7 @@ namespace cereal
void prologue( XMLOutputArchive & ar, T const & data )
{
ar.startNode();
ar.insertType<T>();
}
//! Epilogue for all other types other for XML archives

View File

@@ -1,122 +1,122 @@
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
#define RAPIDXML_UTILS_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
#include "rapidxml.hpp"
#include <vector>
#include <string>
#include <fstream>
#include <stdexcept>
namespace rapidxml
{
//! Represents data loaded from a file
template<class Ch = char>
class file
{
public:
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
//! \param filename Filename to load.
file(const char *filename)
{
using namespace std;
// Open stream
basic_ifstream<Ch> stream(filename, ios::binary);
if (!stream)
throw runtime_error(string("cannot open file ") + filename);
stream.unsetf(ios::skipws);
// Determine stream size
stream.seekg(0, ios::end);
size_t size = stream.tellg();
stream.seekg(0);
// Load data and add terminating 0
m_data.resize(size + 1);
stream.read(&m_data.front(), static_cast<streamsize>(size));
m_data[size] = 0;
}
//! Loads file into the memory. Data will be automatically destroyed by the destructor
//! \param stream Stream to load from
file(std::basic_istream<Ch> &stream)
{
using namespace std;
// Load data and add terminating 0
stream.unsetf(ios::skipws);
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
if (stream.fail() || stream.bad())
throw runtime_error("error reading stream");
m_data.push_back(0);
}
//! Gets file data.
//! \return Pointer to data of file.
Ch *data()
{
return &m_data.front();
}
//! Gets file data.
//! \return Pointer to data of file.
const Ch *data() const
{
return &m_data.front();
}
//! Gets file data size.
//! \return Size of file data, in characters.
std::size_t size() const
{
return m_data.size();
}
private:
std::vector<Ch> m_data; // File data
};
//! Counts children of node. Time complexity is O(n).
//! \return Number of children of node
template<class Ch>
inline std::size_t count_children(xml_node<Ch> *node)
{
xml_node<Ch> *child = node->first_node();
std::size_t count = 0;
while (child)
{
++count;
child = child->next_sibling();
}
return count;
}
//! Counts attributes of node. Time complexity is O(n).
//! \return Number of attributes of node
template<class Ch>
inline std::size_t count_attributes(xml_node<Ch> *node)
{
xml_attribute<Ch> *attr = node->first_attribute();
std::size_t count = 0;
while (attr)
{
++count;
attr = attr->next_attribute();
}
return count;
}
}
#endif
#ifndef RAPIDXML_UTILS_HPP_INCLUDED
#define RAPIDXML_UTILS_HPP_INCLUDED
// Copyright (C) 2006, 2009 Marcin Kalicinski
// Version 1.13
// Revision $DateTime: 2009/05/13 01:46:17 $
//! \file rapidxml_utils.hpp This file contains high-level rapidxml utilities that can be useful
//! in certain simple scenarios. They should probably not be used if maximizing performance is the main objective.
#include "rapidxml.hpp"
#include <vector>
#include <string>
#include <fstream>
#include <stdexcept>
namespace rapidxml
{
//! Represents data loaded from a file
template<class Ch = char>
class file
{
public:
//! Loads file into the memory. Data will be automatically destroyed by the destructor.
//! \param filename Filename to load.
file(const char *filename)
{
using namespace std;
// Open stream
basic_ifstream<Ch> stream(filename, ios::binary);
if (!stream)
throw runtime_error(string("cannot open file ") + filename);
stream.unsetf(ios::skipws);
// Determine stream size
stream.seekg(0, ios::end);
size_t size = stream.tellg();
stream.seekg(0);
// Load data and add terminating 0
m_data.resize(size + 1);
stream.read(&m_data.front(), static_cast<streamsize>(size));
m_data[size] = 0;
}
//! Loads file into the memory. Data will be automatically destroyed by the destructor
//! \param stream Stream to load from
file(std::basic_istream<Ch> &stream)
{
using namespace std;
// Load data and add terminating 0
stream.unsetf(ios::skipws);
m_data.assign(istreambuf_iterator<Ch>(stream), istreambuf_iterator<Ch>());
if (stream.fail() || stream.bad())
throw runtime_error("error reading stream");
m_data.push_back(0);
}
//! Gets file data.
//! \return Pointer to data of file.
Ch *data()
{
return &m_data.front();
}
//! Gets file data.
//! \return Pointer to data of file.
const Ch *data() const
{
return &m_data.front();
}
//! Gets file data size.
//! \return Size of file data, in characters.
std::size_t size() const
{
return m_data.size();
}
private:
std::vector<Ch> m_data; // File data
};
//! Counts children of node. Time complexity is O(n).
//! \return Number of children of node
template<class Ch>
inline std::size_t count_children(xml_node<Ch> *node)
{
xml_node<Ch> *child = node->first_node();
std::size_t count = 0;
while (child)
{
++count;
child = child->next_sibling();
}
return count;
}
//! Counts attributes of node. Time complexity is O(n).
//! \return Number of attributes of node
template<class Ch>
inline std::size_t count_attributes(xml_node<Ch> *node)
{
xml_attribute<Ch> *attr = node->first_attribute();
std::size_t count = 0;
while (attr)
{
++count;
attr = attr->next_attribute();
}
return count;
}
}
#endif

View File

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