gloox 1.0.24
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
22namespace 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 {
53 m_xmlns = xmlns;
54 else
55 return;
56
57 if( util::checkValidXMLChars( value ) )
58 m_value = value;
59 else
60 return;
61
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 {
80 return false;
81
82 m_xmlns = xmlns;
83 return true;
84 }
85
86 bool Tag::Attribute::setPrefix( const std::string& prefix )
87 {
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 && !m_prefix.empty() )
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
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
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
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
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
409 void Tag::setAttributes( const AttributeList& attributes )
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 {
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 {
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
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
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
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}
const std::string & name() const
Definition: tag.h:104
bool setPrefix(const std::string &prefix)
Definition: tag.cpp:86
const std::string & value() const
Definition: tag.h:110
const std::string xmlns() const
Definition: tag.cpp:95
bool setValue(const std::string &value)
Definition: tag.cpp:68
const std::string xml() const
Definition: tag.cpp:117
const std::string & prefix() const
Definition: tag.cpp:106
bool setXmlns(const std::string &xmlns)
Definition: tag.cpp:77
Attribute(Tag *parent, const std::string &name, const std::string &value, const std::string &xmlns=EmptyString)
Definition: tag.cpp:26
This is an abstraction of an XML element.
Definition: tag.h:47
Tag * findChildWithAttrib(const std::string &attr, const std::string &value=EmptyString) const
Definition: tag.cpp:659
Tag * findChild(const std::string &name) const
Definition: tag.cpp:624
const std::string & name() const
Definition: tag.h:394
bool hasChildWithCData(const std::string &name, const std::string &cdata) const
Definition: tag.cpp:647
bool setPrefix(const std::string &prefix)
Definition: tag.cpp:565
virtual ~Tag()
Definition: tag.cpp:229
bool setCData(const std::string &cdata)
Definition: tag.cpp:447
const Tag * findTag(const std::string &expression) const
Definition: tag.cpp:805
void removeChild(const std::string &name, const std::string &xmlns=EmptyString)
Definition: tag.cpp:733
const std::string xmlns() const
Definition: tag.cpp:543
void removeAttribute(const std::string &attr, const std::string &value=EmptyString, const std::string &xmlns=EmptyString)
Definition: tag.cpp:779
void addChildCopy(const Tag *child)
Definition: tag.cpp:439
bool addAttribute(Attribute *attr)
Definition: tag.cpp:354
bool hasChild(const std::string &name, const std::string &attr=EmptyString, const std::string &value=EmptyString) const
Definition: tag.cpp:615
std::list< Attribute * > AttributeList
Definition: tag.h:187
ConstTagList findTagList(const std::string &expression) const
Definition: tag.cpp:811
void addChild(Tag *child)
Definition: tag.cpp:424
const std::string findCData(const std::string &expression) const
Definition: tag.cpp:799
bool hasAttribute(const std::string &name, const std::string &value=EmptyString) const
Definition: tag.cpp:602
bool operator==(const Tag &right) const
Definition: tag.cpp:249
const AttributeList & attributes() const
Definition: tag.cpp:516
const std::string cdata() const
Definition: tag.cpp:497
const std::string & findAttribute(const std::string &name) const
Definition: tag.cpp:589
TagList findChildren(const std::string &name, const std::string &xmlns=EmptyString) const
Definition: tag.cpp:714
bool addCData(const std::string &cdata)
Definition: tag.cpp:481
Tag(const std::string &name, const std::string &cdata=EmptyString)
Definition: tag.cpp:139
Tag * clone() const
Definition: tag.cpp:670
const std::string xml() const
Definition: tag.cpp:302
const TagList & children() const
Definition: tag.cpp:510
void setAttributes(const AttributeList &attributes)
Definition: tag.cpp:409
bool setXmlns(const std::string &xmlns, const std::string &prefix=EmptyString)
Definition: tag.cpp:522
const std::string & prefix() const
Definition: tag.h:249
void clearList(std::list< T * > &L)
Definition: util.h:152
void appendEscaped(std::string &target, const std::string &data)
Definition: util.cpp:95
bool checkValidXMLChars(const std::string &data)
Definition: util.cpp:141
The namespace for the gloox library.
Definition: adhoc.cpp:28
std::list< Tag * > TagList
Definition: tag.h:31
std::list< std::string * > StringPList
Definition: gloox.h:1256
const std::string EmptyString
Definition: gloox.cpp:124
const std::string XMLNS
Definition: gloox.cpp:122
const std::string TYPE
Definition: gloox.cpp:123
std::list< const Tag * > ConstTagList
Definition: tag.h:36
std::map< std::string, std::string > StringMap
Definition: gloox.h:1261