wsdlpull  1.23
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 
41  XmlNode_t::XmlNode_t( const XmlNode_t &p_xmlNode)
42  {
43  *this = p_xmlNode;
44  }
45 
46  XmlNode_t &
47  XmlNode_t::operator =( const XmlNode_t &p_xmlNode)
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;
60  m_mapAttributes = p_xmlNode.m_mapAttributes;
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 &
117  XmlNode_t::getParent( void) const
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 &
135  XmlNode_t::getPrev( void) const
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 &
153  XmlNode_t::getNext( void) const
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 &
171  XmlNode_t::getName( void) const
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 &
184  XmlNode_t::getText( void) const
185  {
186  return m_text;
187  }
188 
189  size_t
190  XmlNode_t::getDepth( void) const
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();
426  m_rootNode.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 &
454  XmlDoc_t::setRootNode( const XmlNode_t &p_xmlNode)
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 
XmlNode_t(const std::string &p_name="", size_t p_depth=0)
Definition: XmlDoc.cpp:29
void getAllChildren(XmlNode_t::VectorNodePtrs_t &p_children)
Definition: XmlDoc.cpp:317
bool operator==(const XmlNode_t &p_xmlNode) const
Definition: XmlDoc.cpp:365
void setDepth(size_t p_depth)
Definition: XmlDoc.cpp:196
XmlNode_t * getNode(const std::string &p_name, size_t p_index=0) const
Definition: XmlDoc.cpp:289
std::vector< XmlNode_t * > VectorNodePtrs_t
Definition: XmlDoc.h:55
XmlNode_t * mp_prev
Definition: XmlDoc.h:59
friend 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
XmlNode_t & addNode(XmlNode_t *p_xmlNode=NULL)
Definition: XmlDoc.cpp:222
size_t getDepth(void) const
Definition: XmlDoc.cpp:190
void setPrev(XmlNode_t &p_prev)
Definition: XmlDoc.cpp:141
void setEmpty(bool p_empty)
Definition: XmlDoc.cpp:277
void findDirectChildren(const std::string &p_name, XmlNode_t::VectorNodePtrs_t &p_children)
Definition: XmlDoc.cpp:323
void clear(void)
Definition: XmlDoc.cpp:96
XmlNode_t * mp_next
Definition: XmlDoc.h:60
bool getProcessEnvAndBody(void) const
Definition: XmlDoc.cpp:436
bool isRootNode(void) const
Definition: XmlDoc.cpp:202
bool xpath(const std::string &p_xpath, std::vector< std::string > &p_results, size_t p_index=0)
Definition: XmlDoc.cpp:473
virtual ~XmlNode_t()
Definition: XmlDoc.cpp:82
XmlNode_t & operator=(const XmlNode_t &p_xmlNode)
Definition: XmlDoc.cpp:47
void setLazyRelativeMatch(bool p_lazyRelativeMatch)
Definition: XmlDoc.cpp:442
void setText(const std::string &p_text)
Definition: XmlDoc.cpp:269
void setProcessEnvAndBody(bool p_processEnvAndBody)
Definition: XmlDoc.cpp:430
XmlNode_t m_rootNode
Definition: XmlDoc.h:132
XmlNode_t & getParent(void) const
Definition: XmlDoc.cpp:117
MapAttributes_t m_mapAttributes
Definition: XmlDoc.h:53
void addAttribute(const std::string &p_name, const std::string &p_value)
Definition: XmlDoc.cpp:250
MultiMapNodes_t m_mapNodes
Definition: XmlDoc.h:63
XmlNode_t & getNext(void) const
Definition: XmlDoc.cpp:153
bool empty(void) const
Definition: XmlDoc.cpp:283
const std::string & getName(void) const
Definition: XmlDoc.cpp:171
void setName(const std::string &p_name, bool p_empty=XmlNode_t::EMPTY_NODE)
Definition: XmlDoc.cpp:177
void setNext(XmlNode_t &p_next)
Definition: XmlDoc.cpp:159
VectorAttributes_t m_attributes
Definition: XmlDoc.h:52
const std::string & getText(void) const
Definition: XmlDoc.cpp:184
std::string m_text
Definition: XmlDoc.h:47
void setParent(XmlNode_t &p_parent)
Definition: XmlDoc.cpp:123
XmlNode_t & getPrev(void) const
Definition: XmlDoc.cpp:135
bool getLazyRelativeMatch(void) const
Definition: XmlDoc.cpp:448
XmlNode_t & setRootNode(const XmlNode_t &p_xmlNode)
Definition: XmlDoc.cpp:454
VectorNodePtrs_t m_nodes
Definition: XmlDoc.h:62
void clear(void)
Definition: XmlDoc.cpp:422
XmlNode_t & getRootNode(void)
Definition: XmlDoc.cpp:461
void findAny(const std::string &p_name, XmlNode_t::VectorNodePtrs_t &p_children)
Definition: XmlDoc.cpp:352
size_t m_depth
Definition: XmlDoc.h:42
void findSelfOrChildren(const std::string &p_name, XmlNode_t::VectorNodePtrs_t &p_children, bool p_lazyRelativeMatch=false)
Definition: XmlDoc.cpp:333
XmlNode_t * mp_parent
Definition: XmlDoc.h:58
bool getAttribute(const std::string &p_name, std::string &p_result) const
Definition: XmlDoc.cpp:258
bool m_empty
Definition: XmlDoc.h:44
bool isTextNode(void) const
Definition: XmlDoc.cpp:208
std::string m_name
Definition: XmlDoc.h:46