gloox 1.0
|
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, ¤t, type, token ); 01147 01148 if( len < expression.length()-1 && expression[len+1] == '/' ) 01149 { 01150 // addToken( &root, ¤t, XTDoubleSlash, "//" ); 01151 type = XTDoubleSlash; 01152 ++len; 01153 } 01154 // else 01155 // { 01156 // if( !current ) 01157 // addToken( &root, ¤t, XTSlash, "/" ); 01158 // } 01159 break; 01160 case ']': 01161 closePreviousToken( &root, ¤t, type, token ); 01162 return root; 01163 case '[': 01164 { 01165 closePreviousToken( &root, ¤t, type, token ); 01166 Tag* t = parse( expression, ++len, XTRightBracket ); 01167 if( !addPredicate( &root, ¤t, t ) ) 01168 delete t; 01169 break; 01170 } 01171 case '(': 01172 { 01173 closePreviousToken( &root, ¤t, 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, ¤t, 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, ¤t, type, "*" ); 01225 // break; 01226 // } 01227 addToken( &root, ¤t, type, "*" ); 01228 type = XTElement; 01229 break; 01230 case '+': 01231 case '>': 01232 case '<': 01233 case '=': 01234 case '|': 01235 { 01236 closePreviousToken( &root, ¤t, 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, ¤t, 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, ¤t, 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 }