gloox  1.0.23
tag.cpp
1 /*
2  Copyright (c) 2005-2019 by Jakob Schröter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 
14 #include "tag.h"
15 #include "util.h"
16 
17 #include <ctype.h>
18 #include <stdlib.h>
19 
20 #include <algorithm>
21 
22 namespace gloox
23 {
24 
25  // ---- Tag::Attribute ----
26  Tag::Attribute::Attribute( Tag* parent, const std::string& name, const std::string& value,
27  const std::string& xmlns )
28  : m_parent( parent )
29  {
30  if( m_parent )
31  m_parent->addAttribute( this );
32 
33  init( name, value, xmlns );
34  }
35 
36  Tag::Attribute::Attribute( const std::string& name, const std::string& value,
37  const std::string& xmlns )
38  : m_parent( 0 )
39  {
40  init( name, value, xmlns );
41  }
42 
44  : m_parent( attr.m_parent ), m_name( attr.m_name ), m_value( attr.m_value ),
45  m_xmlns( attr.m_xmlns ), m_prefix( attr.m_prefix )
46  {
47  }
48 
49  void Tag::Attribute::init( const std::string& name, const std::string& value,
50  const std::string& xmlns )
51  {
52  if( util::checkValidXMLChars( xmlns ) )
53  m_xmlns = xmlns;
54  else
55  return;
56 
57  if( util::checkValidXMLChars( value ) )
58  m_value = value;
59  else
60  return;
61 
62  if( util::checkValidXMLChars( name ) )
63  m_name = name;
64  else
65  return;
66  }
67 
68  bool Tag::Attribute::setValue( const std::string& value )
69  {
70  if( !util::checkValidXMLChars( value ) )
71  return false;
72 
73  m_value = value;
74  return true;
75  }
76 
77  bool Tag::Attribute::setXmlns( const std::string& xmlns )
78  {
79  if( !util::checkValidXMLChars( xmlns ) )
80  return false;
81 
82  m_xmlns = xmlns;
83  return true;
84  }
85 
86  bool Tag::Attribute::setPrefix( const std::string& prefix )
87  {
88  if( !util::checkValidXMLChars( prefix ) )
89  return false;
90 
91  m_prefix = prefix;
92  return true;
93  }
94 
95  const std::string Tag::Attribute::xmlns() const
96  {
97  if( !m_xmlns.empty() )
98  return m_xmlns;
99 
100  if( m_parent )
101  return m_parent->xmlns( m_prefix );
102 
103  return EmptyString;
104  }
105 
106  const std::string& Tag::Attribute::prefix() const
107  {
108  if( !m_prefix.empty() )
109  return m_prefix;
110 
111  if( m_parent )
112  return m_parent->prefix( m_xmlns );
113 
114  return EmptyString;
115  }
116 
117  const std::string Tag::Attribute::xml() const
118  {
119  if( m_name.empty() )
120  return EmptyString;
121 
122  std::string xml;
123  xml += ' ';
124  if( !m_prefix.empty() )
125  {
126  xml += m_prefix;
127  xml += ':';
128  }
129  xml += m_name;
130  xml += "='";
131  util::appendEscaped( xml, m_value );
132  xml += '\'';
133 
134  return xml;
135  }
136  // ---- ~Tag::Attribute ----
137 
138  // ---- Tag ----
139  Tag::Tag( const std::string& name, const std::string& cdata )
140  : m_parent( 0 ), m_children( 0 ), m_cdata( 0 ),
141  m_attribs( 0 ), m_nodes( 0 ),
142  m_xmlnss( 0 )
143  {
144  addCData( cdata ); // implicitly UTF-8 checked
145 
146  if( util::checkValidXMLChars( name ) )
147  m_name = name;
148  }
149 
150  Tag::Tag( Tag* parent, const std::string& name, const std::string& cdata )
151  : m_parent( parent ), m_children( 0 ), m_cdata( 0 ),
152  m_attribs( 0 ), m_nodes( 0 ),
153  m_xmlnss( 0 )
154  {
155  if( m_parent )
156  m_parent->addChild( this );
157 
158  addCData( cdata ); // implicitly UTF-8 checked
159 
160  if( util::checkValidXMLChars( name ) )
161  m_name = name;
162  }
163 
164  Tag::Tag( const std::string& name,
165  const std::string& attrib,
166  const std::string& value )
167  : m_parent( 0 ), m_children( 0 ), m_cdata( 0 ),
168  m_attribs( 0 ), m_nodes( 0 ),
169  m_name( name ), m_xmlnss( 0 )
170  {
171  addAttribute( attrib, value ); // implicitly UTF-8 checked
172 
173  if( util::checkValidXMLChars( name ) )
174  m_name = name;
175  }
176 
177  Tag::Tag( Tag* parent, const std::string& name,
178  const std::string& attrib,
179  const std::string& value )
180  : m_parent( parent ), m_children( 0 ), m_cdata( 0 ),
181  m_attribs( 0 ), m_nodes( 0 ),
182  m_name( name ), m_xmlnss( 0 )
183  {
184  if( m_parent )
185  m_parent->addChild( this );
186 
187  addAttribute( attrib, value ); // implicitly UTF-8 checked
188 
189  if( util::checkValidXMLChars( name ) )
190  m_name = name;
191  }
192 
193  Tag::Tag( Tag* tag )
194  : m_parent( 0 ), m_children( 0 ), m_cdata( 0 ), m_attribs( 0 ),
195  m_nodes( 0 ), m_xmlnss( 0 )
196  {
197  if( !tag )
198  return;
199 
200  m_children = tag->m_children;
201  m_cdata = tag->m_cdata;
202  m_attribs = tag->m_attribs;
203  m_nodes = tag->m_nodes;
204  m_name = tag->m_name;
205  m_xmlns = tag->m_xmlns;
206  m_xmlnss = tag->m_xmlnss;
207 
208  tag->m_nodes = 0;
209  tag->m_cdata = 0;
210  tag->m_attribs = 0;
211  tag->m_children = 0;
212  tag->m_xmlnss = 0;
213 
214  if( m_attribs )
215  {
216  AttributeList::iterator it = m_attribs->begin();
217  while( it != m_attribs->end() )
218  (*it++)->m_parent = this;
219  }
220 
221  if( m_children )
222  {
223  TagList::iterator it = m_children->begin();
224  while( it != m_children->end() )
225  (*it++)->m_parent = this;
226  }
227  }
228 
230  {
231  if( m_cdata )
232  util::clearList( *m_cdata );
233  if( m_attribs )
234  util::clearList( *m_attribs );
235  if( m_children )
236  util::clearList( *m_children );
237  if( m_nodes )
238  util::clearList( *m_nodes );
239 
240  delete m_cdata;
241  delete m_attribs;
242  delete m_children;
243  delete m_nodes;
244  delete m_xmlnss;
245 
246  m_parent = 0;
247  }
248 
249  bool Tag::operator==( const Tag& right ) const
250  {
251  if( m_name != right.m_name || m_xmlns != right.m_xmlns )
252  return false;
253 
254  if( m_cdata && right.m_cdata )
255  {
256  StringPList::const_iterator ct = m_cdata->begin();
257  StringPList::const_iterator ct_r = right.m_cdata->begin();
258  while( ct != m_cdata->end() && ct_r != right.m_cdata->end() && *(*ct) == *(*ct_r) )
259  {
260  ++ct;
261  ++ct_r;
262  }
263  if( ct != m_cdata->end() )
264  return false;
265  }
266  else if( m_cdata || right.m_cdata )
267  return false;
268 
269  if( m_children && right.m_children )
270  {
271  TagList::const_iterator it = m_children->begin();
272  TagList::const_iterator it_r = right.m_children->begin();
273  while( it != m_children->end() && it_r != right.m_children->end() && *(*it) == *(*it_r) )
274  {
275  ++it;
276  ++it_r;
277  }
278  if( it != m_children->end() )
279  return false;
280  }
281  else if( m_children || right.m_children )
282  return false;
283 
284  if( m_attribs && right.m_attribs )
285  {
286  AttributeList::const_iterator at = m_attribs->begin();
287  AttributeList::const_iterator at_r = right.m_attribs->begin();
288  while( at != m_attribs->end() && at_r != right.m_attribs->end() && *(*at) == *(*at_r) )
289  {
290  ++at;
291  ++at_r;
292  }
293  if( at != m_attribs->end() )
294  return false;
295  }
296  else if( m_attribs || right.m_attribs )
297  return false;
298 
299  return true;
300  }
301 
302  const std::string Tag::xml() const
303  {
304  if( m_name.empty() )
305  return EmptyString;
306 
307  std::string xml = "<";
308  if( !m_prefix.empty() )
309  {
310  xml += m_prefix;
311  xml += ':';
312  }
313  xml += m_name;
314  if( m_attribs && !m_attribs->empty() )
315  {
316  AttributeList::const_iterator it_a = m_attribs->begin();
317  for( ; it_a != m_attribs->end(); ++it_a )
318  {
319  xml += (*it_a)->xml();
320  }
321  }
322 
323  if( !m_nodes || m_nodes->empty() )
324  xml += "/>";
325  else
326  {
327  xml += '>';
328  NodeList::const_iterator it_n = m_nodes->begin();
329  for( ; it_n != m_nodes->end(); ++it_n )
330  {
331  switch( (*it_n)->type )
332  {
333  case TypeTag:
334  xml += (*it_n)->tag->xml();
335  break;
336  case TypeString:
337  util::appendEscaped( xml, *((*it_n)->str) );
338  break;
339  }
340  }
341  xml += "</";
342  if( !m_prefix.empty() )
343  {
344  xml += m_prefix;
345  xml += ':';
346  }
347  xml += m_name;
348  xml += '>';
349  }
350 
351  return xml;
352  }
353 
355  {
356  if( !attr )
357  return false;
358 
359  if( !(*attr) )
360  {
361  delete attr;
362  return false;
363  }
364 
365  if( !m_attribs )
366  m_attribs = new AttributeList();
367 
368  AttributeList::iterator it = m_attribs->begin();
369  for( ; it != m_attribs->end(); ++it )
370  {
371  if( (*it)->name() == attr->name()
372  && ( (*it)->xmlns() == attr->xmlns() || (*it)->prefix() == attr->prefix() ) )
373  {
374  delete (*it);
375  (*it) = attr;
376  return true;
377  }
378  }
379 
380  m_attribs->push_back( attr );
381 
382  return true;
383  }
384 
385  bool Tag::addAttribute( const std::string& name, const std::string& value )
386  {
387  if( name.empty() || value.empty() )
388  return false;
389 
390  return addAttribute( new Attribute( name, value ) );
391  }
392 
393  bool Tag::addAttribute( const std::string& name, int value )
394  {
395  if( name.empty() )
396  return false;
397 
398  return addAttribute( name, util::int2string( value ) );
399  }
400 
401  bool Tag::addAttribute( const std::string& name, long value )
402  {
403  if( name.empty() )
404  return false;
405 
406  return addAttribute( name, util::long2string( value ) );
407  }
408 
410  {
411  if( !m_attribs )
412  m_attribs = new AttributeList( attributes );
413  else
414  {
415  util::clearList( *m_attribs );
416  *m_attribs = attributes;
417  }
418 
419  AttributeList::iterator it = m_attribs->begin();
420  for( ; it != m_attribs->end(); ++it )
421  (*it)->m_parent = this;
422  }
423 
424  void Tag::addChild( Tag* child )
425  {
426  if( !child )
427  return;
428 
429  if( !m_nodes )
430  m_nodes = new NodeList();
431  if( !m_children )
432  m_children = new TagList();
433 
434  m_children->push_back( child );
435  child->m_parent = this;
436  m_nodes->push_back( new Node( TypeTag, child ) );
437  }
438 
439  void Tag::addChildCopy( const Tag* child )
440  {
441  if( !child )
442  return;
443 
444  addChild( child->clone() );
445  }
446 
447  bool Tag::setCData( const std::string& cdata )
448  {
449  if( cdata.empty() || !util::checkValidXMLChars( cdata ) )
450  return false;
451 
452  if( !m_cdata )
453  m_cdata = new StringPList();
454  else
455  util::clearList( *m_cdata );
456 
457  if( !m_nodes )
458  m_nodes = new NodeList();
459  else
460  {
461  NodeList::iterator it = m_nodes->begin();
462  NodeList::iterator t;
463  while( it != m_nodes->end() )
464  {
465  if( (*it)->type == TypeString )
466  {
467  t = it++;
468  delete (*t);
469  m_nodes->erase( t );
470  }
471  else
472  {
473  it++;
474  }
475  }
476  }
477 
478  return addCData( cdata );
479  }
480 
481  bool Tag::addCData( const std::string& cdata )
482  {
483  if( cdata.empty() || !util::checkValidXMLChars( cdata ) )
484  return false;
485 
486  if( !m_cdata )
487  m_cdata = new StringPList();
488  if( !m_nodes )
489  m_nodes = new NodeList();
490 
491  std::string* str = new std::string( cdata );
492  m_cdata->push_back( str );
493  m_nodes->push_back( new Node( TypeString, str ) );
494  return true;
495  }
496 
497  const std::string Tag::cdata() const
498  {
499  if( !m_cdata )
500  return EmptyString;
501 
502  std::string str;
503  StringPList::const_iterator it = m_cdata->begin();
504  for( ; it != m_cdata->end(); ++it )
505  str += *(*it);
506 
507  return str;
508  }
509 
510  const TagList& Tag::children() const
511  {
512  static const TagList empty;
513  return m_children ? *m_children : empty;
514  }
515 
517  {
518  static const AttributeList empty;
519  return m_attribs ? *m_attribs : empty;
520  }
521 
522  bool Tag::setXmlns( const std::string& xmlns, const std::string& prefix )
523  {
524  if( !util::checkValidXMLChars( xmlns ) || !util::checkValidXMLChars( prefix ) )
525  return false;
526 
527  if( prefix.empty() )
528  {
529  m_xmlns = xmlns;
530  return addAttribute( XMLNS, m_xmlns );
531  }
532  else
533  {
534  if( !m_xmlnss )
535  m_xmlnss = new StringMap();
536 
537  (*m_xmlnss)[prefix] = xmlns;
538 
539  return addAttribute( XMLNS + ":" + prefix, xmlns );
540  }
541  }
542 
543  const std::string Tag::xmlns() const
544  {
545  return xmlns( m_prefix );
546  }
547 
548  const std::string Tag::xmlns( const std::string& prefix ) const
549  {
550  if( prefix.empty() )
551  {
552  return hasAttribute( XMLNS ) ? findAttribute( XMLNS ) : m_xmlns;
553  }
554 
555  if( m_xmlnss )
556  {
557  StringMap::const_iterator it = m_xmlnss->find( prefix );
558  if( it != m_xmlnss->end() )
559  return (*it).second;
560  }
561 
562  return m_parent ? m_parent->xmlns( prefix ) : EmptyString;
563  }
564 
565  bool Tag::setPrefix( const std::string& prefix )
566  {
567  if( !util::checkValidXMLChars( prefix ) )
568  return false;
569 
570  m_prefix = prefix;
571  return true;
572  }
573 
574  const std::string& Tag::prefix( const std::string& xmlns ) const
575  {
576  if( xmlns.empty() || !m_xmlnss )
577  return EmptyString;
578 
579  StringMap::const_iterator it = m_xmlnss->begin();
580  for( ; it != m_xmlnss->end(); ++it )
581  {
582  if( (*it).second == xmlns )
583  return (*it).first;
584  }
585 
586  return EmptyString;
587  }
588 
589  const std::string& Tag::findAttribute( const std::string& name ) const
590  {
591  if( !m_attribs )
592  return EmptyString;
593 
594  AttributeList::const_iterator it = m_attribs->begin();
595  for( ; it != m_attribs->end(); ++it )
596  if( (*it)->name() == name )
597  return (*it)->value();
598 
599  return EmptyString;
600  }
601 
602  bool Tag::hasAttribute( const std::string& name, const std::string& value ) const
603  {
604  if( name.empty() || !m_attribs )
605  return false;
606 
607  AttributeList::const_iterator it = m_attribs->begin();
608  for( ; it != m_attribs->end(); ++it )
609  if( (*it)->name() == name )
610  return value.empty() || (*it)->value() == value;
611 
612  return false;
613  }
614 
615  bool Tag::hasChild( const std::string& name, const std::string& attr,
616  const std::string& value ) const
617  {
618  if( attr.empty() )
619  return findChild( name ) ? true : false;
620  else
621  return findChild( name, attr, value ) ? true : false;
622  }
623 
624  Tag* Tag::findChild( const std::string& name ) const
625  {
626  if( !m_children )
627  return 0;
628 
629  TagList::const_iterator it = m_children->begin();
630  while( it != m_children->end() && (*it)->name() != name )
631  ++it;
632  return it != m_children->end() ? (*it) : 0;
633  }
634 
635  Tag* Tag::findChild( const std::string& name, const std::string& attr,
636  const std::string& value ) const
637  {
638  if( !m_children || name.empty() )
639  return 0;
640 
641  TagList::const_iterator it = m_children->begin();
642  while( it != m_children->end() && ( (*it)->name() != name || !(*it)->hasAttribute( attr, value ) ) )
643  ++it;
644  return it != m_children->end() ? (*it) : 0;
645  }
646 
647  bool Tag::hasChildWithCData( const std::string& name, const std::string& cdata ) const
648  {
649  if( !m_children || name.empty() || cdata.empty() )
650  return 0;
651 
652  TagList::const_iterator it = m_children->begin();
653  while( it != m_children->end() && ( (*it)->name() != name
654  || ( !cdata.empty() && (*it)->cdata() != cdata ) ) )
655  ++it;
656  return it != m_children->end();
657  }
658 
659  Tag* Tag::findChildWithAttrib( const std::string& attr, const std::string& value ) const
660  {
661  if( !m_children || attr.empty() )
662  return 0;
663 
664  TagList::const_iterator it = m_children->begin();
665  while( it != m_children->end() && !(*it)->hasAttribute( attr, value ) )
666  ++it;
667  return it != m_children->end() ? (*it) : 0;
668  }
669 
670  Tag* Tag::clone() const
671  {
672  Tag* t = new Tag( m_name );
673  t->m_xmlns = m_xmlns;
674  t->m_prefix = m_prefix;
675 
676  if( m_attribs )
677  {
678  t->m_attribs = new AttributeList();
679  Tag::AttributeList::const_iterator at = m_attribs->begin();
680  Attribute* attr;
681  for( ; at != m_attribs->end(); ++at )
682  {
683  attr = new Attribute( *(*at) );
684  attr->m_parent = t;
685  t->m_attribs->push_back( attr );
686  }
687  }
688 
689  if( m_xmlnss )
690  {
691  t->m_xmlnss = new StringMap( *m_xmlnss );
692  }
693 
694  if( m_nodes )
695  {
696  Tag::NodeList::const_iterator nt = m_nodes->begin();
697  for( ; nt != m_nodes->end(); ++nt )
698  {
699  switch( (*nt)->type )
700  {
701  case TypeTag:
702  t->addChild( (*nt)->tag->clone() );
703  break;
704  case TypeString:
705  t->addCData( *((*nt)->str) );
706  break;
707  }
708  }
709  }
710 
711  return t;
712  }
713 
714  TagList Tag::findChildren( const std::string& name,
715  const std::string& xmlns ) const
716  {
717  return m_children ? findChildren( *m_children, name, xmlns ) : TagList();
718  }
719 
720  TagList Tag::findChildren( const TagList& list, const std::string& name,
721  const std::string& xmlns ) const
722  {
723  TagList ret;
724  TagList::const_iterator it = list.begin();
725  for( ; it != list.end(); ++it )
726  {
727  if( (*it)->name() == name && ( xmlns.empty() || (*it)->xmlns() == xmlns ) )
728  ret.push_back( (*it) );
729  }
730  return ret;
731  }
732 
733  void Tag::removeChild( const std::string& name, const std::string& xmlns )
734  {
735  if( name.empty() || !m_children || !m_nodes )
736  return;
737 
738  TagList l = findChildren( name, xmlns );
739  TagList::iterator it = l.begin();
740  TagList::iterator it2;
741  while( it != l.end() )
742  {
743  it2 = it++;
744  NodeList::iterator itn = m_nodes->begin();
745  for( ; itn != m_nodes->end(); ++itn )
746  {
747  if( (*itn)->type == TypeTag && (*itn)->tag == (*it2) )
748  {
749  delete (*itn);
750  m_nodes->erase( itn );
751  break;
752  }
753  }
754  m_children->remove( (*it2) );
755  delete (*it2);
756  }
757  }
758 
759  void Tag::removeChild( Tag* tag )
760  {
761  if( m_children )
762  m_children->remove( tag );
763 
764  if( !m_nodes )
765  return;
766 
767  NodeList::iterator it = m_nodes->begin();
768  for( ; it != m_nodes->end(); ++it )
769  {
770  if( (*it)->type == TypeTag && (*it)->tag == tag )
771  {
772  delete (*it);
773  m_nodes->erase( it );
774  return;
775  }
776  }
777  }
778 
779  void Tag::removeAttribute( const std::string& attr, const std::string& value,
780  const std::string& xmlns )
781  {
782  if( attr.empty() || !m_attribs )
783  return;
784 
785  AttributeList::iterator it = m_attribs->begin();
786  AttributeList::iterator it2;
787  while( it != m_attribs->end() )
788  {
789  it2 = it++;
790  if( (*it2)->name() == attr && ( value.empty() || (*it2)->value() == value )
791  && ( xmlns.empty() || (*it2)->xmlns() == xmlns ) )
792  {
793  delete (*it2);
794  m_attribs->erase( it2 );
795  }
796  }
797  }
798 
799  const std::string Tag::findCData( const std::string& expression ) const
800  {
801  const ConstTagList& l = findTagList( expression );
802  return !l.empty() ? l.front()->cdata() : EmptyString;
803  }
804 
805  const Tag* Tag::findTag( const std::string& expression ) const
806  {
807  const ConstTagList& l = findTagList( expression );
808  return !l.empty() ? l.front() : 0;
809  }
810 
811  ConstTagList Tag::findTagList( const std::string& expression ) const
812  {
813  ConstTagList l;
814  if( expression == "/" || expression == "//" )
815  return l;
816 
817  if( m_parent && expression.length() >= 2 && expression[0] == '/'
818  && expression[1] != '/' )
819  return m_parent->findTagList( expression );
820 
821  unsigned len = 0;
822  Tag* p = parse( expression, len );
823 // if( p )
824 // printf( "parsed tree: %s\n", p->xml().c_str() );
825  l = evaluateTagList( p );
826  delete p;
827  return l;
828  }
829 
830  ConstTagList Tag::evaluateTagList( Tag* token ) const
831  {
832  ConstTagList result;
833  if( !token )
834  return result;
835 
836 // printf( "evaluateTagList called in Tag %s and Token %s (type: %s)\n", name().c_str(),
837 // token->name().c_str(), token->findAttribute( TYPE ).c_str() );
838 
839  TokenType tokenType = static_cast<TokenType>( atoi( token->findAttribute( TYPE ).c_str() ) );
840  switch( tokenType )
841  {
842  case XTUnion:
843  add( result, evaluateUnion( token ) );
844  break;
845  case XTElement:
846  {
847 // printf( "in XTElement, token: %s\n", token->name().c_str() );
848  if( token->name() == name() || token->name() == "*" )
849  {
850 // printf( "found %s\n", name().c_str() );
851  const TagList& tokenChildren = token->children();
852  if( tokenChildren.size() )
853  {
854  bool predicatesSucceeded = true;
855  TagList::const_iterator cit = tokenChildren.begin();
856  for( ; cit != tokenChildren.end(); ++cit )
857  {
858  if( (*cit)->hasAttribute( "predicate", "true" ) )
859  {
860  predicatesSucceeded = evaluatePredicate( (*cit) );
861  if( !predicatesSucceeded )
862  return result;
863  }
864  }
865 
866  bool hasElementChildren = false;
867  cit = tokenChildren.begin();
868  for( ; cit != tokenChildren.end(); ++cit )
869  {
870  if( (*cit)->hasAttribute( "predicate", "true" ) ||
871  (*cit)->hasAttribute( "number", "true" ) )
872  continue;
873 
874  hasElementChildren = true;
875 
876 // printf( "checking %d children of token %s\n", tokenChildren.size(), token->name().c_str() );
877  if( m_children && !m_children->empty() )
878  {
879  TagList::const_iterator it = m_children->begin();
880  for( ; it != m_children->end(); ++it )
881  {
882  add( result, (*it)->evaluateTagList( (*cit) ) );
883  }
884  }
885  else if( atoi( (*cit)->findAttribute( TYPE ).c_str() ) == XTDoubleDot && m_parent )
886  {
887  (*cit)->addAttribute( TYPE, XTDot );
888  add( result, m_parent->evaluateTagList( (*cit) ) );
889  }
890  }
891 
892  if( !hasElementChildren )
893  result.push_back( this );
894  }
895  else
896  {
897 // printf( "adding %s to result set\n", name().c_str() );
898  result.push_back( this );
899  }
900  }
901 // else
902 // printf( "found %s != %s\n", token->name().c_str(), name().c_str() );
903 
904  break;
905  }
906  case XTDoubleSlash:
907  {
908 // printf( "in XTDoubleSlash\n" );
909  Tag* t = token->clone();
910 // printf( "original token: %s\ncloned token: %s\n", token->xml().c_str(), n->xml().c_str() );
911  t->addAttribute( TYPE, XTElement );
912  add( result, evaluateTagList( t ) );
913  const ConstTagList& res2 = allDescendants();
914  ConstTagList::const_iterator it = res2.begin();
915  for( ; it != res2.end(); ++it )
916  {
917  add( result, (*it)->evaluateTagList( t ) );
918  }
919  delete t;
920  break;
921  }
922  case XTDot:
923  {
924  const TagList& tokenChildren = token->children();
925  if( !tokenChildren.empty() )
926  {
927  add( result, evaluateTagList( tokenChildren.front() ) );
928  }
929  else
930  result.push_back( this );
931  break;
932  }
933  case XTDoubleDot:
934  {
935 // printf( "in XTDoubleDot\n" );
936  if( m_parent )
937  {
938  const TagList& tokenChildren = token->children();
939  if( tokenChildren.size() )
940  {
941  Tag* testtoken = tokenChildren.front();
942  if( testtoken->name() == "*" )
943  {
944  add( result, m_parent->evaluateTagList( testtoken ) );
945  }
946  else
947  {
948  Tag* t = token->clone();
949  t->addAttribute( TYPE, XTElement );
950  t->m_name = m_parent->m_name;
951  add( result, m_parent->evaluateTagList( t ) );
952  delete t;
953  }
954  }
955  else
956  {
957  result.push_back( m_parent );
958  }
959  }
960  }
961  case XTInteger:
962  {
963  const TagList& l = token->children();
964  if( !l.size() )
965  break;
966 
967  const ConstTagList& res = evaluateTagList( l.front() );
968 
969  int pos = atoi( token->name().c_str() );
970 // printf( "checking index %d\n", pos );
971  if( pos > 0 && pos <= static_cast<int>( res.size() ) )
972  {
973  ConstTagList::const_iterator it = res.begin();
974  while ( --pos )
975  {
976  ++it;
977  }
978  result.push_back( *it );
979  }
980  break;
981  }
982  default:
983  break;
984  }
985  return result;
986  }
987 
988  bool Tag::evaluateBoolean( Tag* token ) const
989  {
990  if( !token )
991  return false;
992 
993  bool result = false;
994  TokenType tokenType = static_cast<TokenType>( atoi( token->findAttribute( TYPE ).c_str() ) );
995  switch( tokenType )
996  {
997  case XTAttribute:
998  if( token->name() == "*" && m_attribs && m_attribs->size() )
999  result = true;
1000  else
1001  result = hasAttribute( token->name() );
1002  break;
1003  case XTOperatorEq:
1004  result = evaluateEquals( token );
1005  break;
1006  case XTOperatorLt:
1007  break;
1008  case XTOperatorLtEq:
1009  break;
1010  case XTOperatorGtEq:
1011  break;
1012  case XTOperatorGt:
1013  break;
1014  case XTUnion:
1015  case XTElement:
1016  {
1017  Tag* t = new Tag( "." );
1018  t->addAttribute( TYPE, XTDot );
1019  t->addChild( token );
1020  result = !evaluateTagList( t ).empty();
1021  t->removeChild( token );
1022  delete t;
1023  break;
1024  }
1025  default:
1026  break;
1027  }
1028 
1029  return result;
1030  }
1031 
1032  bool Tag::evaluateEquals( Tag* token ) const
1033  {
1034  if( !token || token->children().size() != 2 )
1035  return false;
1036 
1037  bool result = false;
1038  TagList::const_iterator it = token->children().begin();
1039  Tag* ch1 = (*it);
1040  Tag* ch2 = (*++it);
1041 
1042  TokenType tt1 = static_cast<TokenType>( atoi( ch1->findAttribute( TYPE ).c_str() ) );
1043  TokenType tt2 = static_cast<TokenType>( atoi( ch2->findAttribute( TYPE ).c_str() ) );
1044  switch( tt1 )
1045  {
1046  case XTAttribute:
1047  switch( tt2 )
1048  {
1049  case XTInteger:
1050  case XTLiteral:
1051  result = ( findAttribute( ch1->name() ) == ch2->name() );
1052  break;
1053  case XTAttribute:
1054  result = ( hasAttribute( ch1->name() ) && hasAttribute( ch2->name() ) &&
1055  findAttribute( ch1->name() ) == findAttribute( ch2->name() ) );
1056  break;
1057  default:
1058  break;
1059  }
1060  break;
1061  case XTInteger:
1062  case XTLiteral:
1063  switch( tt2 )
1064  {
1065  case XTAttribute:
1066  result = ( ch1->name() == findAttribute( ch2->name() ) );
1067  break;
1068  case XTLiteral:
1069  case XTInteger:
1070  result = ( ch1->name() == ch2->name() );
1071  break;
1072  default:
1073  break;
1074  }
1075  break;
1076  default:
1077  break;
1078  }
1079 
1080  return result;
1081  }
1082 
1083  ConstTagList Tag::allDescendants() const
1084  {
1085  ConstTagList result;
1086 
1087  if( !m_children )
1088  return result;
1089 
1090  TagList::const_iterator it = m_children->begin();
1091  for( ; it != m_children->end(); ++it )
1092  {
1093  result.push_back( (*it) );
1094  add( result, (*it)->allDescendants() );
1095  }
1096  return result;
1097  }
1098 
1099  ConstTagList Tag::evaluateUnion( Tag* token ) const
1100  {
1101  ConstTagList result;
1102  if( !token )
1103  return result;
1104 
1105  const TagList& l = token->children();
1106  TagList::const_iterator it = l.begin();
1107  for( ; it != l.end(); ++it )
1108  {
1109  add( result, evaluateTagList( (*it) ) );
1110  }
1111  return result;
1112  }
1113 
1114  void Tag::closePreviousToken( Tag** root, Tag** current, Tag::TokenType& type, std::string& tok ) const
1115  {
1116  if( !tok.empty() )
1117  {
1118  addToken( root, current, type, tok );
1119  type = XTElement;
1120  tok = EmptyString;
1121  }
1122  }
1123 
1124  Tag* Tag::parse( const std::string& expression, unsigned& len, Tag::TokenType border ) const
1125  {
1126  Tag* root = 0;
1127  Tag* current = root;
1128  std::string token;
1129 
1130 // XPathError error = XPNoError;
1131 // XPathState state = Init;
1132 // int expected = 0;
1133 // bool run = true;
1134 // bool ws = false;
1135 
1136  Tag::TokenType type = XTElement;
1137 
1138  char c;
1139  for( ; len < expression.length(); ++len )
1140  {
1141  c = expression[len];
1142  if( type == XTLiteralInside && c != '\'' )
1143  {
1144  token += c;
1145  continue;
1146  }
1147 
1148  switch( c )
1149  {
1150  case '/':
1151  closePreviousToken( &root, &current, type, token );
1152 
1153  if( len < expression.length()-1 && expression[len+1] == '/' )
1154  {
1155 // addToken( &root, &current, XTDoubleSlash, "//" );
1156  type = XTDoubleSlash;
1157  ++len;
1158  }
1159 // else
1160 // {
1161 // if( !current )
1162 // addToken( &root, &current, XTSlash, "/" );
1163 // }
1164  break;
1165  case ']':
1166  closePreviousToken( &root, &current, type, token );
1167  return root;
1168  case '[':
1169  {
1170  closePreviousToken( &root, &current, type, token );
1171  Tag* t = parse( expression, ++len, XTRightBracket );
1172  if( !addPredicate( &root, &current, t ) )
1173  delete t;
1174  break;
1175  }
1176  case '(':
1177  {
1178  closePreviousToken( &root, &current, type, token );
1179  Tag* t = parse( expression, ++len, XTRightParenthesis );
1180  if( current )
1181  {
1182 // printf( "added %s to %s\n", t->xml().c_str(), current->xml().c_str() );
1183  t->addAttribute( "argument", "true" );
1184  current->addChild( t );
1185  }
1186  else
1187  {
1188  root = t;
1189 // printf( "made %s new root\n", t->xml().c_str() );
1190  }
1191  break;
1192  }
1193  case ')':
1194  closePreviousToken( &root, &current, type, token );
1195  ++len;
1196  return root;
1197  case '\'':
1198  if( type == XTLiteralInside )
1199  if( expression[len - 2] == '\\' )
1200  token[token.length() - 2] = c;
1201  else
1202  type = XTLiteral;
1203  else
1204  type = XTLiteralInside;
1205  break;
1206  case '@':
1207  type = XTAttribute;
1208  break;
1209  case '.':
1210  token += c;
1211  if( token.size() == 1 )
1212  {
1213  if( len < expression.length()-1 && expression[len+1] == '.' )
1214  {
1215  type = XTDoubleDot;
1216  ++len;
1217  token += c;
1218  }
1219  else
1220  {
1221  type = XTDot;
1222  }
1223  }
1224  break;
1225  case '*':
1226 // if( !root || ( current && ( current->tokenType() == XTSlash
1227 // || current->tokenType() == XTDoubleSlash ) ) )
1228 // {
1229 // addToken( &root, &current, type, "*" );
1230 // break;
1231 // }
1232  addToken( &root, &current, type, "*" );
1233  type = XTElement;
1234  break;
1235  case '+':
1236  case '>':
1237  case '<':
1238  case '=':
1239  case '|':
1240  {
1241  closePreviousToken( &root, &current, type, token );
1242  std::string s( 1, c );
1243  Tag::TokenType ttype = getType( s );
1244  if( ttype <= border )
1245  return root;
1246  Tag* t = parse( expression, ++len, ttype );
1247  addOperator( &root, &current, t, ttype, s );
1248  if( border == XTRightBracket )
1249  return root;
1250  break;
1251  }
1252  default:
1253  token += c;
1254  }
1255  }
1256 
1257  if( !token.empty() )
1258  addToken( &root, &current, type, token );
1259 
1260 // if( error != XPNoError )
1261 // printf( "error: %d\n", error );
1262  return root;
1263  }
1264 
1265  void Tag::addToken( Tag **root, Tag **current, Tag::TokenType type,
1266  const std::string& token ) const
1267  {
1268  Tag* t = new Tag( token );
1269  if( t->isNumber() && !t->children().size() )
1270  type = XTInteger;
1271  t->addAttribute( TYPE, type );
1272 
1273  if( *root )
1274  {
1275 // printf( "new current %s, type: %d\n", token.c_str(), type );
1276  (*current)->addChild( t );
1277  *current = t;
1278  }
1279  else
1280  {
1281 // printf( "new root %s, type: %d\n", token.c_str(), type );
1282  *current = *root = t;
1283  }
1284  }
1285 
1286  void Tag::addOperator( Tag** root, Tag** current, Tag* arg,
1287  Tag::TokenType type, const std::string& token ) const
1288  {
1289  Tag* t = new Tag( token );
1290  t->addAttribute( TYPE, type );
1291 // printf( "new operator: %s (arg1: %s, arg2: %s)\n", t->name().c_str(), (*root)->xml().c_str(),
1292 // arg->xml().c_str() );
1293  t->addAttribute( "operator", "true" );
1294  t->addChild( *root );
1295  t->addChild( arg );
1296  *current = *root = t;
1297  }
1298 
1299  bool Tag::addPredicate( Tag **root, Tag **current, Tag* token ) const
1300  {
1301  if( !*root || !*current )
1302  return false;
1303 
1304  if( ( token->isNumber() && !token->children().size() ) || token->name() == "+" )
1305  {
1306 // printf( "found Index %s, full: %s\n", token->name().c_str(), token->xml().c_str() );
1307  if( !token->hasAttribute( "operator", "true" ) )
1308  {
1309  token->addAttribute( TYPE, XTInteger );
1310  }
1311  if( *root == *current )
1312  {
1313  *root = token;
1314 // printf( "made Index new root\n" );
1315  }
1316  else
1317  {
1318  (*root)->removeChild( *current );
1319  (*root)->addChild( token );
1320 // printf( "added Index somewhere between root and current\n" );
1321  }
1322  token->addChild( *current );
1323 // printf( "added Index %s, full: %s\n", token->name().c_str(), token->xml().c_str() );
1324  }
1325  else
1326  {
1327  token->addAttribute( "predicate", "true" );
1328  (*current)->addChild( token );
1329  }
1330 
1331  return true;
1332  }
1333 
1334  Tag::TokenType Tag::getType( const std::string& c )
1335  {
1336  if( c == "|" )
1337  return XTUnion;
1338  if( c == "<" )
1339  return XTOperatorLt;
1340  if( c == ">" )
1341  return XTOperatorGt;
1342  if( c == "*" )
1343  return XTOperatorMul;
1344  if( c == "+" )
1345  return XTOperatorPlus;
1346  if( c == "=" )
1347  return XTOperatorEq;
1348 
1349  return XTNone;
1350  }
1351 
1352  bool Tag::isWhitespace( const char c )
1353  {
1354  return ( c == 0x09 || c == 0x0a || c == 0x0d || c == 0x20 );
1355  }
1356 
1357  bool Tag::isNumber() const
1358  {
1359  if( m_name.empty() )
1360  return false;
1361 
1362  std::string::size_type l = m_name.length();
1363  std::string::size_type i = 0;
1364  while( i < l && isdigit( m_name[i] ) )
1365  ++i;
1366  return i == l;
1367  }
1368 
1369  void Tag::add( ConstTagList& one, const ConstTagList& two )
1370  {
1371  ConstTagList::const_iterator it = two.begin();
1372  for( ; it != two.end(); ++it )
1373  if( std::find( one.begin(), one.end(), (*it) ) == one.end() )
1374  one.push_back( (*it) );
1375  }
1376 
1377 }
Tag * clone() const
Definition: tag.cpp:670
ConstTagList findTagList(const std::string &expression) const
Definition: tag.cpp:811
bool checkValidXMLChars(const std::string &data)
Definition: util.cpp:141
bool setXmlns(const std::string &xmlns, const std::string &prefix=EmptyString)
Definition: tag.cpp:522
const std::string XMLNS
Definition: gloox.cpp:122
const std::string xmlns() const
Definition: tag.cpp:543
const std::string & value() const
Definition: tag.h:110
void clearList(std::list< T * > &L)
Definition: util.h:152
bool setPrefix(const std::string &prefix)
Definition: tag.cpp:565
bool hasChildWithCData(const std::string &name, const std::string &cdata) const
Definition: tag.cpp:647
void appendEscaped(std::string &target, const std::string &data)
Definition: util.cpp:95
std::list< Attribute * > AttributeList
Definition: tag.h:187
void setAttributes(const AttributeList &attributes)
Definition: tag.cpp:409
std::list< Tag * > TagList
Definition: tag.h:26
virtual ~Tag()
Definition: tag.cpp:229
bool setPrefix(const std::string &prefix)
Definition: tag.cpp:86
Tag * parent() const
Definition: tag.h:526
std::list< const Tag * > ConstTagList
Definition: tag.h:36
const std::string & name() const
Definition: tag.h:394
const AttributeList & attributes() const
Definition: tag.cpp:516
const std::string TYPE
Definition: gloox.cpp:123
bool hasChild(const std::string &name, const std::string &attr=EmptyString, const std::string &value=EmptyString) const
Definition: tag.cpp:615
const std::string & prefix() const
Definition: tag.h:249
Tag * findChild(const std::string &name) const
Definition: tag.cpp:624
const std::string & name() const
Definition: tag.h:104
bool setCData(const std::string &cdata)
Definition: tag.cpp:447
Tag(const std::string &name, const std::string &cdata=EmptyString)
Definition: tag.cpp:139
TagList findChildren(const std::string &name, const std::string &xmlns=EmptyString) const
Definition: tag.cpp:714
void addChild(Tag *child)
Definition: tag.cpp:424
Tag * findChildWithAttrib(const std::string &attr, const std::string &value=EmptyString) const
Definition: tag.cpp:659
The namespace for the gloox library.
Definition: adhoc.cpp:27
void removeAttribute(const std::string &attr, const std::string &value=EmptyString, const std::string &xmlns=EmptyString)
Definition: tag.cpp:779
Attribute(Tag *parent, const std::string &name, const std::string &value, const std::string &xmlns=EmptyString)
Definition: tag.cpp:26
bool addCData(const std::string &cdata)
Definition: tag.cpp:481
std::map< std::string, std::string > StringMap
Definition: gloox.h:1261
const Tag * findTag(const std::string &expression) const
Definition: tag.cpp:805
const std::string xmlns() const
Definition: tag.cpp:95
const std::string findCData(const std::string &expression) const
Definition: tag.cpp:799
bool setValue(const std::string &value)
Definition: tag.cpp:68
std::list< std::string * > StringPList
Definition: gloox.h:1256
bool addAttribute(Attribute *attr)
Definition: tag.cpp:354
bool operator==(const Tag &right) const
Definition: tag.cpp:249
const std::string xml() const
Definition: tag.cpp:302
bool setXmlns(const std::string &xmlns)
Definition: tag.cpp:77
const std::string & prefix() const
Definition: tag.cpp:106
const std::string & findAttribute(const std::string &name) const
Definition: tag.cpp:589
const TagList & children() const
Definition: tag.cpp:510
const std::string cdata() const
Definition: tag.cpp:497
bool hasAttribute(const std::string &name, const std::string &value=EmptyString) const
Definition: tag.cpp:602
void addChildCopy(const Tag *child)
Definition: tag.cpp:439
const std::string EmptyString
Definition: gloox.cpp:124
const std::string xml() const
Definition: tag.cpp:117
This is an abstraction of an XML element.
Definition: tag.h:46
void removeChild(const std::string &name, const std::string &xmlns=EmptyString)
Definition: tag.cpp:733