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