simplexml_serializer.hpp

Go to the documentation of this file.
00001 #ifndef simplexml_SERIALIZER_H_INCLUDED
00002 #define simplexml_SERIALIZER_H_INCLUDED 1
00003 
00004 ////////////////////////////////////////////////////////////////////////
00005 // simplexml_serializer.hpp: a simple XML dialect for the s11n framework
00006 //
00007 // License: Public Domain
00008 // Author: stephan@s11n.net
00009 ////////////////////////////////////////////////////////////////////////
00010 
00011 #include <s11n.net/s11n/io/data_node_format.hpp>
00012 #include <s11n.net/s11n/io/strtool.hpp> // translate_entities()
00013 
00014 #include <s11n.net/s11n/traits.hpp> // node_traits
00015 #define MAGIC_COOKIE_SIMPLEXML "<!DOCTYPE s11n::simplexml>"
00016 
00017 namespace s11n {
00018     namespace io {
00019 
00020 
00021                 /***
00022                     The sharing namespace defines some "sharing contexts"
00023                     for use with s11n::Detail::phoenix. They are used to
00024                     provide contexts in which disparate framework components
00025                     can share data.
00026                 */
00027                 namespace sharing {
00028                         /**
00029                            Sharing context used by simplexml_serializer.
00030                          */
00031                         struct simplexml_sharing_context {};
00032                 }
00033                 typedef std::map<std::string,std::string> entity_translation_map;
00034 
00035                 /**
00036                    The entity translations map used by simplexml_serializer.
00037                  */
00038                 entity_translation_map & simplexml_serializer_translations();
00039 
00040 
00041 
00042 // INDENT() is a helper macro for some serializers.
00043 #define INDENT(LEVEL,ECHO) indent = ""; for( size_t i = 0; i < depth + LEVEL; i++ ) { indent += '\t'; if(ECHO) dest << '\t'; }
00044 
00045                 /**
00046                    De/serializes objects from/to a simple XML grammar,
00047                    with properties stored as XML attibutes and children
00048                    stored as subnodes.
00049                 */
00050                 template <typename NodeType>
00051                 class simplexml_serializer : public tree_builder_lexer<NodeType,sharing::simplexml_sharing_context>
00052                 {
00053                 public:
00054                         typedef NodeType node_type;
00055 
00056                         typedef simplexml_serializer<node_type> this_type; // convenience typedef
00057                         typedef tree_builder_lexer<node_type,sharing::simplexml_sharing_context> parent_type; // convenience typedef
00058 
00059                         simplexml_serializer() : parent_type( "simplexml_data_nodeFlexLexer" ), m_depth(0)
00060                         {
00061                                 this->magic_cookie( MAGIC_COOKIE_SIMPLEXML );
00062                         }
00063 
00064                         virtual ~simplexml_serializer() {}
00065 
00066                         /**
00067                            Reimplemented to return this type's entity
00068                            translation map.
00069                          */
00070                         virtual const entity_translation_map & entity_translations() const
00071                         {
00072                                 return simplexml_serializer_translations();
00073                         }
00074 
00075 
00076                         /**
00077                            Writes src out to dest.
00078                         */
00079                         virtual bool serialize( const node_type & src, std::ostream & dest )
00080             {
00081                 try
00082                 {
00083                     return this->serialize_impl( src, dest );
00084                 }
00085                 catch(...)
00086                 {
00087                     this->m_depth = 0;
00088                     throw;
00089                 }
00090                 return false; // can't get this far.
00091             }
00092 
00093         private:
00094                         /**
00095                            Writes src out to dest.
00096                         */
00097                         bool serialize_impl( const node_type & src, std::ostream & dest )
00098                         {
00099                                 typedef ::s11n::node_traits<node_type> NT;
00100                                 size_t depth = this->m_depth++;
00101                                 if ( 0 == depth )
00102                                 {
00103                                         dest << this->magic_cookie() << '\n';
00104                                 }
00105 
00106 
00107                                 std::string nname = NT::name(src);
00108                                 std::string impl = NT::class_name(src);
00109                                 std::string indent;
00110                                 const entity_translation_map & trans = this->entity_translations();
00111 
00112                                 std::string ximpl = impl;
00113                                 ::s11n::io::strtool::translate( ximpl, trans, false );
00114 
00115                                 INDENT(0,1);
00116                                 dest << "<" << nname << " s11n_class=\"" << ximpl << "\"";
00117 
00118                                 std::string propval;
00119                                 std::string key;
00120 
00121                                 typedef typename NT::property_map_type::const_iterator PropIT;
00122                 PropIT it = NT::properties(src).begin();
00123                 PropIT et = NT::properties(src).end();
00124                                 if ( it != et )
00125                                 {
00126                                         for ( ; it != et; ++it )
00127                                         {
00128                                                 key = (*it).first;
00129                                                 if ( key == std::string("CDATA") )
00130                                                         continue;   // special treatment later on
00131                                                 propval = (*it).second;
00132                                                 ::s11n::io::strtool::translate_entities( propval, trans, false );
00133                                                 dest << " " << key << "=\"" << propval << "\"";
00134                                         }
00135                                 }
00136 
00137                                 bool use_closer = false; // if false then an element can <close_itself />
00138                                 if ( NT::is_set( src, std::string("CDATA") ) )
00139                                 {
00140                                         dest << ">";
00141                                         use_closer = true;
00142                                         dest << "<![CDATA[" << NT::get( src, "CDATA", std::string("") ) << "]]>";
00143                                 }
00144 
00145 
00146                                 bool tailindent = false;
00147 
00148                 typedef typename NT::child_list_type CLT;
00149                 typedef typename CLT::const_iterator CLIT;
00150                 CLIT cit = NT::children(src).begin();
00151                 CLIT cet = NT::children(src).end();
00152                                 if( cit != cet )
00153                                 {
00154                                         if( ! use_closer ) dest << '>';
00155                                         use_closer = true;
00156                                         tailindent = true;
00157                                         dest << '\n';
00158                     for( ; cet != cit; ++cit )
00159                     {
00160                         this->serialize_impl( *(*cit), dest );
00161                     }
00162                                 }
00163 
00164                                 dest << ( tailindent ? indent : "" );
00165                                 if( use_closer )
00166                                 {
00167                                         dest << "</" << nname << '>';
00168                                 }
00169                                 else
00170                                 {
00171                                         dest << " />";
00172                     // dest << "></"<<nname<<'>';
00173                                 }
00174                                 dest << '\n';
00175 
00176                                 if( 0 == depth )
00177                                 {
00178                                         dest.flush();
00179                                         // if we don't do this then the client is possibly forced to flush() the stream :/
00180                                 }
00181                                 --this->m_depth;
00182                                 return true;
00183                         }
00184 
00185 
00186                 private:
00187                         size_t m_depth;
00188                 };
00189 
00190 
00191     } // namespace io
00192 } // namespace s11n
00193 #undef INDENT
00194 
00195 #endif // simplexml_SERIALIZER_H_INCLUDED

Generated on Sat Mar 20 12:29:24 2010 for libs11n-1.2.10 by  doxygen 1.6.1