libzypp  13.10.6
ParseDef.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
12 #include <iostream>
13 #include <sstream>
14 #include <string>
15 #include <map>
16 
17 #include "zypp/base/Logger.h"
18 #include "zypp/base/String.h"
19 #include "zypp/base/DtorReset.h"
21 
25 #include "zypp/parser/xml/Reader.h"
26 
27 using std::endl;
28 
30 namespace zypp
31 {
32  namespace xml
34  {
35 
37  //
38  // CLASS NAME : ParseDefImplConsume
39  //
42  {
43  virtual void start( const Node & node_r )
44  {
45  debuglog( "START ", node_r );
47  }
48 
49  virtual void text( const Node & node_r )
50  {
51  debuglog( "TEXT ", node_r );
53  }
54 
55  virtual void cdata( const Node & node_r )
56  {
57  debuglog( "CDATA ", node_r );
59  }
60 
61  virtual void done( const Node & node_r )
62  {
63  debuglog( "DONE ", node_r );
65  }
66 
67  virtual void startSubnode( const Node & node_r )
68  {
69  debuglog( "---> ", node_r );
71  }
72 
73  virtual void doneSubnode( const Node & node_r )
74  {
75  debuglog( "<--- ", node_r );
77  }
78 
79  void debuglog( const char *const tag_r, const Node & node_r )
80  {
81  if ( ParseDef::_debug )
82  DBG << tag_r << node_r << endl;
83  }
84  };
86 
88  //
89  // CLASS NAME : ParseDef::Impl
90  //
95  {
96  friend std::ostream & operator<<( std::ostream & str, const ParseDef::Impl & obj );
97  public:
98  typedef shared_ptr<Impl> ImplPtr;
99  typedef std::map<std::string, ImplPtr> SubNodes;
100 
101  public:
102  Impl( const std::string & name_r, Mode mode_r, const shared_ptr<ParseDefConsume> & target_r = shared_ptr<ParseDefConsume>() )
103  : _name( name_r )
104  , _mode( mode_r )
105  , _parent( NULL )
106  {
107  if ( target_r )
108  _callback.setRedirect( target_r );
109  }
110 
112  {
113  for ( SubNodes::iterator it = _subnodes.begin(); it != _subnodes.end(); ++it )
114  {
115  it->second->_parent = NULL;
116  }
117  }
118 
119  bool isOptional() const
121 
122  bool isMandatory() const
124 
125  bool singleDef() const
127 
128  bool multiDef() const
130 
131  public:
132  void addNode( const ImplPtr & subnode_r );
133 
134  ImplPtr getNode( const std::string & name_r ) const
135  {
136  SubNodes::const_iterator it = _subnodes.find( name_r );
137  if ( it != _subnodes.end() )
138  return it->second;
139  return ImplPtr();
140  }
141 
142  void take( Reader & reader_r );
143 
144  private:
153  bool skipNode( Reader & reader_r );
154 
155  std::string exstr( const std::string & what_r, const Impl & impl_r ) const
156  {
157  std::ostringstream str;
158  str << impl_r << ": " << what_r;
159  return str.str();
160  }
161  std::string exstr( const std::string & what_r, const Impl & impl_r, const Reader & reader_r ) const
162  {
163  std::ostringstream str;
164  str << impl_r << ": " << what_r << " |reading " << *reader_r;
165  return str.str();
166  }
167 
168  public:
169  std::string _name;
172 
176 
178  };
180 
182  //
183  // METHOD NAME : ParseDef::Impl::addNode
184  // METHOD TYPE : void
185  //
186  void ParseDef::Impl::addNode( const ImplPtr & subnode_r )
187  {
188  std::pair<SubNodes::iterator, bool> res
189  = _subnodes.insert( std::make_pair( subnode_r->_name, subnode_r ) );
190 
191  if ( ! res.second )
192  {
193  ZYPP_THROW( ParseDefBuildException( exstr("Multiple definiton of subnode "+subnode_r->_name, *this) ) );
194  }
195  if ( res.first->second->_parent )
196  {
197  ZYPP_THROW( ParseDefBuildException( exstr("Can not reparent subnode "+subnode_r->_name, *this) ) );
198  }
199  res.first->second->_parent = this;
200  }
201 
203  //
204  // METHOD NAME : ParseDef::Impl::take
205  // METHOD TYPE : void
206  //
207  void ParseDef::Impl::take( Reader & reader_r )
208  {
209  if ( reader_r->nodeType() != XML_READER_TYPE_ELEMENT )
210  {
211  if ( reader_r->depth() == 0 )
212  {
213  // on the verry first level we skip any initial whitespace and comments...
214  do {
215  // advance to next node
216  if ( ! reader_r.nextNode() )
217  {
218  ZYPP_THROW( ParseDefValidateException( exstr( "Unexpected EOF ", *this ) ) );
219  }
220  } while( reader_r->nodeType() != XML_READER_TYPE_ELEMENT );
221  }
222  else
223  {
224  ZYPP_THROW( ParseDefValidateException( exstr("Expected ELEMENT", *this, reader_r) ) );
225  }
226  }
227  if ( reader_r->name() != _name )
228  {
229  ZYPP_THROW( ParseDefValidateException( exstr("Wrong ELEMENT name", *this, reader_r) ) );
230  }
231  if ( _visited >= 1 && ! multiDef() )
232  {
233  ZYPP_THROW( ParseDefValidateException( exstr("Multiple definitions", *this, reader_r) ) );
234  }
235 
236  ++_visited; // Accepted to parse
237  DtorReset x( _parseDepth, -1 );
238  _parseDepth = reader_r->depth();
239 
240  // Parse attributes
241  _callback.start( *reader_r );
242 
243  // Get content up to end node
244  // Empty element (<node />) has no separate end node, so
245  // there's nothing to parse.
246  if ( ! reader_r->isEmptyElement() )
247  {
248  // For non empty elements (<node></node>) parse known nodes
249  // text and cdata elelments skip unknown nodes.
250  for ( bool done = false; ! done ; /*advance in inside loop*/)
251  {
252  // advance to next node
253  if ( ! reader_r.nextNode() )
254  {
255  ZYPP_THROW( ParseDefValidateException( exstr( "Unexpected EOF ", *this ) ) );
256  }
257 
258  switch ( reader_r->nodeType() )
259  {
260  case XML_READER_TYPE_ELEMENT:
261  // Parse or skip unknown. Anyway reader is located at the
262  // corresponding end node, or an exception was thrown.
263  {
264  ImplPtr sub( getNode( reader_r->name().asString() ) );
265  if ( sub )
266  {
267  _callback.startSubnode( *reader_r );
268  sub->take( reader_r );
269  _callback.doneSubnode( *reader_r );
270  }
271  else
272  {
273  if ( ParseDef::_debug )
274  WAR << "Skip unknown node " << *reader_r << " in "<< *this << endl;
275  skipNode( reader_r );
276  }
277  }
278  break;
279 
280  case XML_READER_TYPE_END_ELEMENT:
281  // This must be the corresponding end node!
282  if ( reader_r->depth() == _parseDepth
283  && reader_r->name() == _name )
284  {
285  done = true;
286  }
287  else
288  {
289  ZYPP_THROW( ParseDefValidateException( exstr("unexpected END_ELEMENT name", *this, reader_r) ) );
290  }
291  break;
292 
293  case XML_READER_TYPE_TEXT:
294  // collect or skip
295  _callback.text( *reader_r );
296  break;
297 
298  case XML_READER_TYPE_CDATA:
299  // collect or skip
300  _callback.cdata( *reader_r );
301  break;
302 
303  default:
304  //DBG << exstr("SKIP ", *this, reader_r) << endl;
305  break;
306  }
307  }
308  }
309 
310  // Parsing complete. Check whether all mandatory nodes were
311  // present. Finally position behind the end node.
312  for ( SubNodes::iterator it = _subnodes.begin(); it != _subnodes.end(); ++it )
313  {
314  if ( ! it->second->_visited && it->second->isMandatory() )
315  {
316  ZYPP_THROW( ParseDefValidateException( exstr("Mandatory ELEMENT missing", *(it->second), reader_r) ) );
317  }
318  it->second->_visited = 0; // reset to be ready for an other visit to this!!
319  }
320 
321  _callback.done( *reader_r );
322  }
323 
325  //
326  // METHOD NAME : ParseDef::Impl::skipNode
327  // METHOD TYPE : void
328  //
330  {
331  if ( ! reader_r.seekToEndNode( reader_r->depth(),
332  reader_r->name().asString() ) )
333  {
335  ( exstr( str::form( "EOF while looking for [%d] <\\%s>",
336  reader_r->depth(),
337  reader_r->name().c_str() ),
338  *this ) ) );
339  }
340  return true;
341  }
342 
343  /******************************************************************
344  **
345  ** FUNCTION NAME : operator<<
346  ** FUNCTION TYPE : std::ostream &
347  */
348  std::ostream & operator<<( std::ostream & str, const ParseDef::Impl & obj )
349  {
350  return str << "ParseDef(" << obj._name
351  << ", " << obj._mode
352  << ", visits " << obj._visited
353  << ")";
354  }
355 
357  //
358  // CLASS NAME : ParseDef
359  //
361 
362  bool ParseDef::_debug = false;
363 
365  //
366  // METHOD NAME : ParseDef::ParseDef
367  // METHOD TYPE : Ctor
368  //
369  ParseDef::ParseDef( const std::string & name_r, Mode mode_r )
370  : _pimpl( new Impl( name_r, mode_r ) )
371  {}
372 
373  ParseDef::ParseDef( const std::string & name_r, Mode mode_r, const shared_ptr<ParseDefConsume> & target_r )
374  : _pimpl( new Impl( name_r, mode_r, target_r ) )
375  {}
376 
377  ParseDef::ParseDef( const shared_ptr<Impl> & pimpl_r )
378  : _pimpl( pimpl_r )
379  {}
380 
382  //
383  // METHOD NAME : ParseDef::~ParseDef
384  // METHOD TYPE : Dtor
385  //
387  {}
388 
389  const std::string & ParseDef::name() const
390  { return _pimpl->_name; }
391 
393  { return _pimpl->_mode; }
394 
395  bool ParseDef::isOptional() const
396  { return _pimpl->isOptional(); }
397 
399  { return _pimpl->isMandatory(); }
400 
401  bool ParseDef::singleDef() const
402  { return _pimpl->singleDef(); }
403 
404  bool ParseDef::multiDef() const
405  { return _pimpl->multiDef(); }
406 
407  unsigned ParseDef::visited() const
408  { return _pimpl->_visited; }
409 
411  { _pimpl->addNode( subnode_r._pimpl.getPtr() ); return *this; }
412 
413  ParseDef ParseDef::operator[]( const std::string & name_r )
414  {
415  shared_ptr<Impl> retimpl( _pimpl->getNode( name_r ) );
416  if ( ! retimpl )
417  {
418  ZYPP_THROW( ParseDefBuildException( "No subnode "+name_r ) );
419  }
420  return retimpl;
421  }
422 
423  void ParseDef::setConsumer( const shared_ptr<ParseDefConsume> & target_r )
424  { _pimpl->_callback.setRedirect( target_r ); }
425 
426  void ParseDef::setConsumer( ParseDefConsume * allocatedTarget_r )
427  { _pimpl->_callback.setRedirect( allocatedTarget_r ); }
428 
430  { _pimpl->_callback.setRedirect( target_r ); }
431 
433  { _pimpl->_callback.cancelRedirect(); }
434 
435  shared_ptr<ParseDefConsume> ParseDef::getConsumer() const
436  { return _pimpl->_callback.getRedirect(); }
437 
438 
439  void ParseDef::take( Reader & reader_r )
440  { _pimpl->take( reader_r ); }
441 
442  /******************************************************************
443  **
444  ** FUNCTION NAME : operator<<
445  ** FUNCTION TYPE : std::ostream &
446  */
447  std::ostream & operator<<( std::ostream & str, ParseDef::Mode obj )
448  {
449  switch ( obj )
450  {
451 #define X(T) case ParseDef::T: return str << #T
452  X(OPTIONAL);
453  X(MANDTAORY);
454  X(MULTIPLE_OPTIONAL);
455  X(MULTIPLE_MANDTAORY);
456 #undef X
457  }
458  return str;
459  }
460 
461  /******************************************************************
462  **
463  ** FUNCTION NAME : operator<<
464  ** FUNCTION TYPE : std::ostream &
465  */
466  std::ostream & operator<<( std::ostream & str, const ParseDef & obj )
467  {
468  return str << obj._pimpl;
469  }
470 
472  } // namespace xml
475 } // namespace zypp
static bool _debug
Definition: ParseDef.h:229
friend std::ostream & operator<<(std::ostream &str, const ParseDef::Impl &obj)
Definition: ParseDef.cc:348
virtual void start(const Node &node_r)
Definition: ParseDef.cc:43
RW_pointer< Impl > _pimpl
Pointer to implementation (shared!)
Definition: ParseDef.h:220
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:320
ParseDef(const std::string &name_r, Mode mode_r)
Definition: ParseDef.cc:369
Define a xml node structure to parse.
Definition: ParseDef.h:128
virtual void done(const Node &_node)
virtual void doneSubnode(const Node &_node)
virtual void startSubnode(const Node &_node)
virtual void text(const Node &_node)
int isEmptyElement() const
Check if the current node is empty.
Definition: Node.h:98
shared_ptr< Impl > ImplPtr
Definition: ParseDef.cc:98
int depth() const
The depth of the node in the tree.
Definition: Node.h:62
bool skipNode(Reader &reader_r)
Skip the current node.
Definition: ParseDef.cc:329
DefaultIntegral< int,-1 > _parseDepth
Definition: ParseDef.cc:177
shared_ptr< ParseDefConsume > getConsumer() const
Get data consumer.
Definition: ParseDef.cc:435
const std::string & name() const
Definition: ParseDef.cc:389
bool nextNode()
Definition: Reader.cc:160
virtual void cdata(const Node &_node)
bool singleDef() const
Definition: ParseDef.cc:401
Assign a vaiable a certain value when going out of scope.
Definition: DtorReset.h:49
bool isOptional() const
Definition: ParseDef.cc:395
bool singleDef() const
Definition: ParseDef.cc:125
Parse exceptions related to the documents node structure.
xmlTextReader based interface to Reader&#39;s current node.
Definition: Node.h:35
bool multiDef() const
Definition: ParseDef.cc:128
#define X(T)
virtual void done(const Node &node_r)
Definition: ParseDef.cc:61
std::map< std::string, ImplPtr > SubNodes
Definition: ParseDef.cc:99
ParseDef implementation.
Definition: ParseDef.cc:94
void take(Reader &reader_r)
Parse the node.
Definition: ParseDef.cc:439
DefaultIntegral< unsigned, 0 > _visited
Definition: ParseDef.cc:171
Mode mode() const
Definition: ParseDef.cc:392
#define WAR
Definition: Logger.h:48
void addNode(const ImplPtr &subnode_r)
Definition: ParseDef.cc:186
ImplPtr getNode(const std::string &name_r) const
Definition: ParseDef.cc:134
Exceptions when building a ParseDef tree.
XmlString name() const
The qualified name of the node, equal to Prefix :LocalName.
Definition: Node.h:115
bool multiDef() const
Definition: ParseDef.cc:404
bool seekToEndNode(int depth_r, const std::string &name_r)
Definition: Reader.cc:232
virtual void startSubnode(const Node &node_r)
Definition: ParseDef.cc:67
Base class for ParseDef consumer.
unsigned visited() const
Definition: ParseDef.cc:407
const char * c_str() const
Explicit conversion to const char *.
Definition: XmlString.h:73
void take(Reader &reader_r)
Definition: ParseDef.cc:207
ParseDefImplConsume _callback
Definition: ParseDef.cc:175
std::string asString() const
Explicit conversion to std::string.
Definition: XmlString.h:77
virtual ~ParseDef()
Definition: ParseDef.cc:386
ParseDef & addNode(ParseDef &subnode_r)
Add subnode definition.
Definition: ParseDef.cc:410
bit::BitField< ModeBitsType > ModeBits
std::string form(const char *format,...)
Printf style construction of std::string.
Definition: String.cc:34
virtual void doneSubnode(const Node &node_r)
Definition: ParseDef.cc:73
ParseDef consumer redirecting all events to another consumer.
bool isMandatory() const
Definition: ParseDef.cc:398
virtual void cdata(const Node &node_r)
Definition: ParseDef.cc:55
bool isOptional() const
Definition: ParseDef.cc:119
std::string exstr(const std::string &what_r, const Impl &impl_r, const Reader &reader_r) const
Definition: ParseDef.cc:161
std::ostream & operator<<(std::ostream &str, const ReadState &obj)
Definition: libxmlfwd.cc:29
void cancelConsumer()
Unset data consumer.
Definition: ParseDef.cc:432
friend std::ostream & operator<<(std::ostream &str, const ParseDef &obj)
Definition: ParseDef.cc:466
ParseDef operator[](const std::string &name_r)
Get subnode by name.
Definition: ParseDef.cc:413
virtual void start(const Node &_node)
bool isMandatory() const
Definition: ParseDef.cc:122
void setConsumer(const shared_ptr< ParseDefConsume > &target_r)
Set data consumer.
Definition: ParseDef.cc:423
void debuglog(const char *const tag_r, const Node &node_r)
Definition: ParseDef.cc:79
virtual void text(const Node &node_r)
Definition: ParseDef.cc:49
Range of bits starting at bit _begin with length _size.
Definition: Bit.h:81
NodeType nodeType() const
Get the node type of the current node.
Definition: Node.h:123
void setRedirect(const shared_ptr< ParseDefConsume > &target_r)
#define DBG
Definition: Logger.h:46
std::string exstr(const std::string &what_r, const Impl &impl_r) const
Definition: ParseDef.cc:155
xmlTextReader based interface to iterate xml streams.
Definition: Reader.h:95