cereal
A C++11 library for serialization
xml.hpp
Go to the documentation of this file.
1
3/*
4 Copyright (c) 2014, Randolph Voorhies, Shane Grant
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of the copyright holder nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29#ifndef CEREAL_ARCHIVES_XML_HPP_
30#define CEREAL_ARCHIVES_XML_HPP_
31#include "cereal/cereal.hpp"
33
34#include "cereal/external/rapidxml/rapidxml.hpp"
35#include "cereal/external/rapidxml/rapidxml_print.hpp"
36#include "cereal/external/base64.hpp"
37
38#include <sstream>
39#include <stack>
40#include <vector>
41#include <limits>
42#include <string>
43#include <cstring>
44#include <cmath>
45
46namespace cereal
47{
48 namespace xml_detail
49 {
50 #ifndef CEREAL_XML_STRING_VALUE
52
54 #define CEREAL_XML_STRING_VALUE "cereal"
55 #endif // CEREAL_XML_STRING_VALUE
56
58 static const char * CEREAL_XML_STRING = CEREAL_XML_STRING_VALUE;
59
61 inline bool isWhitespace( char c )
62 {
63 return c == ' ' || c == '\t' || c == '\n' || c == '\r';
64 }
65 }
66
67 // ######################################################################
69
96 class XMLOutputArchive : public OutputArchive<XMLOutputArchive>, public traits::TextArchive
97 {
98 public:
102
104
107 {
108 public:
110 static Options Default(){ return Options(); }
111
113
117 explicit Options( int precision_ = std::numeric_limits<double>::max_digits10,
118 bool indent_ = true,
119 bool outputType_ = false,
120 bool sizeAttributes_ = true ) :
121 itsPrecision( precision_ ),
122 itsIndent( indent_ ),
123 itsOutputType( outputType_ ),
124 itsSizeAttributes( sizeAttributes_ )
125 { }
126
138
140 Options & precision( int value ){ itsPrecision = value; return * this; }
142 Options & indent( bool enable ){ itsIndent = enable; return *this; }
144 Options & outputType( bool enable ){ itsOutputType = enable; return *this; }
146 Options & sizeAttributes( bool enable ){ itsSizeAttributes = enable; return *this; }
147
149
150 private:
151 friend class XMLOutputArchive;
152 int itsPrecision;
153 bool itsIndent;
154 bool itsOutputType;
155 bool itsSizeAttributes;
156 };
157
159
163 XMLOutputArchive( std::ostream & stream, Options const & options = Options::Default() ) :
165 itsStream(stream),
166 itsOutputType( options.itsOutputType ),
167 itsIndent( options.itsIndent ),
168 itsSizeAttributes(options.itsSizeAttributes)
169 {
170 // rapidxml will delete all allocations when xml_document is cleared
171 auto node = itsXML.allocate_node( rapidxml::node_declaration );
172 node->append_attribute( itsXML.allocate_attribute( "version", "1.0" ) );
173 node->append_attribute( itsXML.allocate_attribute( "encoding", "utf-8" ) );
174 itsXML.append_node( node );
175
176 // allocate root node
177 auto root = itsXML.allocate_node( rapidxml::node_element, xml_detail::CEREAL_XML_STRING );
178 itsXML.append_node( root );
179 itsNodes.emplace( root );
180
181 // set attributes on the streams
182 itsStream << std::boolalpha;
183 itsStream.precision( options.itsPrecision );
184 itsOS << std::boolalpha;
185 itsOS.precision( options.itsPrecision );
186 }
187
190 {
191 const int flags = itsIndent ? 0x0 : rapidxml::print_no_indenting;
192 rapidxml::print( itsStream, itsXML, flags );
193 itsXML.clear();
194 }
195
197
200 void saveBinaryValue( const void * data, size_t size, const char * name = nullptr )
201 {
202 itsNodes.top().name = name;
203
204 startNode();
205
206 auto base64string = base64::encode( reinterpret_cast<const unsigned char *>( data ), size );
207 saveValue( base64string );
208
209 if( itsOutputType )
210 itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
211
212 finishNode();
213 }
214
216
220
222
228 {
229 // generate a name for this new node
230 const auto nameString = itsNodes.top().getValueName();
231
232 // allocate strings for all of the data in the XML object
233 auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
234
235 // insert into the XML
236 auto node = itsXML.allocate_node( rapidxml::node_element, namePtr, nullptr, nameString.size() );
237 itsNodes.top().node->append_node( node );
238 itsNodes.emplace( node );
239 }
240
243 {
244 itsNodes.pop();
245 }
246
248 void setNextName( const char * name )
249 {
250 itsNodes.top().name = name;
251 }
252
254
257 template <class T> inline
258 void saveValue( T const & value )
259 {
260 itsOS.clear(); itsOS.seekp( 0, std::ios::beg );
261 itsOS << value << std::ends;
262
263 auto strValue = itsOS.str();
264
265 // itsOS.str() may contain data from previous calls after the first '\0' that was just inserted
266 // and this data is counted in the length call. We make sure to remove that section so that the
267 // whitespace validation is done properly
268 strValue.resize(std::strlen(strValue.c_str()));
269
270 // If the first or last character is a whitespace, add xml:space attribute
271 const auto len = strValue.length();
272 if ( len > 0 && ( xml_detail::isWhitespace( strValue[0] ) || xml_detail::isWhitespace( strValue[len - 1] ) ) )
273 {
274 itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "xml:space", "preserve" ) );
275 }
276
277 // allocate strings for all of the data in the XML object
278 auto dataPtr = itsXML.allocate_string(strValue.c_str(), strValue.length() + 1 );
279
280 // insert into the XML
281 itsNodes.top().node->append_node( itsXML.allocate_node( rapidxml::node_data, nullptr, dataPtr ) );
282 }
283
285 void saveValue( uint8_t const & value )
286 {
287 saveValue( static_cast<uint32_t>( value ) );
288 }
289
291 void saveValue( int8_t const & value )
292 {
293 saveValue( static_cast<int32_t>( value ) );
294 }
295
297 template <class T> inline
299 {
300 if( !itsOutputType )
301 return;
302
303 // generate a name for this new node
304 const auto nameString = util::demangledName<T>();
305
306 // allocate strings for all of the data in the XML object
307 auto namePtr = itsXML.allocate_string( nameString.data(), nameString.length() + 1 );
308
309 itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", namePtr ) );
310 }
311
313 void appendAttribute( const char * name, const char * value )
314 {
315 auto namePtr = itsXML.allocate_string( name );
316 auto valuePtr = itsXML.allocate_string( value );
317 itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
318 }
319
320 bool hasSizeAttributes() const { return itsSizeAttributes; }
321
322 protected:
324 struct NodeInfo
325 {
326 NodeInfo( rapidxml::xml_node<> * n = nullptr,
327 const char * nm = nullptr ) :
328 node( n ),
329 counter( 0 ),
330 name( nm )
331 { }
332
333 rapidxml::xml_node<> * node;
334 size_t counter;
335 const char * name;
336
338
341 std::string getValueName()
342 {
343 if( name )
344 {
345 auto n = name;
346 name = nullptr;
347 return {n};
348 }
349 else
350 return "value" + std::to_string( counter++ ) + "\0";
351 }
352 }; // NodeInfo
353
355
356 private:
357 std::ostream & itsStream;
358 rapidxml::xml_document<> itsXML;
359 std::stack<NodeInfo> itsNodes;
360 std::ostringstream itsOS;
361 bool itsOutputType;
362 bool itsIndent;
363 bool itsSizeAttributes;
364 }; // XMLOutputArchive
365
366 // ######################################################################
368
405 class XMLInputArchive : public InputArchive<XMLInputArchive>, public traits::TextArchive
406 {
407 public:
411
413
417 XMLInputArchive( std::istream & stream ) :
419 itsData( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() )
420 {
421 try
422 {
423 itsData.push_back('\0'); // rapidxml will do terrible things without the data being null terminated
424 itsXML.parse<rapidxml::parse_trim_whitespace | rapidxml::parse_no_data_nodes | rapidxml::parse_declaration_node>( reinterpret_cast<char *>( itsData.data() ) );
425 }
426 catch( rapidxml::parse_error const & )
427 {
428 //std::cerr << "-----Original-----" << std::endl;
429 //stream.seekg(0);
430 //std::cout << std::string( std::istreambuf_iterator<char>( stream ), std::istreambuf_iterator<char>() ) << std::endl;
431
432 //std::cerr << "-----Error-----" << std::endl;
433 //std::cerr << e.what() << std::endl;
434 //std::cerr << e.where<char>() << std::endl;
435 throw Exception("XML Parsing failed - likely due to invalid characters or invalid naming");
436 }
437
438 // Parse the root
439 auto root = itsXML.first_node( xml_detail::CEREAL_XML_STRING );
440 if( root == nullptr )
441 throw Exception("Could not detect cereal root node - likely due to empty or invalid input");
442 else
443 itsNodes.emplace( root );
444 }
445
447
449
454 void loadBinaryValue( void * data, size_t size, const char * name = nullptr )
455 {
456 setNextName( name );
457 startNode();
458
459 std::string encoded;
460 loadValue( encoded );
461
462 auto decoded = base64::decode( encoded );
463
464 if( size != decoded.size() )
465 throw Exception("Decoded binary data size does not match specified size");
466
467 std::memcpy( data, decoded.data(), decoded.size() );
468
469 finishNode();
470 }
471
473
477
479
489 {
490 auto next = itsNodes.top().child; // By default we would move to the next child node
491 auto const expectedName = itsNodes.top().name; // this is the expected name from the NVP, if provided
492
493 // If we were given an NVP name, look for it in the current level of the document.
494 // We only need to do this if either we have exhausted the siblings of the current level or
495 // the NVP name does not match the name of the node we would normally read next
496 if( expectedName && ( next == nullptr || std::strcmp( next->name(), expectedName ) != 0 ) )
497 {
498 next = itsNodes.top().search( expectedName );
499
500 if( next == nullptr )
501 throw Exception("XML Parsing failed - provided NVP (" + std::string(expectedName) + ") not found");
502 }
503
504 itsNodes.emplace( next );
505 }
506
509 {
510 // remove current
511 itsNodes.pop();
512
513 // advance parent
514 itsNodes.top().advance();
515
516 // Reset name
517 itsNodes.top().name = nullptr;
518 }
519
522 const char * getNodeName() const
523 {
524 return itsNodes.top().getChildName();
525 }
526
528 void setNextName( const char * name )
529 {
530 itsNodes.top().name = name;
531 }
532
534 template <class T, traits::EnableIf<std::is_unsigned<T>::value,
535 std::is_same<T, bool>::value> = traits::sfinae> inline
536 void loadValue( T & value )
537 {
538 std::istringstream is( itsNodes.top().node->value() );
539 is.setf( std::ios::boolalpha );
540 is >> value;
541 }
542
544 template <class T, traits::EnableIf<std::is_integral<T>::value,
545 !std::is_same<T, bool>::value,
546 sizeof(T) == sizeof(char)> = traits::sfinae> inline
547 void loadValue( T & value )
548 {
549 value = *reinterpret_cast<T*>( itsNodes.top().node->value() );
550 }
551
553 void loadValue( int8_t & value )
554 {
555 int32_t val; loadValue( val ); value = static_cast<int8_t>( val );
556 }
557
559 void loadValue( uint8_t & value )
560 {
561 uint32_t val; loadValue( val ); value = static_cast<uint8_t>( val );
562 }
563
565 template <class T, traits::EnableIf<std::is_unsigned<T>::value,
566 !std::is_same<T, bool>::value,
567 !std::is_same<T, char>::value,
568 !std::is_same<T, unsigned char>::value,
569 sizeof(T) < sizeof(long long)> = traits::sfinae> inline
570 void loadValue( T & value )
571 {
572 value = static_cast<T>( std::stoul( itsNodes.top().node->value() ) );
573 }
574
576 template <class T, traits::EnableIf<std::is_unsigned<T>::value,
577 !std::is_same<T, bool>::value,
578 sizeof(T) >= sizeof(long long)> = traits::sfinae> inline
579 void loadValue( T & value )
580 {
581 value = static_cast<T>( std::stoull( itsNodes.top().node->value() ) );
582 }
583
585 template <class T, traits::EnableIf<std::is_signed<T>::value,
586 !std::is_same<T, char>::value,
587 sizeof(T) <= sizeof(int)> = traits::sfinae> inline
588 void loadValue( T & value )
589 {
590 value = static_cast<T>( std::stoi( itsNodes.top().node->value() ) );
591 }
592
594 template <class T, traits::EnableIf<std::is_signed<T>::value,
595 (sizeof(T) > sizeof(int)),
596 sizeof(T) <= sizeof(long)> = traits::sfinae> inline
597 void loadValue( T & value )
598 {
599 value = static_cast<T>( std::stol( itsNodes.top().node->value() ) );
600 }
601
603 template <class T, traits::EnableIf<std::is_signed<T>::value,
604 (sizeof(T) > sizeof(long)),
605 sizeof(T) <= sizeof(long long)> = traits::sfinae> inline
606 void loadValue( T & value )
607 {
608 value = static_cast<T>( std::stoll( itsNodes.top().node->value() ) );
609 }
610
612 void loadValue( float & value )
613 {
614 try
615 {
616 value = std::stof( itsNodes.top().node->value() );
617 }
618 catch( std::out_of_range const & )
619 {
620 // special case for denormalized values
621 std::istringstream is( itsNodes.top().node->value() );
622 is >> value;
623 if( std::fpclassify( value ) != FP_SUBNORMAL )
624 throw;
625 }
626 }
627
629 void loadValue( double & value )
630 {
631 try
632 {
633 value = std::stod( itsNodes.top().node->value() );
634 }
635 catch( std::out_of_range const & )
636 {
637 // special case for denormalized values
638 std::istringstream is( itsNodes.top().node->value() );
639 is >> value;
640 if( std::fpclassify( value ) != FP_SUBNORMAL )
641 throw;
642 }
643 }
644
646 void loadValue( long double & value )
647 {
648 try
649 {
650 value = std::stold( itsNodes.top().node->value() );
651 }
652 catch( std::out_of_range const & )
653 {
654 // special case for denormalized values
655 std::istringstream is( itsNodes.top().node->value() );
656 is >> value;
657 if( std::fpclassify( value ) != FP_SUBNORMAL )
658 throw;
659 }
660 }
661
663 template<class CharT, class Traits, class Alloc> inline
664 void loadValue( std::basic_string<CharT, Traits, Alloc> & str )
665 {
666 std::basic_istringstream<CharT, Traits> is( itsNodes.top().node->value() );
667
668 str.assign( std::istreambuf_iterator<CharT, Traits>( is ),
669 std::istreambuf_iterator<CharT, Traits>() );
670 }
671
673 template <class T> inline
674 void loadSize( T & value )
675 {
676 value = getNumChildren( itsNodes.top().node );
677 }
678
679 protected:
681 static size_t getNumChildren( rapidxml::xml_node<> * node )
682 {
683 size_t size = 0;
684 node = node->first_node(); // get first child
685
686 while( node != nullptr )
687 {
688 ++size;
689 node = node->next_sibling();
690 }
691
692 return size;
693 }
694
696
698 struct NodeInfo
699 {
700 NodeInfo( rapidxml::xml_node<> * n = nullptr ) :
701 node( n ),
702 child( n->first_node() ),
704 name( nullptr )
705 { }
706
708
709 void advance()
710 {
711 if( size > 0 )
712 {
713 --size;
714 child = child->next_sibling();
715 }
716 }
717
719
721 rapidxml::xml_node<> * search( const char * searchName )
722 {
723 if( searchName )
724 {
725 size_t new_size = XMLInputArchive::getNumChildren( node );
726 const size_t name_size = rapidxml::internal::measure( searchName );
727
728 for( auto new_child = node->first_node(); new_child != nullptr; new_child = new_child->next_sibling() )
729 {
730 if( rapidxml::internal::compare( new_child->name(), new_child->name_size(), searchName, name_size, true ) )
731 {
732 size = new_size;
733 child = new_child;
734
735 return new_child;
736 }
737 --new_size;
738 }
739 }
740
741 return nullptr;
742 }
743
745 const char * getChildName() const
746 {
747 return child ? child->name() : nullptr;
748 }
749
750 rapidxml::xml_node<> * node;
751 rapidxml::xml_node<> * child;
752 size_t size;
753 const char * name;
754 }; // NodeInfo
755
757
758 private:
759 std::vector<char> itsData;
760 rapidxml::xml_document<> itsXML;
761 std::stack<NodeInfo> itsNodes;
762 };
763
764 // ######################################################################
765 // XMLArchive prologue and epilogue functions
766 // ######################################################################
767
768 // ######################################################################
770
771 template <class T> inline
773 { }
774
776 template <class T> inline
778 { }
779
780 // ######################################################################
782
783 template <class T> inline
785 { }
786
788 template <class T> inline
790 { }
791
792 // ######################################################################
794
795 template <class T> inline
797 { }
798
800 template <class T> inline
802 { }
803
804 // ######################################################################
806
807 template <class T> inline
809 { }
810
812
813 template <class T> inline
815 { }
816
817 // ######################################################################
819
820 template <class T> inline
822 {
823 if (ar.hasSizeAttributes())
824 {
825 ar.appendAttribute("size", "dynamic");
826 }
827 }
828
829 template <class T> inline
830 void prologue( XMLInputArchive &, SizeTag<T> const & )
831 { }
832
834
835 template <class T> inline
837 { }
838
839 template <class T> inline
840 void epilogue( XMLInputArchive &, SizeTag<T> const & )
841 { }
842
843 // ######################################################################
845
849 template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
850 traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
851 void prologue( XMLOutputArchive & ar, T const & )
852 {
853 ar.startNode();
854 ar.insertType<T>();
855 }
856
858 template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
859 traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
860 void prologue( XMLInputArchive & ar, T const & )
861 {
862 ar.startNode();
863 }
864
865 // ######################################################################
867
870 template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_output_serialization, XMLOutputArchive>::value ||
871 traits::has_minimal_output_serialization<T, XMLOutputArchive>::value> = traits::sfinae> inline
872 void epilogue( XMLOutputArchive & ar, T const & )
873 {
874 ar.finishNode();
875 }
876
878 template <class T, traits::DisableIf<traits::has_minimal_base_class_serialization<T, traits::has_minimal_input_serialization, XMLInputArchive>::value ||
879 traits::has_minimal_input_serialization<T, XMLInputArchive>::value> = traits::sfinae> inline
880 void epilogue( XMLInputArchive & ar, T const & )
881 {
882 ar.finishNode();
883 }
884
885 // ######################################################################
886 // Common XMLArchive serialization functions
887 // ######################################################################
888
890 template <class T> inline
892 {
893 ar.setNextName( t.name );
894 ar( t.value );
895 }
896
898 template <class T> inline
900 {
901 ar.setNextName( t.name );
902 ar( t.value );
903 }
904
905 // ######################################################################
907 template <class T> inline
909 { }
910
912 template <class T> inline
914 {
915 ar.loadSize( st.size );
916 }
917
918 // ######################################################################
920 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
922 {
923 ar.saveValue( t );
924 }
925
927 template <class T, traits::EnableIf<std::is_arithmetic<T>::value> = traits::sfinae> inline
929 {
930 ar.loadValue( t );
931 }
932
933 // ######################################################################
935 template<class CharT, class Traits, class Alloc> inline
936 void CEREAL_SAVE_FUNCTION_NAME(XMLOutputArchive & ar, std::basic_string<CharT, Traits, Alloc> const & str)
937 {
938 ar.saveValue( str );
939 }
940
942 template<class CharT, class Traits, class Alloc> inline
943 void CEREAL_LOAD_FUNCTION_NAME(XMLInputArchive & ar, std::basic_string<CharT, Traits, Alloc> & str)
944 {
945 ar.loadValue( str );
946 }
947} // namespace cereal
948
949// register archives for polymorphic support
952
953// tie input and output archives together
955
956#endif // CEREAL_ARCHIVES_XML_HPP_
Main cereal functionality.
A wrapper around data that should be serialized after all non-deferred data.
Definition: helpers.hpp:233
The base input archive class.
Definition: cereal.hpp:711
For holding name value pairs.
Definition: helpers.hpp:140
The base output archive class.
Definition: cereal.hpp:319
A wrapper around size metadata.
Definition: helpers.hpp:313
An output archive designed to load data from XML.
Definition: xml.hpp:406
void finishNode()
Finishes reading the current node.
Definition: xml.hpp:508
static size_t getNumChildren(rapidxml::xml_node<> *node)
Gets the number of children (usually interpreted as size) for the specified node.
Definition: xml.hpp:681
void loadValue(int8_t &value)
Load an int8_t from the current top node (ensures we parse entire number)
Definition: xml.hpp:553
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: xml.hpp:528
void loadValue(std::basic_string< CharT, Traits, Alloc > &str)
Loads a string from the current node from the current top node.
Definition: xml.hpp:664
void loadValue(long double &value)
Loads a type best represented as a long double from the current top node.
Definition: xml.hpp:646
void startNode()
Prepares to start reading the next node.
Definition: xml.hpp:488
void loadBinaryValue(void *data, size_t size, const char *name=nullptr)
Loads some binary data, encoded as a base64 string, optionally specified by some name.
Definition: xml.hpp:454
XMLInputArchive(std::istream &stream)
Construct, reading in from the provided stream.
Definition: xml.hpp:417
const char * getNodeName() const
Definition: xml.hpp:522
value
Loads a type best represented as an int from the current top node.
Definition: xml.hpp:639
void loadValue(T &value)
Loads a bool from the current top node.
Definition: xml.hpp:536
void loadSize(T &value)
Loads the size of the current top node.
Definition: xml.hpp:674
void loadValue(uint8_t &value)
Load a uint8_t from the current top node (ensures we parse entire number)
Definition: xml.hpp:559
A class containing various advanced options for the XML archive.
Definition: xml.hpp:107
Options & precision(int value)
Sets the precision used for floaing point numbers.
Definition: xml.hpp:140
Options & sizeAttributes(bool enable)
Whether dynamically sized containers (e.g. vector) output the size=dynamic attribute.
Definition: xml.hpp:146
Options & outputType(bool enable)
Whether to output the type of each serialized object as an attribute.
Definition: xml.hpp:144
static Options Default()
Default options.
Definition: xml.hpp:110
Options(int precision_=std::numeric_limits< double >::max_digits10, bool indent_=true, bool outputType_=false, bool sizeAttributes_=true)
Specify specific options for the XMLOutputArchive.
Definition: xml.hpp:117
Options & indent(bool enable)
Whether to indent each line of XML.
Definition: xml.hpp:142
An output archive designed to save data to XML.
Definition: xml.hpp:97
void saveValue(int8_t const &value)
Overload for int8_t prevents them from being serialized as characters.
Definition: xml.hpp:291
~XMLOutputArchive() CEREAL_NOEXCEPT
Destructor, flushes the XML.
Definition: xml.hpp:189
void saveBinaryValue(const void *data, size_t size, const char *name=nullptr)
Saves some binary data, encoded as a base64 string, with an optional name.
Definition: xml.hpp:200
void saveValue(uint8_t const &value)
Overload for uint8_t prevents them from being serialized as characters.
Definition: xml.hpp:285
XMLOutputArchive(std::ostream &stream, Options const &options=Options::Default())
Construct, outputting to the provided stream upon destruction.
Definition: xml.hpp:163
void startNode()
Creates a new node that is a child of the node at the top of the stack.
Definition: xml.hpp:227
void insertType()
Causes the type to be appended as an attribute to the most recently made node if output type is set t...
Definition: xml.hpp:298
void saveValue(T const &value)
Saves some data, encoded as a string, into the current top level node.
Definition: xml.hpp:258
void setNextName(const char *name)
Sets the name for the next node created with startNode.
Definition: xml.hpp:248
void finishNode()
Designates the most recently added node as finished.
Definition: xml.hpp:242
void appendAttribute(const char *name, const char *value)
Appends an attribute to the current top level node.
Definition: xml.hpp:313
#define CEREAL_REGISTER_ARCHIVE(Archive)
Registers a specific Archive type with cereal.
Definition: cereal.hpp:195
void epilogue(JSONOutputArchive &, NameValuePair< T > const &)
Epilogue for NVPs for JSON archives.
Definition: json.hpp:763
void prologue(JSONOutputArchive &, NameValuePair< T > const &)
Prologue for NVPs for JSON archives.
Definition: json.hpp:751
#define CEREAL_NOEXCEPT
Defines the CEREAL_NOEXCEPT macro to use instead of noexcept.
Definition: macros.hpp:130
#define CEREAL_LOAD_FUNCTION_NAME
The deserialization (load) function name to search for.
Definition: macros.hpp:85
#define CEREAL_SAVE_FUNCTION_NAME
The serialization (save) function name to search for.
Definition: macros.hpp:92
An exception class thrown when things go wrong at runtime.
Definition: helpers.hpp:49
A struct that contains metadata about a node.
Definition: xml.hpp:699
size_t size
The remaining number of children for this node.
Definition: xml.hpp:752
rapidxml::xml_node * child
A pointer to its current child.
Definition: xml.hpp:751
const char * name
The NVP name for next child node.
Definition: xml.hpp:753
const char * getChildName() const
Returns the actual name of the next child node, if it exists.
Definition: xml.hpp:745
rapidxml::xml_node * search(const char *searchName)
Searches for a child with the given name in this node.
Definition: xml.hpp:721
void advance()
Advances to the next sibling node of the child.
Definition: xml.hpp:709
rapidxml::xml_node * node
A pointer to this node.
Definition: xml.hpp:750
A struct that contains metadata about a node.
Definition: xml.hpp:325
rapidxml::xml_node * node
A pointer to this node.
Definition: xml.hpp:333
std::string getValueName()
Gets the name for the next child node created from this node.
Definition: xml.hpp:341
const char * name
The name for the next child node.
Definition: xml.hpp:335
size_t counter
The counter for naming child nodes.
Definition: xml.hpp:334
Type traits only struct used to mark an archive as human readable (text based)
Definition: traits.hpp:1321
#define CEREAL_SETUP_ARCHIVE_TRAITS(InputArchive, OutputArchive)
Sets up traits that relate an input archive to an output archive.
Definition: traits.hpp:169
Internal misc utilities.
#define CEREAL_XML_STRING_VALUE
The default name for the root node in a cereal xml archive.
Definition: xml.hpp:54
bool isWhitespace(char c)
Returns true if the character is whitespace.
Definition: xml.hpp:61