From 9ab23d05bb23a284c1b06a28b5516a393746eb36 Mon Sep 17 00:00:00 2001 From: Michael Andres Date: Thu, 5 Feb 2009 19:29:16 +0100 Subject: [PATCH] Enhance xml::parseDefAssign to support Node attribute consumption and pre/post-processing. --- zypp/parser/ProductFileReader.cc | 28 ++-- zypp/parser/xml/ParseDef.cc | 33 ----- zypp/parser/xml/ParseDefConsume.h | 300 +++++++++++++++++++++++++++++--------- zypp/parser/xml/Reader.cc | 4 +- 4 files changed, 249 insertions(+), 116 deletions(-) diff --git a/zypp/parser/ProductFileReader.cc b/zypp/parser/ProductFileReader.cc index 1e6ef13..1f5bdfb 100644 --- a/zypp/parser/ProductFileReader.cc +++ b/zypp/parser/ProductFileReader.cc @@ -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 diff --git a/zypp/parser/xml/ParseDef.cc b/zypp/parser/xml/ParseDef.cc index 59c73ce..2fdda63 100644 --- a/zypp/parser/xml/ParseDef.cc +++ b/zypp/parser/xml/ParseDef.cc @@ -30,39 +30,6 @@ using std::endl; namespace zypp { ///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////// - namespace debug - { ///////////////////////////////////////////////////////////////// - - template - 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 { ///////////////////////////////////////////////////////////////// diff --git a/zypp/parser/xml/ParseDefConsume.h b/zypp/parser/xml/ParseDefConsume.h index c34a9e0..2f75dc9 100644 --- a/zypp/parser/xml/ParseDefConsume.h +++ b/zypp/parser/xml/ParseDefConsume.h @@ -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 - struct ParseDefAssignText : public xml::ParseDefConsume - { - ParseDefAssignText( _Type & value_r ) - : _value( &value_r ) - {} + /** \ref parseDefAssign exposed details */ + namespace parse_def_assign + { ///////////////////////////////////////////////////////////////// + template struct Assigner; + + typedef shared_ptr > AssignerRef; - virtual void text( const xml::Node & node_r ) + /** Common interface to all Assigner types. */ + template <> + struct Assigner { - *_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 + struct Assigner : public Assigner + { + Assigner(_Type & value_r ) + : _value( &value_r ) + {} - /** \name ParseDefAssignText specialisation for numeric and boolean values. - * \relates ParseDefAssignText - */ - //@{ - template <> - inline void ParseDefAssignText::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); } - template <> - inline void ParseDefAssignText::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); } - template <> - inline void ParseDefAssignText::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); } - template <> - inline void ParseDefAssignText::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); } - template <> - inline void ParseDefAssignText::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); } - template <> - inline void ParseDefAssignText::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); } - template <> - inline void ParseDefAssignText::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); } - template <> - inline void ParseDefAssignText::text( const xml::Node & node_r ) { str::strtonum( node_r.value().c_str(), *_value ); } - template <> - inline void ParseDefAssignText::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::assign( const char * text_r ) { str::strtonum( text_r, *_value ); } + template <> + inline void Assigner::assign( const char * text_r ) { str::strtonum( text_r, *_value ); } + template <> + inline void Assigner::assign( const char * text_r ) { str::strtonum( text_r, *_value ); } + template <> + inline void Assigner::assign( const char * text_r ) { str::strtonum( text_r, *_value ); } + template <> + inline void Assigner::assign( const char * text_r ) { str::strtonum( text_r, *_value ); } + template <> + inline void Assigner::assign( const char * text_r ) { str::strtonum( text_r, *_value ); } + template <> + inline void Assigner::assign( const char * text_r ) { str::strtonum( text_r, *_value ); } + template <> + inline void Assigner::assign( const char * text_r ) { str::strtonum( text_r, *_value ); } + + template <> + inline void Assigner::assign( const char * text_r ) { str::strToBoolNodefault( text_r, *_value ); } + //@} + + /** \name \relates Assigner Convenience constructor */ + //@{ + template + inline AssignerRef assigner( _Type & value_r ) + { return AssignerRef( new Assigner<_Type>( value_r ) ); } + + template + 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 void( const Node & ) notification + * callback which is invoked after the node was processed. + * + * \note Use and see \ref xml::parseDefAssign convenience constructor. + * + * \code + * // parsedef for 'value' + * 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 pre_r ) + { _pre = pre_r; } + + /** Set post notification callback. */ + void postnotify( function 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 & 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 > _attr; + std::vector _text; + function _pre; + function _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, so it can be passed as a + * node consumer to \ref ParseDef. + * + * You may also set a void( const Node & ) 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 + Builder( _Type & value_r ) + : _ptr( new Consumer ) + { operator()( value_r ); } + + /** Contruct \ref Consumer. */ + template + Builder( const std::string & attr_r, _Type & value_r ) + : _ptr( new Consumer ) + { operator()( attr_r, value_r ); } + + /** Extend \ref Consumer. */ + template + Builder & operator()( _Type & value_r ) + { _ptr->add( assigner( value_r ) ); return *this; } + + /** Extend \ref Consumer. */ + template + 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 done_r ) + { _ptr->prenotify( done_r ); return *this; } + + /** Set post notification callback. */ + Builder & operator>>( function done_r ) + { _ptr->postnotify( done_r ); return *this; } + + /** Type conversion so this can be passed as node consumer to \ref ParseDef. */ + operator shared_ptr () const + { return _ptr; } + + private: + shared_ptr _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 ready to be passed - * to a \ref ParseDef node. + * \code + * void setupDone( const xml::Node & _node ) + * { ... } + * + * // parsedef for 'value' + * 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 - shared_ptr parseDefAssignText( _Type & value_r ) - { return shared_ptr( new ParseDefAssignText<_Type>( value_r ) ); } + inline parse_def_assign::Builder parseDefAssign( _Type & value_r ) + { return parse_def_assign::Builder( value_r ); } - template - shared_ptr parseDefAssignText( DefaultIntegral<_Tp,_Initial> & value_r ) - { return shared_ptr( new ParseDefAssignText<_Tp>( value_r.get() ) ); } + template + 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 /////////////////////////////////////////////////////////////////// diff --git a/zypp/parser/xml/Reader.cc b/zypp/parser/xml/Reader.cc index c8e9fd0..5f7c155 100644 --- a/zypp/parser/xml/Reader.cc +++ b/zypp/parser/xml/Reader.cc @@ -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 -- 2.7.4