ref: refs/heads/master
commit 9ab23d05bb23a284c1b06a28b5516a393746eb36
Author: Michael Andres
Date: Thu Feb 5 19:29:16 2009 +0100
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<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
{ /////////////////////////////////////////////////////////////////
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 <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 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
+ 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 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<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 _attr;
+ std::vector<AssignerRef> _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<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 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<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_ptrxml::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_ptrxml::ParseDefConsume parseDefAssignText( _Type & value_r )
- { return shared_ptrxml::ParseDefConsume( new ParseDefAssignText<_Type>( value_r ) ); }
+ inline parse_def_assign::Builder parseDefAssign( _Type & value_r )
+ { return parse_def_assign::Builder( value_r ); }
- template
- shared_ptrxml::ParseDefConsume parseDefAssignText( DefaultIntegral<_Tp,_Initial> & value_r )
- { return shared_ptrxml::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
///////////////////////////////////////////////////////////////////
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
--
To unsubscribe, e-mail: zypp-commit+unsubscribe@opensuse.org
For additional commands, e-mail: zypp-commit+help@opensuse.org