wsdlpull svntrunk
XmlDoc.cpp
Go to the documentation of this file.
1/*
2 * wsdlpull - A C++ parser for WSDL (Web services description language)
3 * XmlNode_t and XmlDoc_t for the WsdlParser
4 * Copyright (C) 2009 Daniel Rodriguez
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the Free
18 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21#include "xmlpull/XmlDoc.h"
22
23
24
26 // XmlNode_t
28
29 XmlNode_t::XmlNode_t( const std::string &p_name, size_t p_depth)
30 {
31 m_name = p_name;
32 m_depth = p_depth;
33
34 m_empty = p_name.empty();
35
36 mp_parent = NULL;
37 mp_prev = NULL;
38 mp_next = NULL;
39 }
40
42 {
43 *this = p_xmlNode;
44 }
45
46 XmlNode_t &
48 {
49 m_name = p_xmlNode.m_name;
50 m_text = p_xmlNode.m_text;
51 m_depth = p_xmlNode.m_depth;
52
53 m_empty = p_xmlNode.m_empty;
54
55 mp_parent = NULL;
56 mp_prev = NULL;
57 mp_next = NULL;
58
59 m_attributes = p_xmlNode.m_attributes;
61
62 m_mapNodes = p_xmlNode.m_mapNodes;
63
64 this->deallocateNodes();
65
66 for( size_t l_i = 0; l_i < p_xmlNode.m_nodes.size(); l_i++) {
67
68 XmlNode_t *l_tmpNode = new XmlNode_t( *( p_xmlNode.m_nodes[ l_i]));
69
70 l_tmpNode->setParent( this);
71
72 if( l_i > 0) {
73 l_tmpNode->setPrev( m_nodes.back());
74 m_nodes.back()->setNext( l_tmpNode);
75 }
76 m_nodes.push_back( l_tmpNode);
77 }
78
79 return *this;
80 }
81
83 {
84 this->deallocateNodes();
85 }
86
87 void
88 XmlNode_t::deallocateNodes( void)
89 {
90 for( size_t l_i = 0; l_i < m_nodes.size(); l_i++)
91 delete m_nodes.at( l_i);
92 m_nodes.clear();
93 }
94
95 void
97 {
98 m_name.clear();
99 m_text.clear();
100
101 m_depth = 1;
102
103 m_empty = true;
104
105 mp_parent = NULL;
106 mp_prev = NULL;
107 mp_next = NULL;
108
109 m_attributes.clear();
110 m_mapAttributes.clear();
111
112 this->deallocateNodes();
113 m_mapNodes.clear();
114 }
115
116 XmlNode_t &
118 {
119 return *mp_parent;
120 }
121
122 void
124 {
125 mp_parent = &p_parent;
126 }
127
128 void
130 {
131 mp_parent = p_parent;
132 }
133
134 XmlNode_t &
136 {
137 return *mp_prev;
138 }
139
140 void
142 {
143 mp_prev = &p_prev;
144 }
145
146 void
148 {
149 mp_prev = p_prev;
150 }
151
152 XmlNode_t &
154 {
155 return *mp_next;
156 }
157
158 void
160 {
161 mp_next = &p_next;
162 }
163
164 void
166 {
167 mp_next = p_next;
168 }
169
170 const std::string &
172 {
173 return m_name;
174 }
175
176 void
177 XmlNode_t::setName( const std::string &p_name, bool p_empty)
178 {
179 m_name = p_name;
180 m_empty = p_empty;
181 }
182
183 const std::string &
185 {
186 return m_text;
187 }
188
189 size_t
191 {
192 return m_depth;
193 }
194
195 void
196 XmlNode_t::setDepth( size_t p_depth)
197 {
198 m_depth = p_depth;
199 }
200
201 bool
203 {
204 return mp_parent == NULL;
205 }
206
207 bool
209 {
210 return m_nodes.empty();
211 }
212
213 XmlNode_t &
214 XmlNode_t::addNode( const std::string &p_name, bool p_empty)
215 {
216 XmlNode_t *l_xmlNode = new XmlNode_t( p_name);
217 l_xmlNode->setEmpty( p_empty);
218 return this->addNode( l_xmlNode);
219 }
220
221 XmlNode_t &
223 {
224
225 m_text.clear();
226
227 XmlNode_t *l_xmlNode = p_xmlNode;
228
229 if( l_xmlNode == NULL)
230 l_xmlNode = new XmlNode_t();
231
232 l_xmlNode->setParent( this);
233
234 if( m_nodes.empty() == false) {
235
236 l_xmlNode->setPrev( m_nodes.back());
237 m_nodes.back()->setNext( l_xmlNode);
238
239 }
240
241 l_xmlNode->setDepth( m_depth + 1);
242 m_nodes.push_back( l_xmlNode);
243
244 m_mapNodes.insert( std::make_pair( l_xmlNode->getName(), m_nodes.size() - 1));
245
246 return *l_xmlNode;
247 }
248
249 void
250 XmlNode_t::addAttribute( const std::string &p_name, const std::string &p_value)
251 {
252 m_attributes.push_back( std::make_pair( p_name, p_value));
253
254 m_mapAttributes.insert( std::make_pair( p_name, m_attributes.size() - 1));
255 }
256
257 bool
258 XmlNode_t::getAttribute( const std::string &p_name, std::string &p_result) const
259 {
260 MapAttributes_t::const_iterator l_it = m_mapAttributes.find( p_name);
261 if( l_it == m_mapAttributes.end())
262 return false;
263 size_t l_index = (*l_it).second;
264 p_result = m_attributes[ l_index].second;
265 return true;
266 }
267
268 void
269 XmlNode_t::setText( const std::string &p_text)
270 {
271 m_nodes.clear();
272
273 m_text = p_text;
274 }
275
276 void
277 XmlNode_t::setEmpty( bool p_empty)
278 {
279 m_empty = p_empty;
280 }
281
282 bool
283 XmlNode_t::empty( void) const
284 {
285 return m_empty;
286 }
287
288 XmlNode_t *
289 XmlNode_t::getNode( const std::string &p_name, size_t p_index) const
290 {
291
292 std::pair<MultiMapNodes_t::const_iterator, MultiMapNodes_t::const_iterator> l_itRange;
293 l_itRange = m_mapNodes.equal_range( p_name);
294
295 MultiMapNodes_t::const_iterator &l_itFirst = l_itRange.first;
296 MultiMapNodes_t::const_iterator &l_itLast = l_itRange.second;
297
298 XmlNode_t *l_resultNode = NULL;
299
300 size_t l_index = 0;
301
302 while( l_itFirst != l_itLast) {
303
304 if( l_index == p_index) {
305
306 l_resultNode = m_nodes[ (*l_itFirst).second];
307 break;
308 }
309 ++l_index;
310 ++l_itFirst;
311 }
312
313 return l_resultNode;
314 }
315
316 void
318 {
319 p_children = m_nodes;
320 }
321
322 void
323 XmlNode_t::findDirectChildren( const std::string &p_name, XmlNode_t::VectorNodePtrs_t &p_children)
324 {
325 for( size_t l_i = 0; l_i < m_nodes.size(); l_i++){
326
327 if( p_name == m_nodes[ l_i]->getName())
328 p_children.push_back( m_nodes[ l_i]);
329 }
330 }
331
332 void
333 XmlNode_t::findSelfOrChildren( const std::string &p_name, XmlNode_t::VectorNodePtrs_t &p_children, bool p_lazyRelativeMatch)
334 {
335
336 if( m_name == p_name) {
337 p_children.push_back( this);
338 return;
339 }
340
341 if( p_lazyRelativeMatch == true) {
342
343 for( size_t l_i = 0; l_i < m_nodes.size(); l_i++){
344
345 m_nodes[ l_i]->findSelfOrChildren( p_name, p_children, p_lazyRelativeMatch);
346
347 }
348 }
349 }
350
351 void
352 XmlNode_t::findAny( const std::string &p_name, XmlNode_t::VectorNodePtrs_t &p_children)
353 {
354 if( m_name == p_name)
355 p_children.push_back( this);
356
357 for( size_t l_i = 0; l_i < m_nodes.size(); l_i++){
358
359 m_nodes[ l_i]->findAny( p_name, p_children);
360
361 }
362 }
363
364 bool
365 XmlNode_t::operator ==( const XmlNode_t &p_xmlNode) const
366 {
367 return m_name == p_xmlNode.m_name;
368 }
369
370 std::ostream &
371 operator <<( std::ostream &p_ostream, const XmlNode_t &p_xmlNode)
372 {
373 p_ostream << std::string( ( p_xmlNode.m_depth - 1) * XmlNode_t::WS_AMOUNT, ' ');
374
375 // Output Start tag
376 p_ostream << "<" << p_xmlNode.m_name;
377
378 // Attributes
379 for( size_t l_i = 0; l_i < p_xmlNode.m_attributes.size(); l_i++) {
380 p_ostream << " "
381 << p_xmlNode.m_attributes[ l_i].first
382 << "=\"" << p_xmlNode.m_attributes[ l_i].second
383 << "\"";
384 }
385 // Close Start tag
386 p_ostream << ">";
387
388 // Output Text or child nodes
389 if( p_xmlNode.isTextNode() == true) {
390 // Output Text
391 p_ostream << p_xmlNode.m_text;
392 } else {
393 p_ostream << std::endl;
394 for( size_t l_i = 0; l_i < p_xmlNode.m_nodes.size(); l_i++) {
395 // Output child nodes
396 p_ostream << *( p_xmlNode.m_nodes[ l_i]);
397 }
398 }
399
400 if( p_xmlNode.isTextNode() == false)
401 p_ostream << std::string( ( p_xmlNode.m_depth - 1)* XmlNode_t::WS_AMOUNT, ' ');
402
403 // Output End tag
404 p_ostream << "</" << p_xmlNode.m_name << ">" << std::endl;
405
406 return p_ostream;
407 }
408
410 // XmlDoc_t
412
413 XmlDoc_t::XmlDoc_t( const XmlNode_t &p_xmlNode)
414 {
415 m_rootNode = p_xmlNode;
416
417 m_processEnvAndBody = false;
418 m_lazyRelativeMatch = true;
419 }
420
421 void
423 {
424 // m_version.clear();
425 // m_encoding.clear();
427 }
428
429 void
430 XmlDoc_t::setProcessEnvAndBody( bool p_processEnvAndBody)
431 {
432 m_processEnvAndBody = p_processEnvAndBody;
433 }
434
435 bool
437 {
438 return m_processEnvAndBody;
439 }
440
441 void
442 XmlDoc_t::setLazyRelativeMatch( bool p_lazyRelativeMatch)
443 {
444 m_lazyRelativeMatch = p_lazyRelativeMatch;
445 }
446
447 bool
449 {
450 return m_lazyRelativeMatch;
451 }
452
453 XmlNode_t &
455 {
456 m_rootNode = p_xmlNode;
457 return m_rootNode;
458 }
459
460 XmlNode_t &
462 {
463 return m_rootNode;
464 }
465
466 const XmlNode_t &
468 {
469 return m_rootNode;
470 }
471
472 bool
473 XmlDoc_t::xpath( const std::string &p_xpath, std::vector< std::string> &p_results, size_t p_index)
474 {
475
476 std::vector< XmlNode_t *> l_nodeSet[ 2];
477 size_t l_curSetIndex = 0;
478
479 // Seed Initial Set of nodes: either skip /Envelope/Body
480 // or be it envelope
481 if( m_processEnvAndBody == true) {
482 l_nodeSet[ l_curSetIndex].push_back( &m_rootNode);
483 } else {
484
485 // /Envelope is the root node, no need to look for it
486 // Get his first child: "Body"
487 XmlNode_t *l_tmpNode = m_rootNode.getNode( "Body");
488
489 // This shouldn't happen, as there /Envelope/Body
490 // should always be there
491 if( l_tmpNode == NULL)
492 return false;
493
494 // Insert all children under /Envelope/Body
495 l_tmpNode->getAllChildren( l_nodeSet[ l_curSetIndex]);
496
497 // If no children ... bail out
498 if( l_nodeSet[ l_curSetIndex].empty() == true)
499 return false;
500 }
501
502 std::string l_name, l_xpath;
503 std::string::size_type l_slashPos = 0;
504 std::string::size_type l_nonSlashPos = 0;
505 size_t l_matchCounter = 0;
506 bool l_matchAny = false;
507 bool l_matchAttribute = false;
508 bool l_lazyRelativeMatch = false;
509
510 // Check if root match is sought
511 if( p_xpath.find( "/") == 0 && p_xpath.find( "//") != 0) {
512
513 // Find the name token
514 l_slashPos = p_xpath.find( "/", 1);
515 l_name = p_xpath.substr( 1, l_slashPos - 1);
516
517 // Check the already seeded set
518 for( size_t l_i = 0; l_i < l_nodeSet[ l_curSetIndex].size(); l_i++) {
519
520 XmlNode_t *l_tmpNode = l_nodeSet[ l_curSetIndex][ l_i];
521
522 // If a name match is found, seed the alternate set
523 if( l_name == l_tmpNode->getName())
524 l_nodeSet[ !l_curSetIndex].push_back( l_tmpNode);
525 }
526
527 // Switch the main and alternate sets
528 l_curSetIndex = !l_curSetIndex;
529
530 // If root match was expected but the set is empty
531 // we may safely return false
532 if( l_nodeSet[ l_curSetIndex].empty() == true)
533 return false;
534
535 // Else, indicate that a match was found. This disables "lazyEvaluationMatch"
536 ++l_matchCounter;
537 }
538
539 // Record the xpath expression before entering the main search loop
540 l_xpath = p_xpath;
541
542 // Do exit when we reach the End of String
543 while( l_slashPos != std::string::npos) {
544
545 // Until we see a double slash, we will not match any single node
546 l_matchAny = false;
547 // The local lazyRelativeMatch is false and can only once be true
548 // During the first match and when the global lazyRelativeMatch is set
549 l_lazyRelativeMatch = false;
550
551 // Reduce the xpath expression to purge the already consumed tokens
552 l_xpath = l_xpath.substr( l_slashPos);
553
554 // If no further input is available ... break away
555 if( l_xpath.empty() == true)
556 break;
557
558 l_slashPos = l_xpath.find( "/");
559
560 if( l_slashPos == 0) {
561
562 // Slash found at the beginning of the string
563
564 // Check for a "matchAny" doubleslash
565 if( l_xpath.find( "//") == 0)
566 l_matchAny = true;
567
568 // Locate the start of the token after the slash(es)
569 l_nonSlashPos = l_xpath.find_first_not_of( "/");
570
571 // Check if there are any characters left
572 // This could well be a trailing slash
573 if( l_nonSlashPos == std::string::npos)
574 break;
575
576 // Locate next slash after the token
577 l_slashPos = l_xpath.find( "/", l_nonSlashPos);
578
579 // Retrieve the token
580 l_name = l_xpath.substr( l_nonSlashPos, l_slashPos - l_nonSlashPos);
581
582 } else {
583
584 // Next slash is somewhere in the middle of the xpath expression
585 // or there are no further slashes ( l_slashPos == npos)
586 // in any case the substr is from 0 to l_slashPos
587 l_name = l_xpath.substr( 0, l_slashPos);
588
589 // If no match has been done, then allow lazyRelativeMatch
590 // to act (if so configured)
591 if( l_matchCounter == 0 && m_lazyRelativeMatch == true)
592 l_lazyRelativeMatch = true;
593 }
594
595 // Indicate that a match happened (to avoid lazyRelativeMatch)
596 ++l_matchCounter;
597
598 // If no token is found ... bail out
599 if( l_name.empty() == true)
600 break;
601
602 // Check if attribute values are sought
603 if( l_name[ 0] == '@') {
604
605 // Mark the fact that an attribut is sought
606 l_matchAttribute = true;
607 // Purge the "@" from the token
608 l_name = l_name.substr( 1);
609
610 // break away, since the previous token has been a match
611 // and attributes are not matched in the xml tree
612 // but rather extracted from the last set of matched nodes
613 break;
614 }
615
616 // Clear the alternate set, as we are in a loop
617 l_nodeSet[ !l_curSetIndex].clear();
618
619 for( size_t l_i = 0; l_i < l_nodeSet[ l_curSetIndex].size(); l_i++) {
620
621 XmlNode_t *l_tmpNode = l_nodeSet[ l_curSetIndex][ l_i];
622
623 // Match any node according to "name" if sought
624 if( l_matchAny == true)
625 l_tmpNode->findAny( l_name, l_nodeSet[ !l_curSetIndex]);
626 // if lazyRelative is acting, go down the tree looking for the first match of "name"
627 else if( l_lazyRelativeMatch == true)
628 l_tmpNode->findSelfOrChildren( l_name, l_nodeSet[ !l_curSetIndex], l_lazyRelativeMatch);
629 // in any other case, see if any direct children matches "name"
630 else
631 l_tmpNode->findDirectChildren( l_name, l_nodeSet[ !l_curSetIndex]);
632 }
633
634 // Swap the sets
635 l_curSetIndex = !l_curSetIndex;
636
637 // If no node is selected ... exit happily
638 if( l_nodeSet[ l_curSetIndex].empty() == true)
639 return false;
640 }
641
642 // A nodeSet should be in place, so we should be able to fill the results
643
644 for( size_t l_i = 0; l_i < l_nodeSet[ l_curSetIndex].size(); l_i++) {
645
646 XmlNode_t *l_tmpNode = l_nodeSet[ l_curSetIndex][ l_i];
647
648 // According to W3C standards, nodes start at "1"
649 // So we use p_index == 0 to mark that we take all nodes
650 // If p_index != 0, then we will only return one result
651 if( p_index == 0 || ( l_i == ( p_index - 1))) {
652
653 if( l_matchAttribute == false) {
654 // Fill results with text from the node
655 p_results.push_back( l_tmpNode->getText());
656 } else {
657 // Extract the attribute and add it to the results
658 std::string l_tmpAttr;
659 if( l_tmpNode->getAttribute( l_name, l_tmpAttr) == true)
660 p_results.push_back( l_tmpAttr);
661 }
662 }
663 }
664
665 // Tell the world if any results is being delivered back
666 return ( p_results.empty() == false);
667 }
668
669 std::ostream &
670 operator <<( std::ostream &p_ostream, const XmlDoc_t &p_xmlDoc)
671 {
672 // p_ostream << "<?xml version=\"" << m_version << "\" encoding=\"" << m_encoding << "\"" << std::endl;
673 p_ostream << p_xmlDoc.m_rootNode;
674
675 return p_ostream;
676 }
677
678
std::ostream & operator<<(std::ostream &p_ostream, const XmlNode_t &p_xmlNode)
Definition: XmlDoc.cpp:371
XmlDoc_t(const XmlNode_t &p_xmlNode=XmlNode_t())
Definition: XmlDoc.cpp:413
void setLazyRelativeMatch(bool p_lazyRelativeMatch)
Definition: XmlDoc.cpp:442
XmlNode_t m_rootNode
Definition: XmlDoc.h:132
XmlNode_t & setRootNode(const XmlNode_t &p_xmlNode)
Definition: XmlDoc.cpp:454
void clear(void)
Definition: XmlDoc.cpp:422
void setProcessEnvAndBody(bool p_processEnvAndBody)
Definition: XmlDoc.cpp:430
bool getLazyRelativeMatch(void) const
Definition: XmlDoc.cpp:448
bool m_processEnvAndBody
Definition: XmlDoc.h:134
bool m_lazyRelativeMatch
Definition: XmlDoc.h:135
XmlNode_t & getRootNode(void)
Definition: XmlDoc.cpp:461
bool getProcessEnvAndBody(void) const
Definition: XmlDoc.cpp:436
bool xpath(const std::string &p_xpath, std::vector< std::string > &p_results, size_t p_index=0)
Definition: XmlDoc.cpp:473
@ WS_AMOUNT
Definition: XmlDoc.h:35
XmlNode_t(const std::string &p_name="", size_t p_depth=0)
Definition: XmlDoc.cpp:29
size_t m_depth
Definition: XmlDoc.h:42
void setEmpty(bool p_empty)
Definition: XmlDoc.cpp:277
void setText(const std::string &p_text)
Definition: XmlDoc.cpp:269
void clear(void)
Definition: XmlDoc.cpp:96
XmlNode_t * mp_parent
Definition: XmlDoc.h:58
XmlNode_t * mp_next
Definition: XmlDoc.h:60
bool getAttribute(const std::string &p_name, std::string &p_result) const
Definition: XmlDoc.cpp:258
void setDepth(size_t p_depth)
Definition: XmlDoc.cpp:196
MapAttributes_t m_mapAttributes
Definition: XmlDoc.h:53
void findAny(const std::string &p_name, XmlNode_t::VectorNodePtrs_t &p_children)
Definition: XmlDoc.cpp:352
VectorNodePtrs_t m_nodes
Definition: XmlDoc.h:62
XmlNode_t * getNode(const std::string &p_name, size_t p_index=0) const
Definition: XmlDoc.cpp:289
void setParent(XmlNode_t &p_parent)
Definition: XmlDoc.cpp:123
XmlNode_t * mp_prev
Definition: XmlDoc.h:59
const std::string & getName(void) const
Definition: XmlDoc.cpp:171
MultiMapNodes_t m_mapNodes
Definition: XmlDoc.h:63
void findDirectChildren(const std::string &p_name, XmlNode_t::VectorNodePtrs_t &p_children)
Definition: XmlDoc.cpp:323
void setNext(XmlNode_t &p_next)
Definition: XmlDoc.cpp:159
std::string m_text
Definition: XmlDoc.h:47
void addAttribute(const std::string &p_name, const std::string &p_value)
Definition: XmlDoc.cpp:250
XmlNode_t & getPrev(void) const
Definition: XmlDoc.cpp:135
XmlNode_t & getParent(void) const
Definition: XmlDoc.cpp:117
bool m_empty
Definition: XmlDoc.h:44
XmlNode_t & addNode(XmlNode_t *p_xmlNode=NULL)
Definition: XmlDoc.cpp:222
std::string m_name
Definition: XmlDoc.h:46
virtual ~XmlNode_t()
Definition: XmlDoc.cpp:82
XmlNode_t & operator=(const XmlNode_t &p_xmlNode)
Definition: XmlDoc.cpp:47
const std::string & getText(void) const
Definition: XmlDoc.cpp:184
bool isTextNode(void) const
Definition: XmlDoc.cpp:208
void setPrev(XmlNode_t &p_prev)
Definition: XmlDoc.cpp:141
std::vector< XmlNode_t * > VectorNodePtrs_t
Definition: XmlDoc.h:55
void getAllChildren(XmlNode_t::VectorNodePtrs_t &p_children)
Definition: XmlDoc.cpp:317
VectorAttributes_t m_attributes
Definition: XmlDoc.h:52
bool empty(void) const
Definition: XmlDoc.cpp:283
bool isRootNode(void) const
Definition: XmlDoc.cpp:202
XmlNode_t & getNext(void) const
Definition: XmlDoc.cpp:153
size_t getDepth(void) const
Definition: XmlDoc.cpp:190
void setName(const std::string &p_name, bool p_empty=XmlNode_t::EMPTY_NODE)
Definition: XmlDoc.cpp:177
bool operator==(const XmlNode_t &p_xmlNode) const
Definition: XmlDoc.cpp:365
void findSelfOrChildren(const std::string &p_name, XmlNode_t::VectorNodePtrs_t &p_children, bool p_lazyRelativeMatch=false)
Definition: XmlDoc.cpp:333