js_serializer.hpp

Go to the documentation of this file.
00001 #ifndef s11n_JS_SERIALIZER_HPP_INCLUDED
00002 #define s11n_JS_SERIALIZER_HPP_INCLUDED 1
00003 
00004 #include <s11n.net/s11n/traits.hpp> // node_traits
00005 
00006 /**
00007 MAGIC_COOKIE_JS defines the magic-cookie which prefixes each
00008 file output by the js_serializer. If the magic cookie
00009 associated with a Serializer changes, older versions of
00010 the serializer will not be able to read the file. Since
00011 js_serializer is write-only, this is not a specific problem
00012 for this serializer, but it should not be changed without
00013 careful consideration nonetheless.
00014 
00015 Note that this macro is #undef'd at the end of this file,
00016 and is therefore unavailable to client code.
00017 */
00018 #define MAGIC_COOKIE_JS "// s11n::io::js_serializer"
00019 
00020 #include <stdexcept>
00021 #include <sstream>
00022 namespace s11n {
00023 
00024         namespace io {
00025 
00026                 namespace sharing {
00027                         /**
00028                            Sharing context used by expat_serializer.
00029                          */
00030                         struct js_sharing_context {};
00031 
00032                 }
00033 
00034         /**
00035            An attempt to quote s as a JS string:
00036 
00037            If s contains no apostrophes, it is returned as 's', with
00038            apostrophes as quotes.
00039            Else, if it contains no double-quotes, "s" is
00040            returned.  Else we backslash-escape the apostrophes
00041            and return 's'.
00042         */
00043         std::string quote_js_string( std::string const & s );
00044 
00045                 /**
00046                    js_serializer writes objects to a Javascript dialect.
00047                 */
00048                 template <typename NodeType>
00049                 class js_serializer : public data_node_serializer<NodeType>
00050                 {
00051                 public:
00052                         typedef NodeType node_type;
00053 
00054                         typedef js_serializer<node_type> this_type; // convenience typedef
00055 
00056                         js_serializer() : m_depth(0)
00057                         {
00058                                 this->magic_cookie( MAGIC_COOKIE_JS );
00059                         }
00060 
00061                         virtual ~js_serializer() {}
00062 
00063                         /**
00064                            Writes src out to dest.
00065                         */
00066                         virtual bool serialize( const node_type & src, std::ostream & dest )
00067             {
00068                 this->m_depth = 0;
00069                 return this->serialize_impl( src, dest );
00070             }
00071 
00072                         /**
00073                            Throws an exception: this type doesn't
00074                            support reading from JS.
00075                         */
00076                         virtual node_type * deserialize( std::istream & src )
00077                         {
00078                 throw ::s11n::s11n_exception( "js_serializer() does not support DEserialization." );
00079                                 return 0; // avoid warning from compiler about implicit return
00080                         }
00081  
00082                 private:
00083                         size_t m_depth;
00084                         bool serialize_impl( const node_type & src, std::ostream & dest )
00085                         {
00086                                 typedef ::s11n::node_traits<node_type> NT;
00087 
00088 // INDENT() is a helper macro for some serializers.
00089 #define INDENT(LEVEL,ECHO) indent = ""; for( size_t i = 0; i < depth + LEVEL; i++ ) { indent += '\t'; if(ECHO) dest << '\t'; }
00090 
00091                                 size_t depth = this->m_depth++;
00092                                 if ( 0 == depth )
00093                                 {
00094                                         dest << this->magic_cookie() << '\n';
00095                                 }
00096 
00097 
00098                                 std::string nname = NT::name(src);
00099                                 std::string impl = NT::class_name(src);
00100                                 std::string indent;
00101                 dest << "(function() {\n";
00102                 INDENT(1,0);
00103                 dest << indent << "var self = new Object();\n";
00104                 dest << indent << "self.$name = '" << nname << "';\n";
00105                 dest << indent << "self.$class = '"<< impl <<"';\n";
00106                                 typedef typename NT::property_map_type PMT;
00107                 typedef typename PMT::const_iterator CHIT;
00108                 CHIT cit, cet;
00109                 cit = NT::properties(src).begin();
00110                 cet = NT::properties(src).end();
00111                                 std::string propval;
00112                                 std::string key;
00113 
00114 
00115                                 if( cet != cit )
00116                                 { // got properties?
00117                     dest << indent << "var p = self.$properties = new Array();\n";
00118 //                  INDENT(2,0);
00119 //                  size_t sz = NT::properties(src).size();
00120 //                  size_t pos = 0;
00121                                         for ( ; cet != cit; ++cit )
00122                                         {
00123                         dest << indent << "p["<<quote_js_string((*cit).first) <<"] = "
00124                              << quote_js_string( ( *cit ).second ) << ";\n";
00125                         continue;
00126 //                                                 key = ( *cit ).first;
00127 //                                                 propval = quote_js_string( ( *cit ).second );
00128                                                 //dest << indent << "$"<<key << ":" << propval;
00129                         // ^^^ we prefix with $ to avoid collisions with JS reserved words.
00130                         // e.g., void='abc' will not work, but $void='abc' will.
00131 //                      if( pos++ < (sz-1) ) { dest << ','; }
00132 //                      dest << '\n';
00133                                         }
00134 //                  INDENT(1,0);
00135 //                  dest << indent << "};\n";
00136                                 }
00137 
00138                 
00139                 typedef typename NT::child_list_type CHLT;
00140                                 typename CHLT::const_iterator chit = NT::children(src).begin(),
00141                                         chet = NT::children(src).end();
00142                                 if( chet != chit )
00143                                 { // got kids?
00144                                         INDENT(1,0);
00145                     dest << indent << "self.$children = (function() {\n";
00146                     node_type const * node = 0;
00147                                         INDENT(2,0);
00148                     dest << indent << "var a = new Array();\n";
00149                     size_t pos = 0;
00150                     for( ; chet != chit; ++chit )
00151                     {
00152                         node = *chit;
00153                         //dest << indent;
00154                         dest << indent << "a["<<pos++<<"] = ";
00155                         try
00156                         {
00157                             ++m_depth;
00158                             this->serialize_impl( *node, dest );
00159                             --m_depth;
00160                         }
00161                         catch(...)
00162                         {
00163                             --m_depth;
00164                             throw;
00165                         }
00166                     }
00167                     dest << indent << "return a;\n";
00168                     INDENT(1,0);
00169                     dest << indent << "})();\n"; // end children
00170                                 }
00171                 INDENT(1,0);
00172                 dest << indent << "return self;\n";
00173                 //if( 0 == depth ) { INDENT(1,0); }
00174                 //dest << indent << "};\n";
00175                 INDENT(((0==depth) ? 0 : 1),0);
00176                 dest << indent << "})();\n"; // close and call function
00177                                 if( 0 == depth )
00178                                 {
00179                     dest << "\n";
00180                                         dest.flush();
00181                                         // if we don't do this then the client is possibly forced to flush() the stream :/
00182                                 }
00183                                 --this->m_depth;
00184                                 return true;
00185 #undef INDENT
00186                         }
00187             
00188                 };
00189 
00190         } // namespace io
00191 } // namespace s11n
00192 
00193 #undef MAGIC_COOKIE_JS
00194 #endif // s11n_JS_SERIALIZER_HPP_INCLUDED

Generated on Wed Jun 4 21:44:19 2008 for libs11n by  doxygen 1.5.3