gloox 1.0

tag.cpp

00001 /*
00002   Copyright (c) 2005-2009 by Jakob Schroeter <js@camaya.net>
00003   This file is part of the gloox library. http://camaya.net/gloox
00004 
00005   This software is distributed under a license. The full license
00006   agreement can be found in the file LICENSE in this distribution.
00007   This software may not be copied, modified, sold or distributed
00008   other than expressed in the named license agreement.
00009 
00010   This software is distributed without any warranty.
00011 */
00012 
00013 
00014 #include "tag.h"
00015 #include "util.h"
00016 
00017 #include <stdlib.h>
00018 
00019 #include <algorithm>
00020 
00021 namespace gloox
00022 {
00023 
00024   // ---- Tag::Attribute ----
00025   Tag::Attribute::Attribute( Tag* parent, const std::string& name, const std::string& value,
00026                              const std::string& xmlns )
00027     : m_parent( parent )
00028   {
00029     if( m_parent )
00030       m_parent->addAttribute( this );
00031 
00032     init( name, value, xmlns );
00033   }
00034 
00035   Tag::Attribute::Attribute( const std::string& name, const std::string& value,
00036                              const std::string& xmlns )
00037     : m_parent( 0 )
00038   {
00039     init( name, value, xmlns );
00040   }
00041 
00042   Tag::Attribute::Attribute( const Attribute& attr )
00043     : m_parent( attr.m_parent ), m_name( attr.m_name ), m_value( attr.m_value ),
00044       m_xmlns( attr.m_xmlns ), m_prefix( attr.m_prefix )
00045   {
00046   }
00047 
00048   void Tag::Attribute::init( const std::string& name, const std::string& value,
00049                              const std::string& xmlns )
00050   {
00051     if( util::checkValidXMLChars( xmlns ) )
00052       m_xmlns = xmlns;
00053     else
00054       return;
00055 
00056     if( util::checkValidXMLChars( value ) )
00057       m_value = value;
00058     else
00059       return;
00060 
00061     if( util::checkValidXMLChars( name ) )
00062       m_name = name;
00063     else
00064       return;
00065   }
00066 
00067   bool Tag::Attribute::setValue( const std::string& value )
00068   {
00069     if( !util::checkValidXMLChars( value ) )
00070       return false;
00071 
00072     m_value = value;
00073     return true;
00074   }
00075 
00076   bool Tag::Attribute::setXmlns( const std::string& xmlns )
00077   {
00078     if( !util::checkValidXMLChars( xmlns ) )
00079       return false;
00080 
00081     m_xmlns = xmlns;
00082     return true;
00083   }
00084 
00085   bool Tag::Attribute::setPrefix( const std::string& prefix )
00086   {
00087     if( !util::checkValidXMLChars( prefix ) )
00088       return false;
00089 
00090     m_prefix = prefix;
00091     return true;
00092   }
00093 
00094   const std::string& Tag::Attribute::xmlns() const
00095   {
00096     if( !m_xmlns.empty() )
00097       return m_xmlns;
00098 
00099     if( m_parent )
00100       return m_parent->xmlns( m_prefix );
00101 
00102     return EmptyString;
00103   }
00104 
00105   const std::string& Tag::Attribute::prefix() const
00106   {
00107     if( !m_prefix.empty() )
00108       return m_prefix;
00109 
00110     if( m_parent )
00111       return m_parent->prefix( m_xmlns );
00112 
00113     return EmptyString;
00114   }
00115 
00116   const std::string Tag::Attribute::xml() const
00117   {
00118     if( m_name.empty() )
00119       return EmptyString;
00120 
00121     std::string xml;
00122     xml += ' ';
00123     if( !m_prefix.empty() )
00124     {
00125       xml += m_prefix;
00126       xml += ':';
00127     }
00128     xml += m_name;
00129     xml += "='";
00130     xml += util::escape( m_value );
00131     xml += '\'';
00132 
00133     return xml;
00134   }
00135   // ---- ~Tag::Attribute ----
00136 
00137   // ---- Tag ----
00138   Tag::Tag( const std::string& name, const std::string& cdata )
00139     : m_parent( 0 ), m_children( 0 ), m_cdata( 0 ),
00140       m_attribs( 0 ), m_nodes( 0 ),
00141       m_xmlnss( 0 )
00142   {
00143     addCData( cdata ); // implicitly UTF-8 checked
00144 
00145     if( util::checkValidXMLChars( name ) )
00146       m_name = name;
00147   }
00148 
00149   Tag::Tag( Tag* parent, const std::string& name, const std::string& cdata )
00150     : m_parent( parent ), m_children( 0 ), m_cdata( 0 ),
00151       m_attribs( 0 ), m_nodes( 0 ),
00152       m_xmlnss( 0 )
00153   {
00154     if( m_parent )
00155       m_parent->addChild( this );
00156 
00157     addCData( cdata ); // implicitly UTF-8 checked
00158 
00159     if( util::checkValidXMLChars( name ) )
00160       m_name = name;
00161   }
00162 
00163   Tag::Tag( const std::string& name,
00164             const std::string& attrib,
00165             const std::string& value )
00166     : m_parent( 0 ), m_children( 0 ), m_cdata( 0 ),
00167       m_attribs( 0 ), m_nodes( 0 ),
00168       m_name( name ), m_xmlnss( 0 )
00169   {
00170     addAttribute( attrib, value ); // implicitly UTF-8 checked
00171 
00172     if( util::checkValidXMLChars( name ) )
00173       m_name = name;
00174   }
00175 
00176   Tag::Tag( Tag* parent, const std::string& name,
00177                          const std::string& attrib,
00178                          const std::string& value )
00179     : m_parent( parent ), m_children( 0 ), m_cdata( 0 ),
00180       m_attribs( 0 ), m_nodes( 0 ),
00181       m_name( name ), m_xmlnss( 0 )
00182   {
00183     if( m_parent )
00184       m_parent->addChild( this );
00185 
00186     addAttribute( attrib, value ); // implicitly UTF-8 checked
00187 
00188     if( util::checkValidXMLChars( name ) )
00189       m_name = name;
00190   }
00191 
00192   Tag::Tag( Tag* tag )
00193     : m_parent( 0 ), m_children( 0 ), m_cdata( 0 ), m_attribs( 0 ),
00194       m_nodes( 0 ), m_xmlnss( 0 )
00195   {
00196     if( !tag )
00197       return;
00198 
00199     m_children = tag->m_children;
00200     m_cdata = tag->m_cdata;
00201     m_attribs = tag->m_attribs;
00202     m_nodes = tag->m_nodes;
00203     m_name = tag->m_name;
00204     m_xmlns = tag->m_xmlns;
00205     m_xmlnss = tag->m_xmlnss;
00206 
00207     tag->m_nodes = 0;
00208     tag->m_cdata = 0;
00209     tag->m_attribs = 0;
00210     tag->m_children = 0;
00211     tag->m_xmlnss = 0;
00212 
00213     if( m_attribs )
00214     {
00215       AttributeList::iterator it = m_attribs->begin();
00216       while( it != m_attribs->end() )
00217         (*it++)->m_parent = this;
00218     }
00219 
00220     if( m_children )
00221     {
00222       TagList::iterator it = m_children->begin();
00223       while( it != m_children->end() )
00224         (*it++)->m_parent = this;
00225     }
00226   }
00227 
00228   Tag::~Tag()
00229   {
00230     if( m_cdata )
00231       util::clearList( *m_cdata );
00232     if( m_attribs )
00233       util::clearList( *m_attribs );
00234     if( m_children )
00235       util::clearList( *m_children );
00236     if( m_nodes )
00237       util::clearList( *m_nodes );
00238 
00239     delete m_cdata;
00240     delete m_attribs;
00241     delete m_children;
00242     delete m_nodes;
00243     delete m_xmlnss;
00244 
00245     m_parent = 0;
00246   }
00247 
00248   bool Tag::operator==( const Tag& right ) const
00249   {
00250     if( m_name != right.m_name || m_xmlns != right.m_xmlns )
00251       return false;
00252 
00253     if( m_cdata && right.m_cdata )
00254     {
00255       StringPList::const_iterator ct = m_cdata->begin();
00256       StringPList::const_iterator ct_r = right.m_cdata->begin();
00257       while( ct != m_cdata->end() && ct_r != right.m_cdata->end() && *(*ct) == *(*ct_r) )
00258       {
00259         ++ct;
00260         ++ct_r;
00261       }
00262       if( ct != m_cdata->end() )
00263         return false;
00264     }
00265     else if( m_cdata || right.m_cdata )
00266       return false;
00267 
00268     if( m_children && right.m_children )
00269     {
00270       TagList::const_iterator it = m_children->begin();
00271       TagList::const_iterator it_r = right.m_children->begin();
00272       while( it != m_children->end() && it_r != right.m_children->end() && *(*it) == *(*it_r) )
00273       {
00274         ++it;
00275         ++it_r;
00276       }
00277       if( it != m_children->end() )
00278         return false;
00279     }
00280     else if( m_children || right.m_children )
00281       return false;
00282 
00283     if( m_attribs && right.m_attribs )
00284     {
00285       AttributeList::const_iterator at = m_attribs->begin();
00286       AttributeList::const_iterator at_r = right.m_attribs->begin();
00287       while( at != m_attribs->end() && at_r != right.m_attribs->end() && *(*at) == *(*at_r) )
00288       {
00289         ++at;
00290         ++at_r;
00291       }
00292       if( at != m_attribs->end() )
00293         return false;
00294     }
00295     else if( m_attribs || right.m_attribs )
00296       return false;
00297 
00298     return true;
00299   }
00300 
00301   const std::string Tag::xml() const
00302   {
00303     if( m_name.empty() )
00304       return EmptyString;
00305 
00306     std::string xml = "<";
00307     if( !m_prefix.empty() )
00308     {
00309       xml += m_prefix;
00310       xml += ':';
00311     }
00312     xml += m_name;
00313     if( m_attribs && !m_attribs->empty() )
00314     {
00315       AttributeList::const_iterator it_a = m_attribs->begin();
00316       for( ; it_a != m_attribs->end(); ++it_a )
00317       {
00318         xml += (*it_a)->xml();
00319       }
00320     }
00321 
00322     if( !m_nodes || m_nodes->empty() )
00323       xml += "/>";
00324     else
00325     {
00326       xml += '>';
00327       NodeList::const_iterator it_n = m_nodes->begin();
00328       for( ; it_n != m_nodes->end(); ++it_n )
00329       {
00330         switch( (*it_n)->type )
00331         {
00332           case TypeTag:
00333             xml += (*it_n)->tag->xml();
00334             break;
00335           case TypeString:
00336             xml += util::escape( *((*it_n)->str) );
00337             break;
00338         }
00339       }
00340       xml += "</";
00341       if( !m_prefix.empty() )
00342       {
00343         xml += m_prefix;
00344         xml += ':';
00345       }
00346       xml += m_name;
00347       xml += '>';
00348     }
00349 
00350     return xml;
00351   }
00352 
00353   bool Tag::addAttribute( Attribute* attr )
00354   {
00355     if( !attr )
00356       return false;
00357 
00358     if( !(*attr) )
00359     {
00360       delete attr;
00361       return false;
00362     }
00363 
00364     if( !m_attribs )
00365       m_attribs = new AttributeList();
00366 
00367     AttributeList::iterator it = m_attribs->begin();
00368     for( ; it != m_attribs->end(); ++it )
00369     {
00370       if( (*it)->name() == attr->name()
00371           && ( (*it)->xmlns() == attr->xmlns() || (*it)->prefix() == attr->prefix() ) )
00372       {
00373         delete (*it);
00374         (*it) = attr;
00375         return true;
00376       }
00377     }
00378 
00379     m_attribs->push_back( attr );
00380 
00381     return true;
00382   }
00383 
00384   bool Tag::addAttribute( const std::string& name, const std::string& value )
00385   {
00386     if( name.empty() || value.empty() )
00387       return false;
00388 
00389     return addAttribute( new Attribute( name, value ) );
00390   }
00391 
00392   bool Tag::addAttribute( const std::string& name, int value )
00393   {
00394     if( name.empty() )
00395       return false;
00396 
00397     return addAttribute( name, util::int2string( value ) );
00398   }
00399 
00400   bool Tag::addAttribute( const std::string& name, long value )
00401   {
00402     if( name.empty() )
00403       return false;
00404 
00405     return addAttribute( name, util::long2string( value ) );
00406   }
00407 
00408   void Tag::setAttributes( const AttributeList& attributes )
00409   {
00410     if( !m_attribs )
00411       m_attribs = new AttributeList( attributes );
00412     else
00413     {
00414       util::clearList( *m_attribs );
00415       *m_attribs = attributes;
00416     }
00417 
00418     AttributeList::iterator it = m_attribs->begin();
00419     for( ; it != m_attribs->end(); ++it )
00420       (*it)->m_parent = this;
00421   }
00422 
00423   void Tag::addChild( Tag* child )
00424   {
00425     if( !child )
00426       return;
00427 
00428     if( !m_nodes )
00429       m_nodes = new NodeList();
00430     if( !m_children )
00431       m_children = new TagList();
00432 
00433     m_children->push_back( child );
00434     child->m_parent = this;
00435     m_nodes->push_back( new Node( TypeTag, child ) );
00436   }
00437 
00438   void Tag::addChildCopy( const Tag* child )
00439   {
00440     if( !child )
00441       return;
00442 
00443     addChild( child->clone() );
00444   }
00445 
00446   bool Tag::setCData( const std::string& cdata )
00447   {
00448     if( cdata.empty() || !util::checkValidXMLChars( cdata ) )
00449       return false;
00450 
00451     if( !m_cdata )
00452       m_cdata = new StringPList();
00453     else
00454       util::clearList( *m_cdata );
00455 
00456     if( !m_nodes )
00457       m_nodes = new NodeList();
00458     else
00459     {
00460       NodeList::iterator it = m_nodes->begin();
00461       NodeList::iterator t;
00462       while( it != m_nodes->end() )
00463       {
00464         if( (*it)->type == TypeString )
00465         {
00466           t = it++;
00467           delete (*t);
00468           m_nodes->erase( t );
00469         }
00470       }
00471     }
00472 
00473     return addCData( cdata );
00474   }
00475 
00476   bool Tag::addCData( const std::string& cdata )
00477   {
00478     if( cdata.empty() || !util::checkValidXMLChars( cdata ) )
00479       return false;
00480 
00481     if( !m_cdata )
00482       m_cdata = new StringPList();
00483     if( !m_nodes )
00484       m_nodes = new NodeList();
00485 
00486     std::string* str = new std::string( cdata );
00487     m_cdata->push_back( str );
00488     m_nodes->push_back( new Node( TypeString, str ) );
00489     return true;
00490   }
00491 
00492   const std::string Tag::cdata() const
00493   {
00494     if( !m_cdata )
00495       return EmptyString;
00496 
00497     std::string str;
00498     StringPList::const_iterator it = m_cdata->begin();
00499     for( ; it != m_cdata->end(); ++it )
00500       str += *(*it);
00501 
00502     return str;
00503   }
00504 
00505   const TagList& Tag::children() const
00506   {
00507     static const TagList empty;
00508     return m_children ? *m_children : empty;
00509   }
00510 
00511   const Tag::AttributeList& Tag::attributes() const
00512   {
00513     static const AttributeList empty;
00514     return m_attribs ? *m_attribs : empty;
00515   }
00516 
00517   bool Tag::setXmlns( const std::string& xmlns, const std::string& prefix )
00518   {
00519     if( !util::checkValidXMLChars( xmlns ) || !util::checkValidXMLChars( prefix ) )
00520       return false;
00521 
00522     if( prefix.empty() )
00523     {
00524       m_xmlns = xmlns;
00525       return addAttribute( XMLNS, m_xmlns );
00526     }
00527     else
00528     {
00529       if( !m_xmlnss )
00530         m_xmlnss = new StringMap();
00531 
00532       (*m_xmlnss)[prefix] = xmlns;
00533 
00534       return addAttribute( XMLNS + ":" + prefix, xmlns );
00535     }
00536   }
00537 
00538   const std::string& Tag::xmlns() const
00539   {
00540     return xmlns( m_prefix );
00541   }
00542 
00543   const std::string& Tag::xmlns( const std::string& prefix ) const
00544   {
00545     if( prefix.empty() )
00546     {
00547       return hasAttribute( XMLNS ) ? findAttribute( XMLNS ) : m_xmlns;
00548     }
00549 
00550     if( m_xmlnss )
00551     {
00552       StringMap::const_iterator it = m_xmlnss->find( prefix );
00553       if( it != m_xmlnss->end() )
00554         return (*it).second;
00555     }
00556 
00557     return m_parent ? m_parent->xmlns( prefix ) : EmptyString;
00558   }
00559 
00560   bool Tag::setPrefix( const std::string& prefix )
00561   {
00562     if( !util::checkValidXMLChars( prefix ) )
00563       return false;
00564 
00565     m_prefix = prefix;
00566     return true;
00567   }
00568 
00569   const std::string& Tag::prefix( const std::string& xmlns ) const
00570   {
00571     if( xmlns.empty() || !m_xmlnss )
00572       return EmptyString;
00573 
00574     StringMap::const_iterator it = m_xmlnss->begin();
00575     for( ; it != m_xmlnss->end(); ++it )
00576     {
00577       if( (*it).second == xmlns )
00578         return (*it).first;
00579     }
00580 
00581     return EmptyString;
00582   }
00583 
00584   const std::string& Tag::findAttribute( const std::string& name ) const
00585   {
00586     if( !m_attribs )
00587       return EmptyString;
00588 
00589     AttributeList::const_iterator it = m_attribs->begin();
00590     for( ; it != m_attribs->end(); ++it )
00591       if( (*it)->name() == name )
00592         return (*it)->value();
00593 
00594     return EmptyString;
00595   }
00596 
00597   bool Tag::hasAttribute( const std::string& name, const std::string& value ) const
00598   {
00599     if( name.empty() || !m_attribs )
00600       return false;
00601 
00602     AttributeList::const_iterator it = m_attribs->begin();
00603     for( ; it != m_attribs->end(); ++it )
00604       if( (*it)->name() == name )
00605         return value.empty() || (*it)->value() == value;
00606 
00607     return false;
00608   }
00609 
00610   bool Tag::hasChild( const std::string& name, const std::string& attr,
00611                       const std::string& value ) const
00612   {
00613     if( attr.empty() )
00614       return findChild( name ) ? true : false;
00615     else
00616       return findChild( name, attr, value ) ? true : false;
00617   }
00618 
00619   Tag* Tag::findChild( const std::string& name ) const
00620   {
00621     if( !m_children )
00622       return 0;
00623 
00624     TagList::const_iterator it = m_children->begin();
00625     while( it != m_children->end() && (*it)->name() != name )
00626       ++it;
00627     return it != m_children->end() ? (*it) : 0;
00628   }
00629 
00630   Tag* Tag::findChild( const std::string& name, const std::string& attr,
00631                        const std::string& value ) const
00632   {
00633     if( !m_children || name.empty() )
00634       return 0;
00635 
00636     TagList::const_iterator it = m_children->begin();
00637     while( it != m_children->end() && ( (*it)->name() != name || !(*it)->hasAttribute( attr, value ) ) )
00638       ++it;
00639     return it != m_children->end() ? (*it) : 0;
00640   }
00641 
00642   bool Tag::hasChildWithCData( const std::string& name, const std::string& cdata ) const
00643   {
00644     if( !m_children || name.empty() || cdata.empty() )
00645       return 0;
00646 
00647     TagList::const_iterator it = m_children->begin();
00648     while( it != m_children->end() && ( (*it)->name() != name
00649             || ( !cdata.empty() && (*it)->cdata() != cdata ) ) )
00650       ++it;
00651     return it != m_children->end();
00652   }
00653 
00654   Tag* Tag::findChildWithAttrib( const std::string& attr, const std::string& value ) const
00655   {
00656     if( !m_children || attr.empty() )
00657       return 0;
00658 
00659     TagList::const_iterator it = m_children->begin();
00660     while( it != m_children->end() && !(*it)->hasAttribute( attr, value ) )
00661       ++it;
00662     return it != m_children->end() ? (*it) : 0;
00663   }
00664 
00665   Tag* Tag::clone() const
00666   {
00667     Tag* t = new Tag( m_name );
00668     t->m_xmlns = m_xmlns;
00669     t->m_prefix = m_prefix;
00670 
00671     if( m_attribs )
00672     {
00673       t->m_attribs = new AttributeList();
00674       Tag::AttributeList::const_iterator at = m_attribs->begin();
00675       Attribute* attr;
00676       for( ; at != m_attribs->end(); ++at )
00677       {
00678         attr = new Attribute( *(*at) );
00679         attr->m_parent = t;
00680         t->m_attribs->push_back( attr );
00681       }
00682     }
00683 
00684     if( m_xmlnss )
00685     {
00686       t->m_xmlnss = new StringMap( *m_xmlnss );
00687     }
00688 
00689     if( m_nodes )
00690     {
00691       Tag::NodeList::const_iterator nt = m_nodes->begin();
00692       for( ; nt != m_nodes->end(); ++nt )
00693       {
00694         switch( (*nt)->type )
00695         {
00696           case TypeTag:
00697             t->addChild( (*nt)->tag->clone() );
00698             break;
00699           case TypeString:
00700             t->addCData( *((*nt)->str) );
00701             break;
00702         }
00703       }
00704     }
00705 
00706     return t;
00707   }
00708 
00709   TagList Tag::findChildren( const std::string& name,
00710                              const std::string& xmlns ) const
00711   {
00712     return m_children ? findChildren( *m_children, name, xmlns ) : TagList();
00713   }
00714 
00715   TagList Tag::findChildren( const TagList& list, const std::string& name,
00716                              const std::string& xmlns ) const
00717   {
00718     TagList ret;
00719     TagList::const_iterator it = list.begin();
00720     for( ; it != list.end(); ++it )
00721     {
00722       if( (*it)->name() == name && ( xmlns.empty() || (*it)->xmlns() == xmlns ) )
00723         ret.push_back( (*it) );
00724     }
00725     return ret;
00726   }
00727 
00728   void Tag::removeChild( const std::string& name, const std::string& xmlns )
00729   {
00730     if( name.empty() || !m_children || !m_nodes )
00731       return;
00732 
00733     TagList l = findChildren( name, xmlns );
00734     TagList::iterator it = l.begin();
00735     TagList::iterator it2;
00736     while( it != l.end() )
00737     {
00738       it2 = it++;
00739       NodeList::iterator itn = m_nodes->begin();
00740       for( ; itn != m_nodes->end(); ++itn )
00741       {
00742         if( (*itn)->type == TypeTag && (*itn)->tag == (*it2) )
00743         {
00744           delete (*itn);
00745           m_nodes->erase( itn );
00746           break;
00747         }
00748       }
00749       m_children->remove( (*it2) );
00750       delete (*it2);
00751     }
00752   }
00753 
00754   void Tag::removeChild( Tag* tag )
00755   {
00756     if( m_children )
00757       m_children->remove( tag );
00758 
00759     if( !m_nodes )
00760       return;
00761 
00762     NodeList::iterator it = m_nodes->begin();
00763     for( ; it != m_nodes->end(); ++it )
00764     {
00765       if( (*it)->type == TypeTag && (*it)->tag == tag )
00766       {
00767         delete (*it);
00768         m_nodes->erase( it );
00769         return;
00770       }
00771     }
00772   }
00773 
00774   void Tag::removeAttribute( const std::string& attr, const std::string& value,
00775                              const std::string& xmlns )
00776   {
00777     if( attr.empty() || !m_attribs )
00778       return;
00779 
00780     AttributeList::iterator it = m_attribs->begin();
00781     AttributeList::iterator it2;
00782     while( it != m_attribs->end() )
00783     {
00784       it2 = it++;
00785       if( (*it2)->name() == attr && ( value.empty() || (*it2)->value() == value )
00786                                  && ( xmlns.empty() || (*it2)->xmlns() == xmlns ) )
00787       {
00788         delete (*it2);
00789         m_attribs->erase( it2 );
00790       }
00791     }
00792   }
00793 
00794   const std::string Tag::findCData( const std::string& expression ) const
00795   {
00796     const ConstTagList& l = findTagList( expression );
00797     return !l.empty() ? l.front()->cdata() : EmptyString;
00798   }
00799 
00800   const Tag* Tag::findTag( const std::string& expression ) const
00801   {
00802     const ConstTagList& l = findTagList( expression );
00803     return !l.empty() ? l.front() : 0;
00804   }
00805 
00806   ConstTagList Tag::findTagList( const std::string& expression ) const
00807   {
00808     ConstTagList l;
00809     if( expression == "/" || expression == "//" )
00810       return l;
00811 
00812     if( m_parent && expression.length() >= 2 && expression[0] == '/'
00813                                              && expression[1] != '/' )
00814       return m_parent->findTagList( expression );
00815 
00816     unsigned len = 0;
00817     Tag* p = parse( expression, len );
00818 //     if( p )
00819 //       printf( "parsed tree: %s\n", p->xml().c_str() );
00820     l = evaluateTagList( p );
00821     delete p;
00822     return l;
00823   }
00824 
00825   ConstTagList Tag::evaluateTagList( Tag* token ) const
00826   {
00827     ConstTagList result;
00828     if( !token )
00829       return result;
00830 
00831 //     printf( "evaluateTagList called in Tag %s and Token %s (type: %s)\n", name().c_str(),
00832 //             token->name().c_str(), token->findAttribute( TYPE ).c_str() );
00833 
00834     TokenType tokenType = (TokenType)atoi( token->findAttribute( TYPE ).c_str() );
00835     switch( tokenType )
00836     {
00837       case XTUnion:
00838         add( result, evaluateUnion( token ) );
00839         break;
00840       case XTElement:
00841       {
00842 //         printf( "in XTElement, token: %s\n", token->name().c_str() );
00843         if( token->name() == name() || token->name() == "*" )
00844         {
00845 //           printf( "found %s\n", name().c_str() );
00846           const TagList& tokenChildren = token->children();
00847           if( tokenChildren.size() )
00848           {
00849             bool predicatesSucceeded = true;
00850             TagList::const_iterator cit = tokenChildren.begin();
00851             for( ; cit != tokenChildren.end(); ++cit )
00852             {
00853               if( (*cit)->hasAttribute( "predicate", "true" ) )
00854               {
00855                 predicatesSucceeded = evaluatePredicate( (*cit) );
00856                 if( !predicatesSucceeded )
00857                   return result;
00858               }
00859             }
00860 
00861             bool hasElementChildren = false;
00862             cit = tokenChildren.begin();
00863             for( ; cit != tokenChildren.end(); ++cit )
00864             {
00865               if( (*cit)->hasAttribute( "predicate", "true" ) ||
00866                   (*cit)->hasAttribute( "number", "true" ) )
00867                 continue;
00868 
00869               hasElementChildren = true;
00870 
00871 //               printf( "checking %d children of token %s\n", tokenChildren.size(), token->name().c_str() );
00872               if( m_children && !m_children->empty() )
00873               {
00874                 TagList::const_iterator it = m_children->begin();
00875                 for( ; it != m_children->end(); ++it )
00876                 {
00877                   add( result, (*it)->evaluateTagList( (*cit) ) );
00878                 }
00879               }
00880               else if( atoi( (*cit)->findAttribute( TYPE ).c_str() ) == XTDoubleDot && m_parent )
00881               {
00882                 (*cit)->addAttribute( TYPE, XTDot );
00883                 add( result, m_parent->evaluateTagList( (*cit) ) );
00884               }
00885             }
00886 
00887             if( !hasElementChildren )
00888               result.push_back( this );
00889           }
00890           else
00891           {
00892 //             printf( "adding %s to result set\n", name().c_str() );
00893             result.push_back( this );
00894           }
00895         }
00896 //         else
00897 //           printf( "found %s != %s\n", token->name().c_str(), name().c_str() );
00898 
00899         break;
00900       }
00901       case XTDoubleSlash:
00902       {
00903 //         printf( "in XTDoubleSlash\n" );
00904         Tag* t = token->clone();
00905 //         printf( "original token: %s\ncloned token: %s\n", token->xml().c_str(), n->xml().c_str() );
00906         t->addAttribute( TYPE, XTElement );
00907         add( result, evaluateTagList( t ) );
00908         const ConstTagList& res2 = allDescendants();
00909         ConstTagList::const_iterator it = res2.begin();
00910         for( ; it != res2.end(); ++it )
00911         {
00912           add( result, (*it)->evaluateTagList( t ) );
00913         }
00914         delete t;
00915         break;
00916       }
00917       case XTDot:
00918       {
00919         const TagList& tokenChildren = token->children();
00920         if( !tokenChildren.empty() )
00921         {
00922           add( result, evaluateTagList( tokenChildren.front() ) );
00923         }
00924         else
00925           result.push_back( this );
00926         break;
00927       }
00928       case XTDoubleDot:
00929       {
00930 //         printf( "in XTDoubleDot\n" );
00931         if( m_parent )
00932         {
00933           const TagList& tokenChildren = token->children();
00934           if( tokenChildren.size() )
00935           {
00936             Tag* testtoken = tokenChildren.front();
00937             if( testtoken->name() == "*" )
00938             {
00939               add( result, m_parent->evaluateTagList( testtoken ) );
00940             }
00941             else
00942             {
00943               Tag* t = token->clone();
00944               t->addAttribute( TYPE, XTElement );
00945               t->m_name = m_parent->m_name;
00946               add( result, m_parent->evaluateTagList( t ) );
00947               delete t;
00948             }
00949           }
00950           else
00951           {
00952             result.push_back( m_parent );
00953           }
00954         }
00955       }
00956       case XTInteger:
00957       {
00958         const TagList& l = token->children();
00959         if( !l.size() )
00960           break;
00961 
00962         const ConstTagList& res = evaluateTagList( l.front() );
00963 
00964         int pos = atoi( token->name().c_str() );
00965 //         printf( "checking index %d\n", pos );
00966         if( pos > 0 && pos <= (int)res.size() )
00967         {
00968           ConstTagList::const_iterator it = res.begin();
00969           while ( --pos )
00970           {
00971             ++it;
00972           }
00973           result.push_back( *it );
00974         }
00975         break;
00976       }
00977       default:
00978         break;
00979     }
00980     return result;
00981   }
00982 
00983   bool Tag::evaluateBoolean( Tag* token ) const
00984   {
00985     if( !token )
00986       return false;
00987 
00988     bool result = false;
00989     TokenType tokenType = (TokenType)atoi( token->findAttribute( TYPE ).c_str() );
00990     switch( tokenType )
00991     {
00992       case XTAttribute:
00993         if( token->name() == "*" && m_attribs && m_attribs->size() )
00994           result = true;
00995         else
00996           result = hasAttribute( token->name() );
00997         break;
00998       case XTOperatorEq:
00999         result = evaluateEquals( token );
01000         break;
01001       case XTOperatorLt:
01002         break;
01003       case XTOperatorLtEq:
01004         break;
01005       case XTOperatorGtEq:
01006         break;
01007       case XTOperatorGt:
01008         break;
01009       case XTUnion:
01010       case XTElement:
01011       {
01012         Tag* t = new Tag( "." );
01013         t->addAttribute( TYPE, XTDot );
01014         t->addChild( token );
01015         result = !evaluateTagList( t ).empty();
01016         t->removeChild( token );
01017         delete t;
01018         break;
01019       }
01020       default:
01021         break;
01022     }
01023 
01024     return result;
01025   }
01026 
01027   bool Tag::evaluateEquals( Tag* token ) const
01028   {
01029     if( !token || token->children().size() != 2 )
01030       return false;
01031 
01032     bool result = false;
01033     TagList::const_iterator it = token->children().begin();
01034     Tag* ch1 = (*it);
01035     Tag* ch2 = (*++it);
01036 
01037     TokenType tt1 = (TokenType)atoi( ch1->findAttribute( TYPE ).c_str() );
01038     TokenType tt2 = (TokenType)atoi( ch2->findAttribute( TYPE ).c_str() );
01039     switch( tt1 )
01040     {
01041       case XTAttribute:
01042         switch( tt2 )
01043         {
01044           case XTInteger:
01045           case XTLiteral:
01046             result = ( findAttribute( ch1->name() ) == ch2->name() );
01047             break;
01048           case XTAttribute:
01049             result = ( hasAttribute( ch1->name() ) && hasAttribute( ch2->name() ) &&
01050                       findAttribute( ch1->name() ) == findAttribute( ch2->name() ) );
01051             break;
01052           default:
01053             break;
01054         }
01055         break;
01056       case XTInteger:
01057       case XTLiteral:
01058         switch( tt2 )
01059         {
01060           case XTAttribute:
01061             result = ( ch1->name() == findAttribute( ch2->name() ) );
01062             break;
01063           case XTLiteral:
01064           case XTInteger:
01065             result = ( ch1->name() == ch2->name() );
01066             break;
01067           default:
01068             break;
01069         }
01070         break;
01071       default:
01072         break;
01073     }
01074 
01075     return result;
01076   }
01077 
01078   ConstTagList Tag::allDescendants() const
01079   {
01080     ConstTagList result;
01081 
01082     if( !m_children )
01083       return result;
01084 
01085     TagList::const_iterator it = m_children->begin();
01086     for( ; it != m_children->end(); ++it )
01087     {
01088       result.push_back( (*it) );
01089       add( result, (*it)->allDescendants() );
01090     }
01091     return result;
01092   }
01093 
01094   ConstTagList Tag::evaluateUnion( Tag* token ) const
01095   {
01096     ConstTagList result;
01097     if( !token )
01098       return result;
01099 
01100     const TagList& l = token->children();
01101     TagList::const_iterator it = l.begin();
01102     for( ; it != l.end(); ++it )
01103     {
01104       add( result, evaluateTagList( (*it) ) );
01105     }
01106     return result;
01107   }
01108 
01109   void Tag::closePreviousToken( Tag** root, Tag** current, Tag::TokenType& type, std::string& tok ) const
01110   {
01111     if( !tok.empty() )
01112     {
01113       addToken( root, current, type, tok );
01114       type = XTElement;
01115       tok = EmptyString;
01116     }
01117   }
01118 
01119   Tag* Tag::parse( const std::string& expression, unsigned& len, Tag::TokenType border ) const
01120   {
01121     Tag* root = 0;
01122     Tag* current = root;
01123     std::string token;
01124 
01125 //     XPathError error = XPNoError;
01126 //     XPathState state = Init;
01127 //     int expected = 0;
01128 //     bool run = true;
01129 //     bool ws = false;
01130 
01131     Tag::TokenType type  = XTElement;
01132 
01133     char c;
01134     for( ; len < expression.length(); ++len )
01135     {
01136       c = expression[len];
01137       if( type == XTLiteralInside && c != '\'' )
01138       {
01139         token += c;
01140         continue;
01141       }
01142 
01143       switch( c )
01144       {
01145         case '/':
01146           closePreviousToken( &root, &current, type, token );
01147 
01148           if( len < expression.length()-1 && expression[len+1] == '/' )
01149           {
01150 //             addToken( &root, &current, XTDoubleSlash, "//" );
01151             type = XTDoubleSlash;
01152             ++len;
01153           }
01154 //           else
01155 //           {
01156 //             if( !current )
01157 //             addToken( &root, &current, XTSlash, "/" );
01158 //           }
01159           break;
01160         case ']':
01161           closePreviousToken( &root, &current, type, token );
01162           return root;
01163         case '[':
01164         {
01165           closePreviousToken( &root, &current, type, token );
01166           Tag* t = parse( expression, ++len, XTRightBracket );
01167           if( !addPredicate( &root, &current, t ) )
01168             delete t;
01169           break;
01170         }
01171         case '(':
01172         {
01173           closePreviousToken( &root, &current, type, token );
01174           Tag* t = parse( expression, ++len, XTRightParenthesis );
01175           if( current )
01176           {
01177 //             printf( "added %s to %s\n", t->xml().c_str(), current->xml().c_str() );
01178             t->addAttribute( "argument", "true" );
01179             current->addChild( t );
01180           }
01181           else
01182           {
01183             root = t;
01184 //             printf( "made %s new root\n", t->xml().c_str() );
01185           }
01186           break;
01187         }
01188         case ')':
01189           closePreviousToken( &root, &current, type, token );
01190           ++len;
01191           return root;
01192         case '\'':
01193           if( type == XTLiteralInside )
01194             if( expression[len - 2] == '\\' )
01195               token[token.length() - 2] = c;
01196             else
01197               type = XTLiteral;
01198           else
01199             type = XTLiteralInside;
01200           break;
01201         case '@':
01202           type = XTAttribute;
01203           break;
01204         case '.':
01205           token += c;
01206           if( token.size() == 1 )
01207           {
01208             if( len < expression.length()-1 && expression[len+1] == '.' )
01209             {
01210               type = XTDoubleDot;
01211               ++len;
01212               token += c;
01213             }
01214             else
01215             {
01216               type = XTDot;
01217             }
01218           }
01219           break;
01220         case '*':
01221 //           if( !root || ( current && ( current->tokenType() == XTSlash
01222 //                                       || current->tokenType() == XTDoubleSlash ) ) )
01223 //           {
01224 //             addToken( &root, &current, type, "*" );
01225 //             break;
01226 //           }
01227           addToken( &root, &current, type, "*" );
01228           type = XTElement;
01229           break;
01230         case '+':
01231         case '>':
01232         case '<':
01233         case '=':
01234         case '|':
01235         {
01236           closePreviousToken( &root, &current, type, token );
01237           std::string s( 1, c );
01238           Tag::TokenType ttype = getType( s );
01239           if( ttype <= border )
01240             return root;
01241           Tag* t = parse( expression, ++len, ttype );
01242           addOperator( &root, &current, t, ttype, s );
01243           if( border == XTRightBracket )
01244             return root;
01245           break;
01246         }
01247         default:
01248           token += c;
01249       }
01250     }
01251 
01252     if( !token.empty() )
01253       addToken( &root, &current, type, token );
01254 
01255 //     if( error != XPNoError )
01256 //       printf( "error: %d\n", error );
01257     return root;
01258   }
01259 
01260   void Tag::addToken( Tag **root, Tag **current, Tag::TokenType type,
01261                       const std::string& token ) const
01262   {
01263     Tag* t = new Tag( token );
01264     if( t->isNumber() && !t->children().size() )
01265       type = XTInteger;
01266     t->addAttribute( TYPE, type );
01267 
01268     if( *root )
01269     {
01270 //       printf( "new current %s, type: %d\n", token.c_str(), type );
01271       (*current)->addChild( t );
01272       *current = t;
01273     }
01274     else
01275     {
01276 //       printf( "new root %s, type: %d\n", token.c_str(), type );
01277       *current = *root = t;
01278     }
01279   }
01280 
01281   void Tag::addOperator( Tag** root, Tag** current, Tag* arg,
01282                            Tag::TokenType type, const std::string& token ) const
01283   {
01284     Tag* t = new Tag( token );
01285     t->addAttribute( TYPE, type );
01286 //     printf( "new operator: %s (arg1: %s, arg2: %s)\n", t->name().c_str(), (*root)->xml().c_str(),
01287 //                                                                           arg->xml().c_str() );
01288     t->addAttribute( "operator", "true" );
01289     t->addChild( *root );
01290     t->addChild( arg );
01291     *current = *root = t;
01292   }
01293 
01294   bool Tag::addPredicate( Tag **root, Tag **current, Tag* token ) const
01295   {
01296     if( !*root || !*current )
01297       return false;
01298 
01299     if( ( token->isNumber() && !token->children().size() ) || token->name() == "+" )
01300     {
01301 //       printf( "found Index %s, full: %s\n", token->name().c_str(), token->xml().c_str() );
01302       if( !token->hasAttribute( "operator", "true" ) )
01303       {
01304         token->addAttribute( TYPE, XTInteger );
01305       }
01306       if( *root == *current )
01307       {
01308         *root = token;
01309 //         printf( "made Index new root\n" );
01310       }
01311       else
01312       {
01313         (*root)->removeChild( *current );
01314         (*root)->addChild( token );
01315 //         printf( "added Index somewhere between root and current\n" );
01316       }
01317       token->addChild( *current );
01318 //       printf( "added Index %s, full: %s\n", token->name().c_str(), token->xml().c_str() );
01319     }
01320     else
01321     {
01322       token->addAttribute( "predicate", "true" );
01323       (*current)->addChild( token );
01324     }
01325 
01326     return true;
01327   }
01328 
01329   Tag::TokenType Tag::getType( const std::string& c )
01330   {
01331     if( c == "|" )
01332       return XTUnion;
01333     if( c == "<" )
01334       return XTOperatorLt;
01335     if( c == ">" )
01336       return XTOperatorGt;
01337     if( c == "*" )
01338       return XTOperatorMul;
01339     if( c == "+" )
01340       return XTOperatorPlus;
01341     if( c == "=" )
01342       return XTOperatorEq;
01343 
01344     return XTNone;
01345   }
01346 
01347   bool Tag::isWhitespace( const char c )
01348   {
01349     return ( c == 0x09 || c == 0x0a || c == 0x0d || c == 0x20 );
01350   }
01351 
01352   bool Tag::isNumber() const
01353   {
01354     if( m_name.empty() )
01355       return false;
01356 
01357     std::string::size_type l = m_name.length();
01358     std::string::size_type i = 0;
01359     while( i < l && isdigit( m_name[i] ) )
01360       ++i;
01361     return i == l;
01362   }
01363 
01364   void Tag::add( ConstTagList& one, const ConstTagList& two )
01365   {
01366     ConstTagList::const_iterator it = two.begin();
01367     for( ; it != two.end(); ++it )
01368       if( std::find( one.begin(), one.end(), (*it) ) == one.end() )
01369         one.push_back( (*it) );
01370   }
01371 
01372 }