Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

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                                 typedef ::s11n::node_traits<node_type> NT;
00082                                 size_t depth = this->m_depth++;
00083                                 if ( 0 == depth )
00084                                 {
00085                                         dest << this->magic_cookie() << '\n';
00086                                 }
00087 
00088 
00089                                 std::string nname = NT::name(src);
00090                                 std::string impl = NT::class_name(src);
00091                                 std::string indent;
00092                                 const entity_translation_map & trans = this->entity_translations();
00093 
00094                                 std::string ximpl = impl;
00095                                 ::s11n::io::strtool::translate( ximpl, trans, false );
00096 
00097                                 INDENT(0,1);
00098                                 dest << "<" << nname << " s11n_class=\"" << ximpl << "\"";
00099 
00100                                 std::string propval;
00101                                 std::string key;
00102 
00103                                 typedef typename NT::property_map_type::const_iterator PropIT;
00104                 PropIT it = NT::properties(src).begin();
00105                 PropIT et = NT::properties(src).end();
00106                                 if ( it != et )
00107                                 {
00108                                         for ( ; it != et; ++it )
00109                                         {
00110                                                 key = (*it).first;
00111                                                 if ( key == std::string("CDATA") )
00112                                                         continue;   // special treatment later on
00113                                                 propval = (*it).second;
00114                                                 ::s11n::io::strtool::translate_entities( propval, trans, false );
00115                                                 dest << " " << key << "=\"" << propval << "\"";
00116                                         }
00117                                 }
00118 
00119                                 bool use_closer = false; // if false then an element can <close_itself />
00120                                 if ( NT::is_set( src, std::string("CDATA") ) )
00121                                 {
00122                                         dest << ">";
00123                                         use_closer = true;
00124                                         dest << "<![CDATA[" << NT::get( src, "CDATA", std::string("") ) << "]]>";
00125                                 }
00126 
00127 
00128                                 bool tailindent = false;
00129 
00130                                 if( NT::children(src).end() != NT::children(src).begin() )
00131                                 {
00132                                         if( ! use_closer ) dest << '>';
00133                                         use_closer = true;
00134                                         tailindent = true;
00135                                         dest << '\n';
00136                                         std::for_each( NT::children(src).begin(),
00137                                                        NT::children(src).end(),
00138                                                        node_child_simple_formatter<this_type>( *this,
00139                                                                                          dest,
00140                                                                                          "",
00141                                                                                          "" )
00142                                                        );
00143                                 }
00144 
00145                                 dest << ( tailindent ? indent : "" );
00146                                 if( use_closer )
00147                                 {
00148                                         dest << "</" << nname << '>';
00149                                 }
00150                                 else
00151                                 {
00152                                         dest << " />";
00153                     // dest << "></"<<nname<<'>';
00154                                 }
00155                                 dest << '\n';
00156 
00157                                 if( 0 == depth )
00158                                 {
00159                                         dest.flush();
00160                                         // if we don't do this then the client is possibly forced to flush() the stream :/
00161                                 }
00162                                 --this->m_depth;
00163                                 return true;
00164                         }
00165 
00166 
00167                 private:
00168                         size_t m_depth;
00169                 };
00170 
00171 
00172     } // namespace io
00173 } // namespace s11n
00174 #undef INDENT
00175 
00176 #endif // simplexml_SERIALIZER_H_INCLUDED

Generated on Sun Dec 25 20:26:12 2005 for libs11n-1.2.3 by  doxygen 1.4.4