libzypp 17.31.7
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-core/base/DtorReset>
20#include <zypp-core/base/DefaultIntegral>
21
26
27using std::endl;
28
30namespace zypp
31{
33 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 very 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
396 { return _pimpl->isOptional(); }
397
399 { return _pimpl->isMandatory(); }
400
402 { return _pimpl->singleDef(); }
403
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
#define X(T)
std::unordered_set< sat::detail::IdType > _visited
Assign a vaiable a certain value when going out of scope.
Definition: dtorreset.h:50
xmlTextReader based interface to Reader's current node.
Definition: Node.h:36
int depth() const
The depth of the node in the tree.
Definition: Node.h:62
NodeType nodeType() const
Get the node type of the current node.
Definition: Node.h:126
int isEmptyElement() const
Check if the current node is empty.
Definition: Node.h:101
XmlString name() const
The qualified name of the node, equal to Prefix :LocalName.
Definition: Node.h:118
ParseDef consumer redirecting all events to another consumer.
virtual void start(const Node &_node)
virtual void startSubnode(const Node &_node)
virtual void doneSubnode(const Node &_node)
virtual void done(const Node &_node)
virtual void text(const Node &_node)
void setRedirect(const shared_ptr< ParseDefConsume > &target_r)
virtual void cdata(const Node &_node)
ParseDef implementation.
Definition: ParseDef.cc:95
bool isOptional() const
Definition: ParseDef.cc:119
bool skipNode(Reader &reader_r)
Skip the current node.
Definition: ParseDef.cc:329
void take(Reader &reader_r)
Definition: ParseDef.cc:207
DefaultIntegral< int,-1 > _parseDepth
Definition: ParseDef.cc:177
std::string exstr(const std::string &what_r, const Impl &impl_r) const
Definition: ParseDef.cc:155
ImplPtr getNode(const std::string &name_r) const
Definition: ParseDef.cc:134
ParseDefImplConsume _callback
Definition: ParseDef.cc:175
void addNode(const ImplPtr &subnode_r)
Definition: ParseDef.cc:186
DefaultIntegral< unsigned, 0 > _visited
Definition: ParseDef.cc:171
shared_ptr< Impl > ImplPtr
Definition: ParseDef.cc:98
bool isMandatory() const
Definition: ParseDef.cc:122
friend std::ostream & operator<<(std::ostream &str, const ParseDef::Impl &obj)
Definition: ParseDef.cc:348
Impl(const std::string &name_r, Mode mode_r, const shared_ptr< ParseDefConsume > &target_r=shared_ptr< ParseDefConsume >())
Definition: ParseDef.cc:102
std::map< std::string, ImplPtr > SubNodes
Definition: ParseDef.cc:99
bool singleDef() const
Definition: ParseDef.cc:125
std::string exstr(const std::string &what_r, const Impl &impl_r, const Reader &reader_r) const
Definition: ParseDef.cc:161
Define a xml node structure to parse.
Definition: ParseDef.h:129
void setConsumer(const shared_ptr< ParseDefConsume > &target_r)
Set data consumer.
Definition: ParseDef.cc:423
const std::string & name() const
Definition: ParseDef.cc:389
virtual ~ParseDef()
Definition: ParseDef.cc:386
void cancelConsumer()
Unset data consumer.
Definition: ParseDef.cc:432
bool singleDef() const
Definition: ParseDef.cc:401
RW_pointer< Impl > _pimpl
Pointer to implementation (shared!)
Definition: ParseDef.h:220
ParseDef & addNode(ParseDef &subnode_r)
Add subnode definition.
Definition: ParseDef.cc:410
shared_ptr< ParseDefConsume > getConsumer() const
Get data consumer.
Definition: ParseDef.cc:435
friend std::ostream & operator<<(std::ostream &str, const ParseDef &obj)
Definition: ParseDef.cc:466
bool isOptional() const
Definition: ParseDef.cc:395
ParseDef operator[](const std::string &name_r)
Get subnode by name.
Definition: ParseDef.cc:413
bool multiDef() const
Definition: ParseDef.cc:404
void take(Reader &reader_r)
Parse the node.
Definition: ParseDef.cc:439
unsigned visited() const
Definition: ParseDef.cc:407
static bool _debug
Definition: ParseDef.h:229
bool isMandatory() const
Definition: ParseDef.cc:398
ParseDef(const std::string &name_r, Mode mode_r)
Definition: ParseDef.cc:369
Mode mode() const
Definition: ParseDef.cc:392
xmlTextReader based interface to iterate xml streams.
Definition: Reader.h:96
bool seekToEndNode(int depth_r, const std::string &name_r)
Definition: Reader.cc:232
bool nextNode()
Definition: Reader.cc:160
std::string asString() const
Explicit conversion to std::string.
Definition: XmlString.h:77
const char * c_str() const
Explicit conversion to const char *.
Definition: XmlString.h:73
const ProcessCredentials & _callback
String related utilities and Regular expression matching.
std::string form(const char *format,...) __attribute__((format(printf
Printf style construction of std::string.
Definition: String.cc:36
std::ostream & operator<<(std::ostream &str, const ReadState &obj)
Definition: libxmlfwd.cc:29
Easy-to use interface to the ZYPP dependency resolver.
Definition: CodePitfalls.doc:2
Range of bits starting at bit _begin with length _size.
Definition: Bit.h:82
Exceptions when building a ParseDef tree.
Base class for ParseDef consumer.
virtual void text(const Node &node_r)
Definition: ParseDef.cc:49
virtual void startSubnode(const Node &node_r)
Definition: ParseDef.cc:67
virtual void cdata(const Node &node_r)
Definition: ParseDef.cc:55
void debuglog(const char *const tag_r, const Node &node_r)
Definition: ParseDef.cc:79
virtual void doneSubnode(const Node &node_r)
Definition: ParseDef.cc:73
virtual void done(const Node &node_r)
Definition: ParseDef.cc:61
virtual void start(const Node &node_r)
Definition: ParseDef.cc:43
bit::BitField< ModeBitsType > ModeBits
Parse exceptions related to the documents node structure.
#define ZYPP_THROW(EXCPT)
Drops a logline and throws the Exception.
Definition: Exception.h:428
#define DBG
Definition: Logger.h:95
#define WAR
Definition: Logger.h:97