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