gloox  1.0.1
tag.cpp
1 /*
2  Copyright (c) 2005-2012 by Jakob Schroeter <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  }
471  }
472 
473  return addCData( cdata );
474  }
475 
476  bool Tag::addCData( const std::string& cdata )
477  {
478  if( cdata.empty() || !util::checkValidXMLChars( cdata ) )
479  return false;
480 
481  if( !m_cdata )
482  m_cdata = new StringPList();
483  if( !m_nodes )
484  m_nodes = new NodeList();
485 
486  std::string* str = new std::string( cdata );
487  m_cdata->push_back( str );
488  m_nodes->push_back( new Node( TypeString, str ) );
489  return true;
490  }
491 
492  const std::string Tag::cdata() const
493  {
494  if( !m_cdata )
495  return EmptyString;
496 
497  std::string str;
498  StringPList::const_iterator it = m_cdata->begin();
499  for( ; it != m_cdata->end(); ++it )
500  str += *(*it);
501 
502  return str;
503  }
504 
505  const TagList& Tag::children() const
506  {
507  static const TagList empty;
508  return m_children ? *m_children : empty;
509  }
510 
512  {
513  static const AttributeList empty;
514  return m_attribs ? *m_attribs : empty;
515  }
516 
517  bool Tag::setXmlns( const std::string& xmlns, const std::string& prefix )
518  {
519  if( !util::checkValidXMLChars( xmlns ) || !util::checkValidXMLChars( prefix ) )
520  return false;
521 
522  if( prefix.empty() )
523  {
524  m_xmlns = xmlns;
525  return addAttribute( XMLNS, m_xmlns );
526  }
527  else
528  {
529  if( !m_xmlnss )
530  m_xmlnss = new StringMap();
531 
532  (*m_xmlnss)[prefix] = xmlns;
533 
534  return addAttribute( XMLNS + ":" + prefix, xmlns );
535  }
536  }
537 
538  const std::string& Tag::xmlns() const
539  {
540  return xmlns( m_prefix );
541  }
542 
543  const std::string& Tag::xmlns( const std::string& prefix ) const
544  {
545  if( prefix.empty() )
546  {
547  return hasAttribute( XMLNS ) ? findAttribute( XMLNS ) : m_xmlns;
548  }
549 
550  if( m_xmlnss )
551  {
552  StringMap::const_iterator it = m_xmlnss->find( prefix );
553  if( it != m_xmlnss->end() )
554  return (*it).second;
555  }
556 
557  return m_parent ? m_parent->xmlns( prefix ) : EmptyString;
558  }
559 
560  bool Tag::setPrefix( const std::string& prefix )
561  {
562  if( !util::checkValidXMLChars( prefix ) )
563  return false;
564 
565  m_prefix = prefix;
566  return true;
567  }
568 
569  const std::string& Tag::prefix( const std::string& xmlns ) const
570  {
571  if( xmlns.empty() || !m_xmlnss )
572  return EmptyString;
573 
574  StringMap::const_iterator it = m_xmlnss->begin();
575  for( ; it != m_xmlnss->end(); ++it )
576  {
577  if( (*it).second == xmlns )
578  return (*it).first;
579  }
580 
581  return EmptyString;
582  }
583 
584  const std::string& Tag::findAttribute( const std::string& name ) const
585  {
586  if( !m_attribs )
587  return EmptyString;
588 
589  AttributeList::const_iterator it = m_attribs->begin();
590  for( ; it != m_attribs->end(); ++it )
591  if( (*it)->name() == name )
592  return (*it)->value();
593 
594  return EmptyString;
595  }
596 
597  bool Tag::hasAttribute( const std::string& name, const std::string& value ) const
598  {
599  if( name.empty() || !m_attribs )
600  return false;
601 
602  AttributeList::const_iterator it = m_attribs->begin();
603  for( ; it != m_attribs->end(); ++it )
604  if( (*it)->name() == name )
605  return value.empty() || (*it)->value() == value;
606 
607  return false;
608  }
609 
610  bool Tag::hasChild( const std::string& name, const std::string& attr,
611  const std::string& value ) const
612  {
613  if( attr.empty() )
614  return findChild( name ) ? true : false;
615  else
616  return findChild( name, attr, value ) ? true : false;
617  }
618 
619  Tag* Tag::findChild( const std::string& name ) const
620  {
621  if( !m_children )
622  return 0;
623 
624  TagList::const_iterator it = m_children->begin();
625  while( it != m_children->end() && (*it)->name() != name )
626  ++it;
627  return it != m_children->end() ? (*it) : 0;
628  }
629 
630  Tag* Tag::findChild( const std::string& name, const std::string& attr,
631  const std::string& value ) const
632  {
633  if( !m_children || name.empty() )
634  return 0;
635 
636  TagList::const_iterator it = m_children->begin();
637  while( it != m_children->end() && ( (*it)->name() != name || !(*it)->hasAttribute( attr, value ) ) )
638  ++it;
639  return it != m_children->end() ? (*it) : 0;
640  }
641 
642  bool Tag::hasChildWithCData( const std::string& name, const std::string& cdata ) const
643  {
644  if( !m_children || name.empty() || cdata.empty() )
645  return 0;
646 
647  TagList::const_iterator it = m_children->begin();
648  while( it != m_children->end() && ( (*it)->name() != name
649  || ( !cdata.empty() && (*it)->cdata() != cdata ) ) )
650  ++it;
651  return it != m_children->end();
652  }
653 
654  Tag* Tag::findChildWithAttrib( const std::string& attr, const std::string& value ) const
655  {
656  if( !m_children || attr.empty() )
657  return 0;
658 
659  TagList::const_iterator it = m_children->begin();
660  while( it != m_children->end() && !(*it)->hasAttribute( attr, value ) )
661  ++it;
662  return it != m_children->end() ? (*it) : 0;
663  }
664 
665  Tag* Tag::clone() const
666  {
667  Tag* t = new Tag( m_name );
668  t->m_xmlns = m_xmlns;
669  t->m_prefix = m_prefix;
670 
671  if( m_attribs )
672  {
673  t->m_attribs = new AttributeList();
674  Tag::AttributeList::const_iterator at = m_attribs->begin();
675  Attribute* attr;
676  for( ; at != m_attribs->end(); ++at )
677  {
678  attr = new Attribute( *(*at) );
679  attr->m_parent = t;
680  t->m_attribs->push_back( attr );
681  }
682  }
683 
684  if( m_xmlnss )
685  {
686  t->m_xmlnss = new StringMap( *m_xmlnss );
687  }
688 
689  if( m_nodes )
690  {
691  Tag::NodeList::const_iterator nt = m_nodes->begin();
692  for( ; nt != m_nodes->end(); ++nt )
693  {
694  switch( (*nt)->type )
695  {
696  case TypeTag:
697  t->addChild( (*nt)->tag->clone() );
698  break;
699  case TypeString:
700  t->addCData( *((*nt)->str) );
701  break;
702  }
703  }
704  }
705 
706  return t;
707  }
708 
709  TagList Tag::findChildren( const std::string& name,
710  const std::string& xmlns ) const
711  {
712  return m_children ? findChildren( *m_children, name, xmlns ) : TagList();
713  }
714 
715  TagList Tag::findChildren( const TagList& list, const std::string& name,
716  const std::string& xmlns ) const
717  {
718  TagList ret;
719  TagList::const_iterator it = list.begin();
720  for( ; it != list.end(); ++it )
721  {
722  if( (*it)->name() == name && ( xmlns.empty() || (*it)->xmlns() == xmlns ) )
723  ret.push_back( (*it) );
724  }
725  return ret;
726  }
727 
728  void Tag::removeChild( const std::string& name, const std::string& xmlns )
729  {
730  if( name.empty() || !m_children || !m_nodes )
731  return;
732 
733  TagList l = findChildren( name, xmlns );
734  TagList::iterator it = l.begin();
735  TagList::iterator it2;
736  while( it != l.end() )
737  {
738  it2 = it++;
739  NodeList::iterator itn = m_nodes->begin();
740  for( ; itn != m_nodes->end(); ++itn )
741  {
742  if( (*itn)->type == TypeTag && (*itn)->tag == (*it2) )
743  {
744  delete (*itn);
745  m_nodes->erase( itn );
746  break;
747  }
748  }
749  m_children->remove( (*it2) );
750  delete (*it2);
751  }
752  }
753 
754  void Tag::removeChild( Tag* tag )
755  {
756  if( m_children )
757  m_children->remove( tag );
758 
759  if( !m_nodes )
760  return;
761 
762  NodeList::iterator it = m_nodes->begin();
763  for( ; it != m_nodes->end(); ++it )
764  {
765  if( (*it)->type == TypeTag && (*it)->tag == tag )
766  {
767  delete (*it);
768  m_nodes->erase( it );
769  return;
770  }
771  }
772  }
773 
774  void Tag::removeAttribute( const std::string& attr, const std::string& value,
775  const std::string& xmlns )
776  {
777  if( attr.empty() || !m_attribs )
778  return;
779 
780  AttributeList::iterator it = m_attribs->begin();
781  AttributeList::iterator it2;
782  while( it != m_attribs->end() )
783  {
784  it2 = it++;
785  if( (*it2)->name() == attr && ( value.empty() || (*it2)->value() == value )
786  && ( xmlns.empty() || (*it2)->xmlns() == xmlns ) )
787  {
788  delete (*it2);
789  m_attribs->erase( it2 );
790  }
791  }
792  }
793 
794  const std::string Tag::findCData( const std::string& expression ) const
795  {
796  const ConstTagList& l = findTagList( expression );
797  return !l.empty() ? l.front()->cdata() : EmptyString;
798  }
799 
800  const Tag* Tag::findTag( const std::string& expression ) const
801  {
802  const ConstTagList& l = findTagList( expression );
803  return !l.empty() ? l.front() : 0;
804  }
805 
806  ConstTagList Tag::findTagList( const std::string& expression ) const
807  {
808  ConstTagList l;
809  if( expression == "/" || expression == "//" )
810  return l;
811 
812  if( m_parent && expression.length() >= 2 && expression[0] == '/'
813  && expression[1] != '/' )
814  return m_parent->findTagList( expression );
815 
816  unsigned len = 0;
817  Tag* p = parse( expression, len );
818 // if( p )
819 // printf( "parsed tree: %s\n", p->xml().c_str() );
820  l = evaluateTagList( p );
821  delete p;
822  return l;
823  }
824 
825  ConstTagList Tag::evaluateTagList( Tag* token ) const
826  {
827  ConstTagList result;
828  if( !token )
829  return result;
830 
831 // printf( "evaluateTagList called in Tag %s and Token %s (type: %s)\n", name().c_str(),
832 // token->name().c_str(), token->findAttribute( TYPE ).c_str() );
833 
834  TokenType tokenType = (TokenType)atoi( token->findAttribute( TYPE ).c_str() );
835  switch( tokenType )
836  {
837  case XTUnion:
838  add( result, evaluateUnion( token ) );
839  break;
840  case XTElement:
841  {
842 // printf( "in XTElement, token: %s\n", token->name().c_str() );
843  if( token->name() == name() || token->name() == "*" )
844  {
845 // printf( "found %s\n", name().c_str() );
846  const TagList& tokenChildren = token->children();
847  if( tokenChildren.size() )
848  {
849  bool predicatesSucceeded = true;
850  TagList::const_iterator cit = tokenChildren.begin();
851  for( ; cit != tokenChildren.end(); ++cit )
852  {
853  if( (*cit)->hasAttribute( "predicate", "true" ) )
854  {
855  predicatesSucceeded = evaluatePredicate( (*cit) );
856  if( !predicatesSucceeded )
857  return result;
858  }
859  }
860 
861  bool hasElementChildren = false;
862  cit = tokenChildren.begin();
863  for( ; cit != tokenChildren.end(); ++cit )
864  {
865  if( (*cit)->hasAttribute( "predicate", "true" ) ||
866  (*cit)->hasAttribute( "number", "true" ) )
867  continue;
868 
869  hasElementChildren = true;
870 
871 // printf( "checking %d children of token %s\n", tokenChildren.size(), token->name().c_str() );
872  if( m_children && !m_children->empty() )
873  {
874  TagList::const_iterator it = m_children->begin();
875  for( ; it != m_children->end(); ++it )
876  {
877  add( result, (*it)->evaluateTagList( (*cit) ) );
878  }
879  }
880  else if( atoi( (*cit)->findAttribute( TYPE ).c_str() ) == XTDoubleDot && m_parent )
881  {
882  (*cit)->addAttribute( TYPE, XTDot );
883  add( result, m_parent->evaluateTagList( (*cit) ) );
884  }
885  }
886 
887  if( !hasElementChildren )
888  result.push_back( this );
889  }
890  else
891  {
892 // printf( "adding %s to result set\n", name().c_str() );
893  result.push_back( this );
894  }
895  }
896 // else
897 // printf( "found %s != %s\n", token->name().c_str(), name().c_str() );
898 
899  break;
900  }
901  case XTDoubleSlash:
902  {
903 // printf( "in XTDoubleSlash\n" );
904  Tag* t = token->clone();
905 // printf( "original token: %s\ncloned token: %s\n", token->xml().c_str(), n->xml().c_str() );
906  t->addAttribute( TYPE, XTElement );
907  add( result, evaluateTagList( t ) );
908  const ConstTagList& res2 = allDescendants();
909  ConstTagList::const_iterator it = res2.begin();
910  for( ; it != res2.end(); ++it )
911  {
912  add( result, (*it)->evaluateTagList( t ) );
913  }
914  delete t;
915  break;
916  }
917  case XTDot:
918  {
919  const TagList& tokenChildren = token->children();
920  if( !tokenChildren.empty() )
921  {
922  add( result, evaluateTagList( tokenChildren.front() ) );
923  }
924  else
925  result.push_back( this );
926  break;
927  }
928  case XTDoubleDot:
929  {
930 // printf( "in XTDoubleDot\n" );
931  if( m_parent )
932  {
933  const TagList& tokenChildren = token->children();
934  if( tokenChildren.size() )
935  {
936  Tag* testtoken = tokenChildren.front();
937  if( testtoken->name() == "*" )
938  {
939  add( result, m_parent->evaluateTagList( testtoken ) );
940  }
941  else
942  {
943  Tag* t = token->clone();
944  t->addAttribute( TYPE, XTElement );
945  t->m_name = m_parent->m_name;
946  add( result, m_parent->evaluateTagList( t ) );
947  delete t;
948  }
949  }
950  else
951  {
952  result.push_back( m_parent );
953  }
954  }
955  }
956  case XTInteger:
957  {
958  const TagList& l = token->children();
959  if( !l.size() )
960  break;
961 
962  const ConstTagList& res = evaluateTagList( l.front() );
963 
964  int pos = atoi( token->name().c_str() );
965 // printf( "checking index %d\n", pos );
966  if( pos > 0 && pos <= (int)res.size() )
967  {
968  ConstTagList::const_iterator it = res.begin();
969  while ( --pos )
970  {
971  ++it;
972  }
973  result.push_back( *it );
974  }
975  break;
976  }
977  default:
978  break;
979  }
980  return result;
981  }
982 
983  bool Tag::evaluateBoolean( Tag* token ) const
984  {
985  if( !token )
986  return false;
987 
988  bool result = false;
989  TokenType tokenType = (TokenType)atoi( token->findAttribute( TYPE ).c_str() );
990  switch( tokenType )
991  {
992  case XTAttribute:
993  if( token->name() == "*" && m_attribs && m_attribs->size() )
994  result = true;
995  else
996  result = hasAttribute( token->name() );
997  break;
998  case XTOperatorEq:
999  result = evaluateEquals( token );
1000  break;
1001  case XTOperatorLt:
1002  break;
1003  case XTOperatorLtEq:
1004  break;
1005  case XTOperatorGtEq:
1006  break;
1007  case XTOperatorGt:
1008  break;
1009  case XTUnion:
1010  case XTElement:
1011  {
1012  Tag* t = new Tag( "." );
1013  t->addAttribute( TYPE, XTDot );
1014  t->addChild( token );
1015  result = !evaluateTagList( t ).empty();
1016  t->removeChild( token );
1017  delete t;
1018  break;
1019  }
1020  default:
1021  break;
1022  }
1023 
1024  return result;
1025  }
1026 
1027  bool Tag::evaluateEquals( Tag* token ) const
1028  {
1029  if( !token || token->children().size() != 2 )
1030  return false;
1031 
1032  bool result = false;
1033  TagList::const_iterator it = token->children().begin();
1034  Tag* ch1 = (*it);
1035  Tag* ch2 = (*++it);
1036 
1037  TokenType tt1 = (TokenType)atoi( ch1->findAttribute( TYPE ).c_str() );
1038  TokenType tt2 = (TokenType)atoi( ch2->findAttribute( TYPE ).c_str() );
1039  switch( tt1 )
1040  {
1041  case XTAttribute:
1042  switch( tt2 )
1043  {
1044  case XTInteger:
1045  case XTLiteral:
1046  result = ( findAttribute( ch1->name() ) == ch2->name() );
1047  break;
1048  case XTAttribute:
1049  result = ( hasAttribute( ch1->name() ) && hasAttribute( ch2->name() ) &&
1050  findAttribute( ch1->name() ) == findAttribute( ch2->name() ) );
1051  break;
1052  default:
1053  break;
1054  }
1055  break;
1056  case XTInteger:
1057  case XTLiteral:
1058  switch( tt2 )
1059  {
1060  case XTAttribute:
1061  result = ( ch1->name() == findAttribute( ch2->name() ) );
1062  break;
1063  case XTLiteral:
1064  case XTInteger:
1065  result = ( ch1->name() == ch2->name() );
1066  break;
1067  default:
1068  break;
1069  }
1070  break;
1071  default:
1072  break;
1073  }
1074 
1075  return result;
1076  }
1077 
1078  ConstTagList Tag::allDescendants() const
1079  {
1080  ConstTagList result;
1081 
1082  if( !m_children )
1083  return result;
1084 
1085  TagList::const_iterator it = m_children->begin();
1086  for( ; it != m_children->end(); ++it )
1087  {
1088  result.push_back( (*it) );
1089  add( result, (*it)->allDescendants() );
1090  }
1091  return result;
1092  }
1093 
1094  ConstTagList Tag::evaluateUnion( Tag* token ) const
1095  {
1096  ConstTagList result;
1097  if( !token )
1098  return result;
1099 
1100  const TagList& l = token->children();
1101  TagList::const_iterator it = l.begin();
1102  for( ; it != l.end(); ++it )
1103  {
1104  add( result, evaluateTagList( (*it) ) );
1105  }
1106  return result;
1107  }
1108 
1109  void Tag::closePreviousToken( Tag** root, Tag** current, Tag::TokenType& type, std::string& tok ) const
1110  {
1111  if( !tok.empty() )
1112  {
1113  addToken( root, current, type, tok );
1114  type = XTElement;
1115  tok = EmptyString;
1116  }
1117  }
1118 
1119  Tag* Tag::parse( const std::string& expression, unsigned& len, Tag::TokenType border ) const
1120  {
1121  Tag* root = 0;
1122  Tag* current = root;
1123  std::string token;
1124 
1125 // XPathError error = XPNoError;
1126 // XPathState state = Init;
1127 // int expected = 0;
1128 // bool run = true;
1129 // bool ws = false;
1130 
1131  Tag::TokenType type = XTElement;
1132 
1133  char c;
1134  for( ; len < expression.length(); ++len )
1135  {
1136  c = expression[len];
1137  if( type == XTLiteralInside && c != '\'' )
1138  {
1139  token += c;
1140  continue;
1141  }
1142 
1143  switch( c )
1144  {
1145  case '/':
1146  closePreviousToken( &root, &current, type, token );
1147 
1148  if( len < expression.length()-1 && expression[len+1] == '/' )
1149  {
1150 // addToken( &root, &current, XTDoubleSlash, "//" );
1151  type = XTDoubleSlash;
1152  ++len;
1153  }
1154 // else
1155 // {
1156 // if( !current )
1157 // addToken( &root, &current, XTSlash, "/" );
1158 // }
1159  break;
1160  case ']':
1161  closePreviousToken( &root, &current, type, token );
1162  return root;
1163  case '[':
1164  {
1165  closePreviousToken( &root, &current, type, token );
1166  Tag* t = parse( expression, ++len, XTRightBracket );
1167  if( !addPredicate( &root, &current, t ) )
1168  delete t;
1169  break;
1170  }
1171  case '(':
1172  {
1173  closePreviousToken( &root, &current, type, token );
1174  Tag* t = parse( expression, ++len, XTRightParenthesis );
1175  if( current )
1176  {
1177 // printf( "added %s to %s\n", t->xml().c_str(), current->xml().c_str() );
1178  t->addAttribute( "argument", "true" );
1179  current->addChild( t );
1180  }
1181  else
1182  {
1183  root = t;
1184 // printf( "made %s new root\n", t->xml().c_str() );
1185  }
1186  break;
1187  }
1188  case ')':
1189  closePreviousToken( &root, &current, type, token );
1190  ++len;
1191  return root;
1192  case '\'':
1193  if( type == XTLiteralInside )
1194  if( expression[len - 2] == '\\' )
1195  token[token.length() - 2] = c;
1196  else
1197  type = XTLiteral;
1198  else
1199  type = XTLiteralInside;
1200  break;
1201  case '@':
1202  type = XTAttribute;
1203  break;
1204  case '.':
1205  token += c;
1206  if( token.size() == 1 )
1207  {
1208  if( len < expression.length()-1 && expression[len+1] == '.' )
1209  {
1210  type = XTDoubleDot;
1211  ++len;
1212  token += c;
1213  }
1214  else
1215  {
1216  type = XTDot;
1217  }
1218  }
1219  break;
1220  case '*':
1221 // if( !root || ( current && ( current->tokenType() == XTSlash
1222 // || current->tokenType() == XTDoubleSlash ) ) )
1223 // {
1224 // addToken( &root, &current, type, "*" );
1225 // break;
1226 // }
1227  addToken( &root, &current, type, "*" );
1228  type = XTElement;
1229  break;
1230  case '+':
1231  case '>':
1232  case '<':
1233  case '=':
1234  case '|':
1235  {
1236  closePreviousToken( &root, &current, type, token );
1237  std::string s( 1, c );
1238  Tag::TokenType ttype = getType( s );
1239  if( ttype <= border )
1240  return root;
1241  Tag* t = parse( expression, ++len, ttype );
1242  addOperator( &root, &current, t, ttype, s );
1243  if( border == XTRightBracket )
1244  return root;
1245  break;
1246  }
1247  default:
1248  token += c;
1249  }
1250  }
1251 
1252  if( !token.empty() )
1253  addToken( &root, &current, type, token );
1254 
1255 // if( error != XPNoError )
1256 // printf( "error: %d\n", error );
1257  return root;
1258  }
1259 
1260  void Tag::addToken( Tag **root, Tag **current, Tag::TokenType type,
1261  const std::string& token ) const
1262  {
1263  Tag* t = new Tag( token );
1264  if( t->isNumber() && !t->children().size() )
1265  type = XTInteger;
1266  t->addAttribute( TYPE, type );
1267 
1268  if( *root )
1269  {
1270 // printf( "new current %s, type: %d\n", token.c_str(), type );
1271  (*current)->addChild( t );
1272  *current = t;
1273  }
1274  else
1275  {
1276 // printf( "new root %s, type: %d\n", token.c_str(), type );
1277  *current = *root = t;
1278  }
1279  }
1280 
1281  void Tag::addOperator( Tag** root, Tag** current, Tag* arg,
1282  Tag::TokenType type, const std::string& token ) const
1283  {
1284  Tag* t = new Tag( token );
1285  t->addAttribute( TYPE, type );
1286 // printf( "new operator: %s (arg1: %s, arg2: %s)\n", t->name().c_str(), (*root)->xml().c_str(),
1287 // arg->xml().c_str() );
1288  t->addAttribute( "operator", "true" );
1289  t->addChild( *root );
1290  t->addChild( arg );
1291  *current = *root = t;
1292  }
1293 
1294  bool Tag::addPredicate( Tag **root, Tag **current, Tag* token ) const
1295  {
1296  if( !*root || !*current )
1297  return false;
1298 
1299  if( ( token->isNumber() && !token->children().size() ) || token->name() == "+" )
1300  {
1301 // printf( "found Index %s, full: %s\n", token->name().c_str(), token->xml().c_str() );
1302  if( !token->hasAttribute( "operator", "true" ) )
1303  {
1304  token->addAttribute( TYPE, XTInteger );
1305  }
1306  if( *root == *current )
1307  {
1308  *root = token;
1309 // printf( "made Index new root\n" );
1310  }
1311  else
1312  {
1313  (*root)->removeChild( *current );
1314  (*root)->addChild( token );
1315 // printf( "added Index somewhere between root and current\n" );
1316  }
1317  token->addChild( *current );
1318 // printf( "added Index %s, full: %s\n", token->name().c_str(), token->xml().c_str() );
1319  }
1320  else
1321  {
1322  token->addAttribute( "predicate", "true" );
1323  (*current)->addChild( token );
1324  }
1325 
1326  return true;
1327  }
1328 
1329  Tag::TokenType Tag::getType( const std::string& c )
1330  {
1331  if( c == "|" )
1332  return XTUnion;
1333  if( c == "<" )
1334  return XTOperatorLt;
1335  if( c == ">" )
1336  return XTOperatorGt;
1337  if( c == "*" )
1338  return XTOperatorMul;
1339  if( c == "+" )
1340  return XTOperatorPlus;
1341  if( c == "=" )
1342  return XTOperatorEq;
1343 
1344  return XTNone;
1345  }
1346 
1347  bool Tag::isWhitespace( const char c )
1348  {
1349  return ( c == 0x09 || c == 0x0a || c == 0x0d || c == 0x20 );
1350  }
1351 
1352  bool Tag::isNumber() const
1353  {
1354  if( m_name.empty() )
1355  return false;
1356 
1357  std::string::size_type l = m_name.length();
1358  std::string::size_type i = 0;
1359  while( i < l && isdigit( m_name[i] ) )
1360  ++i;
1361  return i == l;
1362  }
1363 
1364  void Tag::add( ConstTagList& one, const ConstTagList& two )
1365  {
1366  ConstTagList::const_iterator it = two.begin();
1367  for( ; it != two.end(); ++it )
1368  if( std::find( one.begin(), one.end(), (*it) ) == one.end() )
1369  one.push_back( (*it) );
1370  }
1371 
1372 }