diff --git a/include/cereal/archives/xml.hpp b/include/cereal/archives/xml.hpp index 7db51034..ef125ec0 100644 --- a/include/cereal/archives/xml.hpp +++ b/include/cereal/archives/xml.hpp @@ -309,7 +309,23 @@ namespace cereal //! Prepares to start reading the next node void startNode() { - itsNodes.emplace( itsNodes.top().child ); + auto next = itsNodes.top().child; + auto const expectedName = itsNodes.top().name; + + std::cerr << "Expected name was " << expectedName << ", actual name was: " << next->name() << std::endl; + + // If the expected name does not match the loaded name, try to load the NVP name + // If we can't find the NVP name, throw an exception + if( expectedName && std::strcmp( next->name(), expectedName ) != 0 ) + { + std::cerr << "Loading " << expectedName << std::endl; + next = itsXML.first_node( expectedName ); + if( next == nullptr ) + throw Exception("XML Parsing failed - provided NVP not found"); + } + + itsNodes.emplace( next ); + //itsNodes.emplace( itsNodes.top().child ); } //! Finishes reading the current node @@ -320,6 +336,16 @@ namespace cereal // advance parent itsNodes.top().advance(); + + // Reset name + itsNodes.top().name = nullptr; + } + + //! Sets the name for the next node created with startNode + void setNextName( const char * name ) + { + std::cerr << "Setting next name to be " << name << std::endl; + itsNodes.top().name = name; } //! Loads a bool @@ -450,7 +476,8 @@ namespace cereal NodeInfo( rapidxml::xml_node<> * n = nullptr ) : node( n ), child( n ? n->first_node() : nullptr ), - size( XMLInputArchive::getNumChildren( n ) ) + size( XMLInputArchive::getNumChildren( n ) ), + name( nullptr ) { } void advance() @@ -465,6 +492,7 @@ namespace cereal rapidxml::xml_node<> * node; //!< A pointer to this node rapidxml::xml_node<> * child; //!< A pointer to its current child size_t size; + const char * name; //!< The NVP name for next next child node }; // NodeInfo private: @@ -574,6 +602,7 @@ namespace cereal template inline void load( XMLInputArchive & ar, NameValuePair & t ) { + ar.setNextName( t.name ); ar( t.value ); } diff --git a/sandbox.cpp b/sandbox.cpp index a434f1be..0c937baf 100644 --- a/sandbox.cpp +++ b/sandbox.cpp @@ -500,6 +500,50 @@ int main() std::remove("endian.out"); } + { + std::ofstream ss("xml_ordering.out"); + cereal::XMLOutputArchive ar(ss); + + double one = 1; + double two = 2; + double three = 3; + std::vector four = {1, 2, 3, 4}; + + // Output is ordered 3 2 1 4 + ar( three, CEREAL_NVP(two), one, cereal::make_nvp("five", four) ); + } + + { + std::ifstream ss("xml_ordering.out"); + cereal::XMLInputArchive ar(ss); + + // Output prodered out of order, try to load in order 1 2 3 4 + double one; + double two; + double three; + std::vector four; + + ar( one ); // cereal can only give warnings if you used an NVP! + ar( CEREAL_NVP( two ) ); + ar( three ); + + try + { + ar( CEREAL_NVP( three ) ); + } + catch( cereal::Exception const & e ) + { + std::cout << e.what() << std::endl; + std::cout << "Looked for three but we didn't use an NVP when saving" << std::endl; + } + ar( cereal::make_nvp("five", four) ); + + std::cout << one << std::endl; + std::cout << two << std::endl; + std::cout << three << std::endl; + for( auto i : four ) std::cout << i << " "; + std::cout << std::endl; + } return 0;