Enhance xml::parseDefAssign to support Node attribute consumption and pre/post-proces...
authorMichael Andres <ma@suse.de>
Thu, 5 Feb 2009 18:29:16 +0000 (19:29 +0100)
committerMichael Andres <ma@suse.de>
Fri, 6 Feb 2009 11:02:09 +0000 (12:02 +0100)
zypp/parser/ProductFileReader.cc
zypp/parser/xml/ParseDef.cc
zypp/parser/xml/ParseDefConsume.h
zypp/parser/xml/Reader.cc

index 1e6ef13..1f5bdfb 100644 (file)
@@ -131,20 +131,20 @@ namespace zypp
         , _pdata( pdata_r )
       {
         (*this)
-            ("vendor",        OPTIONAL,   xml::parseDefAssignText( _pdata._vendor ) )
-            ("name",          MANDTAORY,  xml::parseDefAssignText( _pdata._name ) )
-            ("version",       MANDTAORY,  xml::parseDefAssignText( _version ) )
-            ("release",       MANDTAORY,  xml::parseDefAssignText( _release ) )
-            ("arch",          MANDTAORY,  xml::parseDefAssignText( _pdata._arch ) )
-            ("productline",   OPTIONAL,   xml::parseDefAssignText( _pdata._productline ) )
+            ("vendor",        OPTIONAL,   xml::parseDefAssign( _pdata._vendor ) )
+            ("name",          MANDTAORY,  xml::parseDefAssign( _pdata._name ) )
+            ("version",       MANDTAORY,  xml::parseDefAssign( _version ) )
+            ("release",       MANDTAORY,  xml::parseDefAssign( _release ) )
+            ("arch",          MANDTAORY,  xml::parseDefAssign( _pdata._arch ) )
+            ("productline",   OPTIONAL,   xml::parseDefAssign( _pdata._productline ) )
             ("register",      OPTIONAL)
-            ("updaterepokey", OPTIONAL,   xml::parseDefAssignText( _pdata._updaterepokey ) )
+            ("updaterepokey", OPTIONAL,   xml::parseDefAssign( _pdata._updaterepokey ) )
             ("upgrades",      OPTIONAL)
             ;
 
         (*this)["register"]
-            ("target",        OPTIONAL,   xml::parseDefAssignText( _pdata._registerTarget ) )
-            ("release",       OPTIONAL,   xml::parseDefAssignText( _pdata._registerRelease ) )
+            ("target",        OPTIONAL,   xml::parseDefAssign( _pdata._registerTarget ) )
+            ("release",       OPTIONAL,   xml::parseDefAssign( _pdata._registerRelease ) )
             ;
 
         (*this)["upgrades"]
@@ -152,11 +152,11 @@ namespace zypp
             ;
 
         (*this)["upgrades"]["upgrade"]
-            ("name",          OPTIONAL,   xml::parseDefAssignText( _upgrade._name ) )
-            ("summary",       OPTIONAL,   xml::parseDefAssignText( _upgrade._summary ) )
-            ("repository",    OPTIONAL,   xml::parseDefAssignText( _upgrade._repository ) )
-            ("notify",        OPTIONAL,   xml::parseDefAssignText( _upgrade._notify ) )
-            ("status",        OPTIONAL,   xml::parseDefAssignText( _upgrade._status ) )
+            ("name",          OPTIONAL,   xml::parseDefAssign( _upgrade._name ) )
+            ("summary",       OPTIONAL,   xml::parseDefAssign( _upgrade._summary ) )
+            ("repository",    OPTIONAL,   xml::parseDefAssign( _upgrade._repository ) )
+            ("notify",        OPTIONAL,   xml::parseDefAssign( _upgrade._notify ) )
+            ("status",        OPTIONAL,   xml::parseDefAssign( _upgrade._status ) )
             ;
 
         // Not a clean way to collect the END_ELEMENT calls, but
index 59c73ce..2fdda63 100644 (file)
@@ -30,39 +30,6 @@ using std::endl;
 namespace zypp
 { /////////////////////////////////////////////////////////////////
   ///////////////////////////////////////////////////////////////////
-  namespace debug
-  { /////////////////////////////////////////////////////////////////
-
-    template<class _Derived>
-      struct TraceInstance
-      {
-        TraceInstance()
-        { total(1); }
-        TraceInstance( const TraceInstance & rhs )
-        { total(1); }
-        ~TraceInstance()
-        { total(-1); }
-        static unsigned & total( int cnt_r )
-        {
-          static unsigned _total = 0;
-          _total += cnt_r;
-          INT << "total += " << cnt_r << " => " << _total << endl;
-          return _total;
-        }
-      };
-
-    /////////////////////////////////////////////////////////////////
-  } // namespace debug
-  ///////////////////////////////////////////////////////////////////
-  /////////////////////////////////////////////////////////////////
-} // namespace zypp
-///////////////////////////////////////////////////////////////////
-
-
-///////////////////////////////////////////////////////////////////
-namespace zypp
-{ /////////////////////////////////////////////////////////////////
-  ///////////////////////////////////////////////////////////////////
   namespace xml
   { /////////////////////////////////////////////////////////////////
 
index c34a9e0..2f75dc9 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "zypp/base/PtrTypes.h"
 #include "zypp/base/Function.h"
+#include "zypp/base/Tr1hash.h"
 #include "zypp/base/String.h"
 #include "zypp/base/DefaultIntegral.h"
 
@@ -121,86 +122,249 @@ namespace zypp
     ///////////////////////////////////////////////////////////////////
 
     ///////////////////////////////////////////////////////////////////
-    //
-    // CLASS NAME : ParseDefAssignText<_Type>
-    //
-    /** Assign a \ref Node text to types constructible from \c char*.
-     * \code
-     * struct ProductNode : public xml::ParseDef
-     * {
-     *   ProductNode( ProductFileData::Impl & pdata_r )
-     *     : ParseDef( "product", MANDTAORY )
-     *   {
-     *     (*this)
-     *         ("vendor",        OPTIONAL,  parseDefAssignText( _vendor ) )
-     *         ("name",          MANDTAORY, parseDefAssignText( _name ) )
-     *         ...
-     *   }
-     *
-     *   std::string _vendor;
-     *   std::string _name;
-     * };
-     * \endcode
-     */
-    template <class _Type>
-    struct ParseDefAssignText : public xml::ParseDefConsume
-    {
-      ParseDefAssignText( _Type & value_r )
-        : _value( &value_r )
-      {}
+    /** \ref parseDefAssign exposed details */
+    namespace parse_def_assign
+    { /////////////////////////////////////////////////////////////////
+     template <class _Type> struct Assigner;
+
+      typedef shared_ptr<Assigner<void> > AssignerRef;
 
-      virtual void text( const xml::Node & node_r )
+      /** Common interface to all Assigner types. */
+      template <>
+          struct Assigner<void>
       {
-        *_value = _Type( node_r.value().c_str() );
-      }
+        virtual ~Assigner()
+        {}
+        virtual void assign( const char * text_r )
+        {}
+      };
 
-      private:
-      _Type * _value;
-    };
+      /** Assigner assigns text to types constructible from \c char*.
+       * \see \ref assigner consvenience constructor.
+      */
+      template <class _Type>
+          struct Assigner : public Assigner<void>
+      {
+        Assigner(_Type & value_r )
+          : _value( &value_r )
+        {}
 
-    /** \name ParseDefAssignText specialisation for numeric and boolean values.
-     *  \relates ParseDefAssignText
-     */
-    //@{
-    template <>
-    inline void ParseDefAssignText<short>::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); }
-    template <>
-    inline void ParseDefAssignText<int>::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); }
-    template <>
-    inline void ParseDefAssignText<long>::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); }
-    template <>
-    inline void ParseDefAssignText<long long>::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); }
-    template <>
-    inline void ParseDefAssignText<unsigned short>::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); }
-    template <>
-    inline void ParseDefAssignText<unsigned>::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); }
-    template <>
-    inline void ParseDefAssignText<unsigned long>::text( const xml::Node & node_r )  { str::strtonum( node_r.value().c_str(), *_value ); }
-    template <>
-    inline void ParseDefAssignText<unsigned long long>::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); }
-    template <>
-    inline void ParseDefAssignText<bool>::text( const xml::Node & node_r ) { str::strToBoolNodefault( node_r.value().c_str(), *_value ); }
-    //@}
+        virtual void assign( const char * text_r )
+        { *_value = _Type( text_r ); }
+
+        private:
+          _Type * _value;
+      };
+
+      /** \name Assigner specialisation for numeric and boolean values.
+       *  \relates Assigner
+       */
+      //@{
+      template <>
+          inline void Assigner<short>::assign( const char * text_r )              { str::strtonum( text_r, *_value ); }
+      template <>
+          inline void Assigner<int>::assign( const char * text_r )                { str::strtonum( text_r, *_value ); }
+      template <>
+          inline void Assigner<long>::assign( const char * text_r )               { str::strtonum( text_r, *_value ); }
+      template <>
+          inline void Assigner<long long>::assign( const char * text_r )          { str::strtonum( text_r, *_value ); }
+      template <>
+          inline void Assigner<unsigned short>::assign( const char * text_r )     { str::strtonum( text_r, *_value ); }
+      template <>
+          inline void Assigner<unsigned>::assign( const char * text_r )           { str::strtonum( text_r, *_value ); }
+      template <>
+          inline void Assigner<unsigned long>::assign( const char * text_r )      { str::strtonum( text_r, *_value ); }
+      template <>
+          inline void Assigner<unsigned long long>::assign( const char * text_r ) { str::strtonum( text_r, *_value ); }
+
+      template <>
+          inline void Assigner<bool>::assign( const char * text_r ) { str::strToBoolNodefault( text_r, *_value ); }
+      //@}
+
+      /** \name \relates Assigner Convenience constructor */
+      //@{
+      template <class _Type>
+          inline AssignerRef assigner( _Type & value_r )
+      { return AssignerRef( new Assigner<_Type>( value_r ) ); }
+
+      template <class _Tp, _Tp _Initial>
+          inline AssignerRef assigner( DefaultIntegral<_Tp,_Initial> & value_r )
+      { return AssignerRef( new Assigner<_Tp>( value_r.get() ) ); }
+      //@}
+
+
+      /** \ref ParseDef consumer assigning \ref Node text and attribues values to variables.
+       *
+       * This can be used with all types supported by \ref Assigner.
+       * Basically all types constructible from \c char*, or where a
+       * specialisation exists (e.g. numeric and bool).
+       *
+       * You may also set a <tt>void( const Node & )</tt> notification
+       * callback which is invoked after the node was processed.
+       *
+       * \note Use and see \ref xml::parseDefAssign convenience constructor.
+       *
+       * \code
+       * // parsedef for '<setup attr="13">value</setup>'
+       * ParseDef( "attr", MANDTAORY, xml::parseDefAssign( data.value )
+       *                                                 ( "attr", data.attr ) )
+       * \endcode
+       */
+      struct Consumer : public ParseDefConsume
+      {
+        /** Extend \ref Consumer. */
+        void add( const AssignerRef & assigner_r )
+        { _text.push_back( assigner_r ); }
+
+        /** Extend \ref Consumer. */
+        void add( const std::string & attr_r, const AssignerRef & assigner_r )
+        { _attr[attr_r].push_back( assigner_r ); }
+
+        /** Set pre notification callback. */
+        void prenotify( function<void ( const Node & )> pre_r )
+        { _pre = pre_r; }
+
+        /** Set post notification callback. */
+        void postnotify( function<void ( const Node & )> post_r )
+        { _post = post_r; }
+
+        virtual void start( const xml::Node & node_r )
+        {
+          if ( _pre )
+            _pre( node_r );
+
+          if ( ! _attr.empty() )
+            for_( it, _attr.begin(), _attr.end() )
+              assign( it->second, node_r.getAttribute( it->first.c_str() ).c_str() );
+        }
 
-    /** \name ParseDefAssignText Convenience constructor.
-     * \relates ParseDefAssignText
+        virtual void text( const xml::Node & node_r )
+        {
+          if ( ! _text.empty() )
+            assign( _text, node_r.value().c_str() );
+        }
+
+        virtual void done( const xml::Node & node_r )
+        {
+          if ( _post )
+            _post( node_r );
+        }
+
+        private:
+          void assign( const std::vector<AssignerRef> & vec_r, const char * value_r )
+          {
+            if ( value_r )
+              for_( it, vec_r.begin(), vec_r.end() )
+                (*it)->assign( value_r );
+          }
+
+        private:
+          std::tr1::unordered_map<std::string, std::vector<AssignerRef> > _attr;
+          std::vector<AssignerRef>                                        _text;
+          function<void ( const Node & )>                                 _pre;
+          function<void ( const Node & )>                                 _post;
+      };
+
+      /** Helper class to build a \ref Consumer.
+       * \relates Consumer
+       *
+       * The class constructs the consumer, allows to extend it via
+       * \ref operator(), and provides a conversion to
+       * \c shared_ptr<ParseDefConsume>, so it can be passed as a
+       * node consumer to \ref ParseDef.
+       *
+       * You may also set a <tt>void( const Node & )</tt> notification
+       * callback which is invoked before/after the node was processed.
+       *
+       * \note Use and see \ref xml::parseDefAssign convenience constructor.
+      */
+      struct Builder
+      {
+        /** Contruct \ref Consumer. */
+        Builder()
+          : _ptr( new Consumer )
+        {}
+
+        /** Contruct \ref Consumer. */
+        template <class _Type>
+            Builder( _Type & value_r )
+          : _ptr( new Consumer )
+        { operator()( value_r ); }
+
+        /** Contruct \ref Consumer. */
+        template <class _Type>
+            Builder( const std::string & attr_r, _Type & value_r )
+          : _ptr( new Consumer )
+        {  operator()( attr_r, value_r ); }
+
+        /** Extend \ref Consumer. */
+        template <class _Type>
+            Builder & operator()( _Type & value_r )
+        { _ptr->add( assigner( value_r ) ); return *this; }
+
+        /** Extend \ref Consumer. */
+        template <class _Type>
+            Builder & operator()( const std::string & attr_r, _Type & value_r )
+        { _ptr->add( attr_r, assigner( value_r ) ); return *this; }
+
+        /** Set pre notification callback. */
+        Builder & operator<<( function<void ( const Node & )> done_r )
+        { _ptr->prenotify( done_r ); return *this; }
+
+        /** Set post notification callback. */
+        Builder & operator>>( function<void ( const Node & )> done_r )
+        { _ptr->postnotify( done_r ); return *this; }
+
+        /** Type conversion so this can be passed as node consumer to \ref ParseDef. */
+        operator shared_ptr<ParseDefConsume> () const
+        { return _ptr; }
+
+        private:
+          shared_ptr<Consumer> _ptr;
+      };
+      /////////////////////////////////////////////////////////////////
+    } // namespace parse_def_assign
+    ///////////////////////////////////////////////////////////////////
+
+    /** \name \ref ParseDef consumer assigning \ref Node text and attribues values to variables.
+     * \relates parse_def_assign::Consumer
+     * \relates parse_def_assign::Builder
+     *
+     * This function allows convenient contruction of a \ref parse_def_assign::Consumer
+     * to be passed as \ref Node conssumer to \ref ParseDef. Simply list each attributes
+     * name together with the variable it's value should be assigned to. If the attribute
+     * name is omitted, the nodes text value gets assigned.
+     *
+     * Target variables can be of any type tsupported by \ref Assigner.
+     * Basically all types constructible from \c char*, or where a
+     * specialisation exists (e.g. numeric and bool).
      *
-     * This returns a \c shared_ptr<xml::ParseDefConsume> ready to be passed
-     * to a \ref ParseDef node.
+     * \code
+     * void setupDone( const xml::Node & _node )
+     * { ... }
+     *
+     * // parsedef for '<setup attr="13">value</setup>'
+     * ParseDef( "attr", MANDTAORY,
+     *           xml::parseDefAssign( data.value )
+     *                              ( "attr", data.attr )
+     *                              >> &setupDone       );
+     * \endcode
+     *
+     * \see \ref xml::rnParse for more example.
      */
     //@{
+    inline parse_def_assign::Builder parseDefAssign()
+    { return parse_def_assign::Builder(); }
+
     template <class _Type>
-    shared_ptr<xml::ParseDefConsume> parseDefAssignText( _Type & value_r )
-    { return shared_ptr<xml::ParseDefConsume>( new ParseDefAssignText<_Type>( value_r ) ); }
+        inline parse_def_assign::Builder parseDefAssign( _Type & value_r )
+    { return parse_def_assign::Builder( value_r ); }
 
-    template<class _Tp, _Tp _Initial>
-    shared_ptr<xml::ParseDefConsume> parseDefAssignText( DefaultIntegral<_Tp,_Initial> & value_r )
-    { return shared_ptr<xml::ParseDefConsume>( new ParseDefAssignText<_Tp>( value_r.get() ) ); }
+    template <class _Type>
+        inline parse_def_assign::Builder parseDefAssign( const std::string & attr_r, _Type & value_r )
+    { return parse_def_assign::Builder( attr_r, value_r ); }
     //@}
 
-    ///////////////////////////////////////////////////////////////////
-
-
     /////////////////////////////////////////////////////////////////
   } // namespace xml
   ///////////////////////////////////////////////////////////////////
index c8e9fd0..5f7c155 100644 (file)
@@ -90,6 +90,7 @@ namespace zypp
                                stream_r.path().asString().c_str(), "utf-8", XML_PARSE_PEDANTIC ) )
     , _node( _reader )
     {
+      MIL << "Start Parsing " << _stream << endl;
       if ( ! _reader || ! stream_r.stream().good() )
         ZYPP_THROW( Exception( "Bad input stream" ) );
       // set error handler
@@ -111,6 +112,7 @@ namespace zypp
         {
           xmlFreeTextReader( _reader );
         }
+      MIL << "Done Parsing " << _stream << endl;
     }
 
     XmlString Reader::nodeText()
@@ -127,7 +129,7 @@ namespace zypp
       }
       return XmlString();
     }
-    
+
     ///////////////////////////////////////////////////////////////////
     //
     // METHOD NAME : Reader::nextNode