Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | Related Pages

tag.cpp

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

Generated on Mon Nov 17 02:45:13 2008 for gloox by  doxygen 1.4.1