ParseDef.cc

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------\
00002 |                          ____ _   __ __ ___                          |
00003 |                         |__  / \ / / . \ . \                         |
00004 |                           / / \ V /|  _/  _/                         |
00005 |                          / /__ | | | | | |                           |
00006 |                         /_____||_| |_| |_|                           |
00007 |                                                                      |
00008 \---------------------------------------------------------------------*/
00012 #include <iostream>
00013 #include <sstream>
00014 #include <string>
00015 #include <map>
00016 
00017 #include "zypp/base/Logger.h"
00018 #include "zypp/base/String.h"
00019 #include "zypp/base/DtorReset.h"
00020 #include "zypp/base/DefaultIntegral.h"
00021 
00022 #include "zypp/parser/xml/ParseDef.h"
00023 #include "zypp/parser/xml/ParseDefException.h"
00024 #include "zypp/parser/xml/ParseDefConsume.h"
00025 #include "zypp/parser/xml/Reader.h"
00026 
00027 using std::endl;
00028 
00030 namespace zypp
00031 { 
00032 
00033   namespace debug
00034   { 
00035 
00036     template<class _Derived>
00037       struct TraceInstance
00038       {
00039         TraceInstance()
00040         { total(1); }
00041         TraceInstance( const TraceInstance & rhs )
00042         { total(1); }
00043         ~TraceInstance()
00044         { total(-1); }
00045         static unsigned & total( int cnt_r )
00046         {
00047           static unsigned _total = 0;
00048           _total += cnt_r;
00049           INT << "total += " << cnt_r << " => " << _total << endl;
00050           return _total;
00051         }
00052       };
00053 
00055   } // namespace debug
00058 } // namespace zypp
00060 
00061 
00063 namespace zypp
00064 { 
00065 
00066   namespace xml
00067   { 
00068 
00070     //
00071     //  CLASS NAME : ParseDefImplConsume
00072     //
00074     struct ParseDefImplConsume : public ParseDefConsumeRedirect
00075     {
00076       virtual void start( const Node & node_r )
00077       {
00078         debuglog( "START ", node_r );
00079         ParseDefConsumeRedirect::start( node_r );
00080       }
00081 
00082       virtual void text( const Node & node_r )
00083       {
00084         debuglog( "TEXT  ", node_r );
00085         ParseDefConsumeRedirect::text( node_r );
00086       }
00087 
00088       virtual void cdata( const Node & node_r )
00089       {
00090         debuglog( "CDATA ", node_r );
00091         ParseDefConsumeRedirect::cdata( node_r );
00092       }
00093 
00094       virtual void done( const Node & node_r )
00095       {
00096         debuglog( "DONE  ", node_r );
00097         ParseDefConsumeRedirect::done( node_r );
00098       }
00099 
00100       virtual void startSubnode( const Node & node_r )
00101       {
00102         debuglog( "--->  ", node_r );
00103         ParseDefConsumeRedirect::start( node_r );
00104       }
00105 
00106       virtual void doneSubnode( const Node & node_r )
00107       {
00108         debuglog( "<---  ", node_r );
00109         ParseDefConsumeRedirect::done( node_r );
00110       }
00111 
00112       void debuglog( const char *const tag_r, const Node & node_r )
00113       {
00114         if ( ParseDef::_debug )
00115           DBG << tag_r << node_r << endl;
00116       }
00117     };
00119 
00121     //
00122     //  CLASS NAME : ParseDef::Impl
00123     //
00127     class ParseDef::Impl
00128     {
00129       friend std::ostream & operator<<( std::ostream & str, const ParseDef::Impl & obj );
00130     public:
00131       typedef shared_ptr<Impl>               ImplPtr;
00132       typedef std::map<std::string, ImplPtr> SubNodes;
00133 
00134     public:
00135       Impl( const std::string & name_r, Mode mode_r )
00136       : _name( name_r )
00137       , _mode( mode_r )
00138       , _parent( NULL )
00139       {}
00140 
00141       ~Impl()
00142       {
00143         for ( SubNodes::iterator it = _subnodes.begin(); it != _subnodes.end(); ++it )
00144           {
00145             it->second->_parent = NULL;
00146           }
00147       }
00148 
00149       bool isOptional() const
00150       { return Traits::ModeBits(_mode).isEqual<Traits::TypeBits>( Traits::BIT_OPTIONAL ); }
00151 
00152       bool isMandatory() const
00153       { return Traits::ModeBits(_mode).isEqual<Traits::TypeBits>( Traits::BIT_MANDTAORY ); }
00154 
00155       bool singleDef() const
00156       { return Traits::ModeBits(_mode).isEqual<Traits::VisitBits>( Traits::BIT_ONCE ); }
00157 
00158       bool multiDef() const
00159       { return Traits::ModeBits(_mode).isEqual<Traits::VisitBits>( Traits::BIT_MULTIPLE ); }
00160 
00161     public:
00162       void addNode( const ImplPtr & subnode_r );
00163 
00164       ImplPtr getNode( const std::string & name_r ) const
00165       {
00166         SubNodes::const_iterator it = _subnodes.find( name_r );
00167         if ( it != _subnodes.end() )
00168           return it->second;
00169         return ImplPtr();
00170       }
00171 
00172       void take( Reader & reader_r );
00173 
00174     private:
00183       bool skipNode( Reader & reader_r );
00184 
00185       std::string exstr( const std::string & what_r, const Impl & impl_r ) const
00186       {
00187         std::ostringstream str;
00188         str << impl_r << ": " << what_r;
00189         return str.str();
00190       }
00191       std::string exstr( const std::string & what_r, const Impl & impl_r, const Reader & reader_r ) const
00192       {
00193         std::ostringstream str;
00194         str << impl_r << ": " << what_r << " |reading " << *reader_r;
00195         return str.str();
00196       }
00197 
00198     public:
00199       std::string                 _name;
00200       Mode                        _mode;
00201       DefaultIntegral<unsigned,0> _visited;
00202 
00203       Impl *                      _parent;
00204       SubNodes                    _subnodes;
00205       ParseDefImplConsume         _callback;
00206 
00207       DefaultIntegral<int,-1>     _parseDepth;
00208     };
00210 
00212     //
00213     //  METHOD NAME : ParseDef::Impl::addNode
00214     //  METHOD TYPE : void
00215     //
00216     void ParseDef::Impl::addNode( const ImplPtr & subnode_r )
00217     {
00218       std::pair<SubNodes::iterator, bool> res
00219       = _subnodes.insert( std::make_pair( subnode_r->_name, subnode_r ) );
00220 
00221       if ( ! res.second )
00222         {
00223           ZYPP_THROW( ParseDefBuildException( exstr("Multiple definiton of subnode "+subnode_r->_name, *this) ) );
00224         }
00225       if ( res.first->second->_parent )
00226         {
00227           ZYPP_THROW( ParseDefBuildException( exstr("Can not reparent subnode "+subnode_r->_name, *this) ) );
00228         }
00229       res.first->second->_parent = this;
00230     }
00231 
00233     //
00234     //  METHOD NAME : ParseDef::Impl::take
00235     //  METHOD TYPE : void
00236     //
00237     void ParseDef::Impl::take( Reader & reader_r )
00238     {
00239       if ( reader_r->nodeType() != XML_READER_TYPE_ELEMENT )
00240         {
00241           ZYPP_THROW( ParseDefValidateException( exstr("Expected ELEMENT", *this, reader_r) ) );
00242         }
00243       if ( reader_r->name() != _name )
00244         {
00245           ZYPP_THROW( ParseDefValidateException( exstr("Wrong ELEMENT name", *this, reader_r) ) );
00246         }
00247       if ( _visited >= 1 && ! multiDef() )
00248         {
00249           ZYPP_THROW( ParseDefValidateException( exstr("Multiple definitions", *this, reader_r) ) );
00250         }
00251 
00252       ++_visited; // Accepted to parse
00253       DtorReset x( _parseDepth, -1 );
00254       _parseDepth = reader_r->depth();
00255 
00256       // Parse attributes
00257       _callback.start( *reader_r );
00258 
00259       // Get content up to end node
00260       // Empty element (<node />) has no separate end node, so
00261       // there's nothing to parse.
00262       if ( ! reader_r->isEmptyElement() )
00263         {
00264           // For non empty elements (<node></node>) parse known nodes
00265           // text and cdata elelments skip unknown nodes.
00266           for ( bool done = false; ! done ; /*advance in inside loop*/)
00267             {
00268               // advance to next node
00269               if ( ! reader_r.nextNode() )
00270                 {
00271                   ZYPP_THROW( ParseDefValidateException( exstr( "Unexpected EOF ", *this ) ) );
00272                 }
00273 
00274               switch ( reader_r->nodeType() )
00275                 {
00276                 case XML_READER_TYPE_ELEMENT:
00277                   // Parse or skip unknown. Anyway reader is located at the
00278                   // corresponding end node, or an exception was thrown.
00279                   {
00280                     ImplPtr sub( getNode( reader_r->name().asString() ) );
00281                     if ( sub )
00282                       {
00283                         _callback.startSubnode( *reader_r );
00284                         sub->take( reader_r );
00285                         _callback.doneSubnode( *reader_r );
00286                       }
00287                     else
00288                       {
00289                         WAR << "Skip unknown node " << *reader_r << " in "<< *this << endl;
00290                         skipNode( reader_r );
00291                       }
00292                   }
00293                 break;
00294 
00295                 case XML_READER_TYPE_END_ELEMENT:
00296                   // This must be the corresponding end node!
00297                   if ( reader_r->depth() == _parseDepth
00298                        && reader_r->name() == _name )
00299                     {
00300                       done = true;
00301                     }
00302                   else
00303                     {
00304                       ZYPP_THROW( ParseDefValidateException( exstr("unexpected END_ELEMENT name", *this, reader_r) ) );
00305                     }
00306                   break;
00307 
00308                 case XML_READER_TYPE_TEXT:
00309                   // collect or skip
00310                   _callback.text( *reader_r );
00311                   break;
00312 
00313                 case XML_READER_TYPE_CDATA:
00314                   // collect or skip
00315                   _callback.cdata( *reader_r );
00316                   break;
00317 
00318                 default:
00319                   break;
00320                 }
00321             }
00322         }
00323 
00324       // Parsing complete. Check whether all mandatory nodes were
00325       // present. Finally position behind the end node.
00326       for ( SubNodes::iterator it = _subnodes.begin(); it != _subnodes.end(); ++it )
00327         {
00328           if ( ! it->second->_visited && it->second->isMandatory() )
00329             {
00330               ZYPP_THROW( ParseDefValidateException( exstr("Mandatory ELEMENT missing", *(it->second), reader_r) ) );
00331             }
00332           it->second->_visited = 0; // reset to be ready for an other visit to this!!
00333         }
00334 
00335       _callback.done( *reader_r );
00336     }
00337 
00339     //
00340     //  METHOD NAME : ParseDef::Impl::skipNode
00341     //  METHOD TYPE : void
00342     //
00343     bool ParseDef::Impl::skipNode( xml::Reader & reader_r )
00344     {
00345       if ( ! reader_r.seekToEndNode( reader_r->depth(),
00346                                      reader_r->name().asString() ) )
00347         {
00348           ZYPP_THROW( ParseDefValidateException
00349                       ( exstr( str::form( "EOF while looking for [%d] <\\%s>",
00350                                           reader_r->depth(),
00351                                           reader_r->name().c_str() ),
00352                                *this ) ) );
00353         }
00354       return true;
00355     }
00356 
00357     /******************************************************************
00358      **
00359      ** FUNCTION NAME : operator<<
00360      ** FUNCTION TYPE : std::ostream &
00361     */
00362     std::ostream & operator<<( std::ostream & str, const ParseDef::Impl & obj )
00363     {
00364       return str << "ParseDef(" << obj._name
00365                  << ", " << obj._mode
00366                  << ", visits " << obj._visited
00367                  << ")";
00368     }
00369 
00371     //
00372     //  CLASS NAME : ParseDef
00373     //
00375 
00376     bool ParseDef::_debug = false;
00377 
00379     //
00380     //  METHOD NAME : ParseDef::ParseDef
00381     //  METHOD TYPE : Ctor
00382     //
00383     ParseDef::ParseDef( const std::string & name_r, Mode mode_r )
00384     : _pimpl( new Impl( name_r, mode_r ) )
00385     {}
00386 
00387     ParseDef::ParseDef( const shared_ptr<Impl> & pimpl_r )
00388     : _pimpl( pimpl_r )
00389     {}
00390 
00392     //
00393     //  METHOD NAME : ParseDef::~ParseDef
00394     //  METHOD TYPE : Dtor
00395     //
00396     ParseDef::~ParseDef()
00397     {}
00398 
00399     const std::string & ParseDef::name() const
00400     { return _pimpl->_name; }
00401 
00402     ParseDef::Mode ParseDef::mode() const
00403     { return _pimpl->_mode; }
00404 
00405     bool ParseDef::isOptional() const
00406     { return _pimpl->isOptional(); }
00407 
00408     bool ParseDef::isMandatory() const
00409     { return _pimpl->isMandatory(); }
00410 
00411     bool ParseDef::singleDef() const
00412     { return _pimpl->singleDef(); }
00413 
00414     bool ParseDef::multiDef() const
00415     { return _pimpl->multiDef(); }
00416 
00417     unsigned ParseDef::visited() const
00418     { return _pimpl->_visited; }
00419 
00420     ParseDef & ParseDef::addNode( ParseDef & subnode_r )
00421     { _pimpl->addNode( subnode_r._pimpl.getPtr() ); return *this; }
00422 
00423     ParseDef ParseDef::operator[]( const std::string & name_r )
00424     {
00425       shared_ptr<Impl> retimpl( _pimpl->getNode( name_r ) );
00426       if ( ! retimpl )
00427         {
00428           ZYPP_THROW( ParseDefBuildException( "No subnode "+name_r ) );
00429         }
00430       return retimpl;
00431     }
00432 
00433     void ParseDef::setConsumer( const shared_ptr<ParseDefConsume> & target_r )
00434     { _pimpl->_callback.setRedirect( target_r ); }
00435 
00436     void ParseDef::setConsumer( ParseDefConsume * allocatedTarget_r )
00437     { _pimpl->_callback.setRedirect( allocatedTarget_r ); }
00438 
00439     void ParseDef::setConsumer( ParseDefConsume & target_r )
00440     { _pimpl->_callback.setRedirect( target_r ); }
00441 
00442     void ParseDef::cancelConsumer()
00443     { _pimpl->_callback.cancelRedirect(); }
00444 
00445     shared_ptr<ParseDefConsume> ParseDef::getConsumer() const
00446     { return _pimpl->_callback.getRedirect(); }
00447 
00448 
00449     void ParseDef::take( Reader & reader_r )
00450     { _pimpl->take( reader_r ); }
00451 
00452     /******************************************************************
00453      **
00454      ** FUNCTION NAME : operator<<
00455      ** FUNCTION TYPE : std::ostream &
00456     */
00457     std::ostream & operator<<( std::ostream & str, ParseDef::Mode obj )
00458     {
00459       switch ( obj )
00460         {
00461 #define X(T) case ParseDef::T: return str << #T
00462           X(OPTIONAL);
00463           X(MANDTAORY);
00464           X(MULTIPLE_OPTIONAL);
00465           X(MULTIPLE_MANDTAORY);
00466 #undef X
00467         }
00468       return str;
00469     }
00470 
00471     /******************************************************************
00472      **
00473      ** FUNCTION NAME : operator<<
00474      ** FUNCTION TYPE : std::ostream &
00475     */
00476     std::ostream & operator<<( std::ostream & str, const ParseDef & obj )
00477     {
00478       return str << obj._pimpl;
00479     }
00480 
00482   } // namespace xml
00485 } // namespace zypp

Generated on Tue Sep 25 19:23:03 2007 for libzypp by  doxygen 1.5.3