KHTML
functions.cpp
Go to the documentation of this file.
00001 /* 00002 * functions.cc - Copyright 2005 Frerich Raabe <raabe@kde.org> 00003 * 00004 * Redistribution and use in source and binary forms, with or without 00005 * modification, are permitted provided that the following conditions 00006 * are met: 00007 * 00008 * 1. Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * 2. Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * 00014 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00015 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00016 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 00017 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 00018 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 00019 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00020 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00021 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00022 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 00023 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00024 */ 00025 #include "functions.h" 00026 00027 #include "xml/dom_docimpl.h" 00028 #include "xml/dom_nodeimpl.h" 00029 #include "xml/dom_nodelistimpl.h" 00030 #include "xml/dom_elementimpl.h" 00031 #include "kjs/operations.h" 00032 00033 #include <QtDebug> 00034 00035 #include <math.h> 00036 00037 using namespace DOM; 00038 00039 namespace khtml { 00040 namespace XPath { 00041 00042 #define DEFINE_FUNCTION_CREATOR(Class) \ 00043 static Function *create##Class() { return new Class; } 00044 00045 class Interval 00046 { 00047 public: 00048 static const int Inf =-1; 00049 00050 Interval(); 00051 Interval( int value ); 00052 Interval( int min, int max ); 00053 00054 bool contains( int value ) const; 00055 00056 QString asString() const; 00057 00058 private: 00059 int m_min; 00060 int m_max; 00061 }; 00062 00063 class FunLast : public Function 00064 { 00065 public: 00066 virtual bool isConstant() const; 00067 00068 private: 00069 virtual Value doEvaluate() const; 00070 }; 00071 00072 class FunPosition : public Function 00073 { 00074 public: 00075 virtual bool isConstant() const; 00076 00077 private: 00078 virtual Value doEvaluate() const; 00079 }; 00080 00081 class FunCount : public Function 00082 { 00083 public: 00084 virtual bool isConstant() const; 00085 00086 private: 00087 virtual Value doEvaluate() const; 00088 }; 00089 00090 // Base for various node-property functions, that have 00091 // the same node picking logic. It passes the proper node, 00092 // if any, or otherwise returns an empty string by itself 00093 class NodeFunction : public Function 00094 { 00095 private: 00096 virtual Value doEvaluate() const; 00097 virtual Value evaluateOnNode( DOM::NodeImpl* node ) const = 0; 00098 }; 00099 00100 class FunLocalName : public NodeFunction 00101 { 00102 public: 00103 virtual bool isConstant() const; 00104 00105 private: 00106 virtual Value evaluateOnNode( DOM::NodeImpl* node ) const; 00107 }; 00108 00109 class FunNamespaceURI : public NodeFunction 00110 { 00111 public: 00112 virtual bool isConstant() const; 00113 00114 private: 00115 virtual Value evaluateOnNode( DOM::NodeImpl* node ) const; 00116 }; 00117 00118 class FunName : public NodeFunction 00119 { 00120 public: 00121 virtual bool isConstant() const; 00122 00123 private: 00124 virtual Value evaluateOnNode( DOM::NodeImpl* node ) const; 00125 }; 00126 00127 class FunId : public Function 00128 { 00129 private: 00130 virtual Value doEvaluate() const; 00131 }; 00132 00133 class FunString : public Function 00134 { 00135 private: 00136 virtual Value doEvaluate() const; 00137 }; 00138 00139 class FunConcat : public Function 00140 { 00141 private: 00142 virtual Value doEvaluate() const; 00143 }; 00144 00145 class FunStartsWith : public Function 00146 { 00147 private: 00148 virtual Value doEvaluate() const; 00149 }; 00150 00151 class FunContains : public Function 00152 { 00153 private: 00154 virtual Value doEvaluate() const; 00155 }; 00156 00157 class FunSubstringBefore : public Function 00158 { 00159 private: 00160 virtual Value doEvaluate() const; 00161 }; 00162 00163 class FunSubstringAfter : public Function 00164 { 00165 private: 00166 virtual Value doEvaluate() const; 00167 }; 00168 00169 class FunSubstring : public Function 00170 { 00171 private: 00172 virtual Value doEvaluate() const; 00173 }; 00174 00175 class FunStringLength : public Function 00176 { 00177 private: 00178 virtual Value doEvaluate() const; 00179 }; 00180 00181 class FunNormalizeSpace : public Function 00182 { 00183 private: 00184 virtual Value doEvaluate() const; 00185 }; 00186 00187 class FunTranslate : public Function 00188 { 00189 private: 00190 virtual Value doEvaluate() const; 00191 }; 00192 00193 class FunBoolean : public Function 00194 { 00195 private: 00196 virtual Value doEvaluate() const; 00197 }; 00198 00199 class FunNot : public Function 00200 { 00201 private: 00202 virtual Value doEvaluate() const; 00203 }; 00204 00205 class FunTrue : public Function 00206 { 00207 public: 00208 virtual bool isConstant() const; 00209 00210 private: 00211 virtual Value doEvaluate() const; 00212 }; 00213 00214 class FunFalse : public Function 00215 { 00216 public: 00217 virtual bool isConstant() const; 00218 00219 private: 00220 virtual Value doEvaluate() const; 00221 }; 00222 00223 class FunLang : public Function 00224 { 00225 public: 00226 virtual bool isConstant() const; 00227 00228 private: 00229 virtual Value doEvaluate() const; 00230 }; 00231 00232 class FunNumber : public Function 00233 { 00234 private: 00235 virtual Value doEvaluate() const; 00236 }; 00237 00238 class FunSum : public Function 00239 { 00240 private: 00241 virtual Value doEvaluate() const; 00242 }; 00243 00244 class FunFloor : public Function 00245 { 00246 private: 00247 virtual Value doEvaluate() const; 00248 }; 00249 00250 class FunCeiling : public Function 00251 { 00252 private: 00253 virtual Value doEvaluate() const; 00254 }; 00255 00256 class FunRound : public Function 00257 { 00258 private: 00259 virtual Value doEvaluate() const; 00260 }; 00261 00262 DEFINE_FUNCTION_CREATOR( FunLast ) 00263 DEFINE_FUNCTION_CREATOR( FunPosition ) 00264 DEFINE_FUNCTION_CREATOR( FunCount ) 00265 DEFINE_FUNCTION_CREATOR( FunLocalName ) 00266 DEFINE_FUNCTION_CREATOR( FunNamespaceURI ) 00267 DEFINE_FUNCTION_CREATOR( FunName ) 00268 DEFINE_FUNCTION_CREATOR( FunId ) 00269 00270 DEFINE_FUNCTION_CREATOR( FunString ) 00271 DEFINE_FUNCTION_CREATOR( FunConcat ) 00272 DEFINE_FUNCTION_CREATOR( FunStartsWith ) 00273 DEFINE_FUNCTION_CREATOR( FunContains ) 00274 DEFINE_FUNCTION_CREATOR( FunSubstringBefore ) 00275 DEFINE_FUNCTION_CREATOR( FunSubstringAfter ) 00276 DEFINE_FUNCTION_CREATOR( FunSubstring ) 00277 DEFINE_FUNCTION_CREATOR( FunStringLength ) 00278 DEFINE_FUNCTION_CREATOR( FunNormalizeSpace ) 00279 DEFINE_FUNCTION_CREATOR( FunTranslate ) 00280 00281 DEFINE_FUNCTION_CREATOR( FunBoolean ) 00282 DEFINE_FUNCTION_CREATOR( FunNot ) 00283 DEFINE_FUNCTION_CREATOR( FunTrue ) 00284 DEFINE_FUNCTION_CREATOR( FunFalse ) 00285 DEFINE_FUNCTION_CREATOR( FunLang ) 00286 00287 DEFINE_FUNCTION_CREATOR( FunNumber ) 00288 DEFINE_FUNCTION_CREATOR( FunSum ) 00289 DEFINE_FUNCTION_CREATOR( FunFloor ) 00290 DEFINE_FUNCTION_CREATOR( FunCeiling ) 00291 DEFINE_FUNCTION_CREATOR( FunRound ) 00292 00293 #undef DEFINE_FUNCTION_CREATOR 00294 00295 Interval::Interval() 00296 : m_min( Inf ), 00297 m_max( Inf ) 00298 { 00299 } 00300 00301 Interval::Interval( int value ) 00302 : m_min( value ), 00303 m_max( value ) 00304 { 00305 } 00306 00307 Interval::Interval( int min, int max ) 00308 : m_min( min ), 00309 m_max( max ) 00310 { 00311 } 00312 00313 bool Interval::contains( int value ) const 00314 { 00315 if ( m_min == Inf && m_max == Inf ) { 00316 return true; 00317 } 00318 00319 if ( m_min == Inf ) { 00320 return value <= m_max; 00321 } 00322 00323 if ( m_max == Inf ) { 00324 return value >= m_min; 00325 } 00326 00327 return value >= m_min && value <= m_max; 00328 } 00329 00330 QString Interval::asString() const 00331 { 00332 QString s = "["; 00333 00334 if ( m_min == Inf ) { 00335 s += "-Infinity"; 00336 } else { 00337 s += QString::number( m_min ); 00338 } 00339 00340 s += ".."; 00341 00342 if ( m_max == Inf ) { 00343 s += "Infinity"; 00344 } else { 00345 s += QString::number( m_max ); 00346 } 00347 00348 s += "]"; 00349 00350 return s; 00351 } 00352 00353 void Function::setArguments( const QList<Expression *> &args ) 00354 { 00355 foreach( Expression *arg, args ) { 00356 addSubExpression( arg ); 00357 } 00358 } 00359 00360 void Function::setName( const DOM::DOMString &name ) 00361 { 00362 m_name = name; 00363 } 00364 00365 QString Function::dump() const 00366 { 00367 if ( argCount() == 0 ) { 00368 return QString( "<function name=\"%1\"/>" ).arg( name().string() ); 00369 } 00370 00371 QString s = QString( "<function name=\"%1\">" ).arg( name().string() ); 00372 for ( unsigned int i = 0; i < argCount(); ++i ) { 00373 s += "<operand>" + arg( i )->dump() + "</operand>"; 00374 } 00375 s += "</function>"; 00376 return s; 00377 } 00378 00379 00380 Expression *Function::arg( int i ) 00381 { 00382 return subExpr( i ); 00383 } 00384 00385 const Expression *Function::arg( int i ) const 00386 { 00387 return subExpr( i ); 00388 } 00389 00390 unsigned int Function::argCount() const 00391 { 00392 return subExprCount(); 00393 } 00394 00395 DOM::DOMString Function::name() const 00396 { 00397 return m_name; 00398 } 00399 00400 Value FunLast::doEvaluate() const 00401 { 00402 return Value( double( Expression::evaluationContext().size ) ); 00403 } 00404 00405 bool FunLast::isConstant() const 00406 { 00407 return false; 00408 } 00409 00410 Value FunPosition::doEvaluate() const 00411 { 00412 return Value( double( Expression::evaluationContext().position ) ); 00413 } 00414 00415 bool FunPosition::isConstant() const 00416 { 00417 return false; 00418 } 00419 00420 Value NodeFunction::doEvaluate() const 00421 { 00422 NodeImpl *node = 0; 00423 if ( argCount() > 0 ) { 00424 Value a = arg( 0 )->evaluate(); 00425 if ( a.isNodeset() && a.toNodeset()->length() ) { 00426 node = a.toNodeset()->first(); 00427 } 00428 } else { 00429 // no argument -> default to context node 00430 node = evaluationContext().node; 00431 } 00432 00433 if ( !node ) 00434 return Value( DOMString() ); 00435 00436 return evaluateOnNode( node ); 00437 } 00438 00439 bool FunLocalName::isConstant() const 00440 { 00441 return false; 00442 } 00443 00444 Value FunLocalName::evaluateOnNode( DOM::NodeImpl* node ) const 00445 { 00446 DOM::DOMString n; 00447 switch ( node->nodeType() ) { 00448 case Node::PROCESSING_INSTRUCTION_NODE: 00449 n = node->nodeName(); // target name 00450 break; 00451 default: 00452 n = node->localName(); 00453 } 00454 return Value( n ); 00455 } 00456 00457 bool FunNamespaceURI::isConstant() const 00458 { 00459 return false; 00460 } 00461 00462 Value FunNamespaceURI::evaluateOnNode( DOM::NodeImpl* node ) const 00463 { 00464 return Value( node->namespaceURI() ); 00465 } 00466 00467 Value FunId::doEvaluate() const 00468 { 00469 Value a = arg( 0 )->evaluate(); 00470 00471 WTF::Vector<DOM::DOMString> ids; 00472 00473 QString queryString; // whitespace-separated IDs 00474 if ( a.isNodeset() ) { 00475 DomNodeList set = a.toNodeset(); 00476 for ( unsigned long i = 0; i < set->length(); ++i) 00477 queryString += stringValue( set->item(i) ).string() + QLatin1Char(' '); 00478 } else { 00479 queryString = a.toString().string(); 00480 } 00481 00482 QStringList qids = queryString.simplified().split(' '); 00483 for ( int i = 0; i < qids.size(); ++i) 00484 ids.append( DOM::DOMString( qids[i] ) ); 00485 00486 DomNodeList out = new StaticNodeListImpl(); 00487 DOM::DocumentImpl* doc = Expression::evaluationContext().node->document(); 00488 00489 for ( unsigned i = 0; i < ids.size(); ++i ) { 00490 DOM::ElementImpl* e = doc->getElementById( ids[i] ); 00491 00492 if ( e ) 00493 out->append( e ); 00494 } 00495 00496 return Value( out ); 00497 } 00498 00499 bool FunName::isConstant() const 00500 { 00501 return false; 00502 } 00503 00504 Value FunName::evaluateOnNode( DOM::NodeImpl* node ) const 00505 { 00506 DOM::DOMString n; 00507 switch ( node->nodeType() ) { 00508 case Node::TEXT_NODE: 00509 case Node::CDATA_SECTION_NODE: 00510 case Node::COMMENT_NODE: 00511 case Node::DOCUMENT_NODE: 00512 // All of these have an empty XPath name 00513 break; 00514 case Node::ELEMENT_NODE: { 00515 n = static_cast<DOM::ElementImpl*>( node )->nonCaseFoldedTagName(); 00516 break; 00517 } 00518 default: 00519 n = node->nodeName(); 00520 } 00521 return Value( n ); 00522 } 00523 00524 Value FunCount::doEvaluate() const 00525 { 00526 Value a = arg( 0 )->evaluate(); 00527 if ( !a.isNodeset() ) { 00528 Expression::reportInvalidExpressionErr(); 00529 kWarning() << "count() expects <nodeset>"; 00530 return Value( ); 00531 } 00532 a.toNodeset()->normalizeUpto(StaticNodeListImpl::AxisOrder); 00533 00534 return Value( double( a.toNodeset()->length() ) ); 00535 } 00536 00537 bool FunCount::isConstant() const 00538 { 00539 return false; 00540 } 00541 00542 Value FunString::doEvaluate() const 00543 { 00544 if ( argCount() == 0 ) { 00545 DOMString s = Value( Expression::evaluationContext().node ).toString(); 00546 return Value( s ); 00547 } 00548 return Value( arg( 0 )->evaluate().toString() ); 00549 } 00550 00551 Value FunConcat::doEvaluate() const 00552 { 00553 QString str; 00554 for ( unsigned int i = 0; i < argCount(); ++i ) { 00555 str.append( arg( i )->evaluate().toString().string() ); 00556 } 00557 return Value( DOMString( str ) ); 00558 } 00559 00560 Value FunStartsWith::doEvaluate() const 00561 { 00562 DOMString s1 = arg( 0 )->evaluate().toString(); 00563 DOMString s2 = arg( 1 )->evaluate().toString(); 00564 00565 if ( s2.isEmpty() ) { 00566 return Value( true ); 00567 } 00568 00569 return Value( s1.startsWith( s2 ) ); 00570 } 00571 00572 Value FunContains::doEvaluate() const 00573 { 00574 QString s1 = arg( 0 )->evaluate().toString().string(); 00575 QString s2 = arg( 1 )->evaluate().toString().string(); 00576 00577 if ( s2.isEmpty() ) { 00578 return Value( true ); 00579 } 00580 00581 return Value( s1.contains( s2 ) ); 00582 } 00583 00584 Value FunSubstringBefore::doEvaluate() const 00585 { 00586 QString s1 = arg( 0 )->evaluate().toString().string(); 00587 QString s2 = arg( 1 )->evaluate().toString().string(); 00588 00589 if ( s2.isEmpty() ) { 00590 return Value( DOMString() ); 00591 } 00592 00593 int i = s1.indexOf( s2 ); 00594 if ( i == -1 ) { 00595 return Value( DOMString() ); 00596 } 00597 00598 return Value( DOMString( s1.left( i ) ) ); 00599 } 00600 00601 Value FunSubstringAfter::doEvaluate() const 00602 { 00603 QString s1 = arg( 0 )->evaluate().toString().string(); 00604 QString s2 = arg( 1 )->evaluate().toString().string(); 00605 00606 if ( s2.isEmpty() ) { 00607 return Value( s1 ); 00608 } 00609 00610 int i = s1.indexOf( s2 ); 00611 if ( i == -1 ) { 00612 return Value( DOMString() ); 00613 } 00614 00615 return Value( DOMString( s1.mid( i + s2.length() ) ) ); 00616 } 00617 00618 Value FunSubstring::doEvaluate() const 00619 { 00620 QString s = arg( 0 )->evaluate().toString().string(); 00621 long pos = long( qRound( arg( 1 )->evaluate().toNumber() ) ); 00622 bool haveLength = argCount() == 3; 00623 long len = -1; 00624 if ( haveLength ) { 00625 len = long( qRound( arg( 2 )->evaluate().toNumber() ) ); 00626 } 00627 00628 if ( pos > long( s.length() ) ) { 00629 return Value( DOMString() ); 00630 } 00631 00632 if ( haveLength && pos < 1 ) { 00633 len -= 1 - pos; 00634 pos = 1; 00635 if ( len < 1 ) { 00636 return Value( DOMString() ); 00637 } 00638 } 00639 00640 return Value( DOMString( s.mid( pos - 1, len ) ) ); 00641 } 00642 00643 Value FunStringLength::doEvaluate() const 00644 { 00645 if ( argCount() == 0 ) { 00646 DOMString s = Value( Expression::evaluationContext().node ).toString(); 00647 return Value( double( s.length() ) ); 00648 } 00649 00650 return Value( double( arg( 0 )->evaluate().toString().length() ) ); 00651 } 00652 00653 Value FunNormalizeSpace::doEvaluate() const 00654 { 00655 if ( argCount() == 0 ) { 00656 DOMString s = Value( Expression::evaluationContext().node ).toString(); 00657 return Value( DOMString( s.string().simplified() ) ); 00658 } 00659 00660 QString s = arg( 0 )->evaluate().toString().string(); 00661 s = s.simplified(); 00662 return Value( DOMString( s ) ); 00663 } 00664 00665 Value FunTranslate::doEvaluate() const 00666 { 00667 QString s1 = arg( 0 )->evaluate().toString().string(); 00668 QString s2 = arg( 1 )->evaluate().toString().string(); 00669 QString s3 = arg( 2 )->evaluate().toString().string(); 00670 QString newString; 00671 00672 for ( int i1 = 0; i1 < s1.length(); ++i1 ) { 00673 QChar ch = s1[ i1 ]; 00674 int i2 = s2.indexOf( ch ); 00675 if ( i2 == -1 ) { 00676 newString += ch; 00677 } else if ( i2 < s3.length() ) { 00678 newString += s3[ i2 ]; 00679 } 00680 } 00681 00682 return Value( DOMString( newString ) ); 00683 } 00684 00685 Value FunBoolean::doEvaluate() const 00686 { 00687 return Value( arg( 0 )->evaluate().toBoolean() ); 00688 } 00689 00690 Value FunNot::doEvaluate() const 00691 { 00692 return Value( !arg( 0 )->evaluate().toBoolean() ); 00693 } 00694 00695 Value FunTrue::doEvaluate() const 00696 { 00697 return Value( true ); 00698 } 00699 00700 bool FunTrue::isConstant() const 00701 { 00702 return true; 00703 } 00704 00705 #ifdef __GNUC__ 00706 #warning "This looks bogus" 00707 #endif 00708 00709 Value FunLang::doEvaluate() const 00710 { 00711 QString lang = arg( 0 )->evaluate().toString().string(); 00712 00713 NodeImpl* node = evaluationContext().node; 00714 00715 DOMString langNodeValue; 00716 00717 while ( node ) { 00718 if (node->isElementNode()) { 00719 langNodeValue = static_cast<ElementImpl*>(node)->getAttribute("xml:lang"); 00720 if ( !langNodeValue.isNull() ) 00721 break; 00722 } 00723 node = xpathParentNode( node ); 00724 } 00725 00726 if ( langNodeValue.isNull() ) { 00727 return Value( false ); 00728 } 00729 00730 // extract 'en' out of 'en-us' 00731 QString langNodeValueString = langNodeValue.string(); 00732 QString langNodeBaseString = langNodeValueString.left( langNodeValueString.indexOf( '-' ) ); 00733 00734 return Value( langNodeValueString.toLower() == lang.toLower() || 00735 langNodeBaseString.toLower() == lang.toLower() ); 00736 } 00737 00738 bool FunLang::isConstant() const 00739 { 00740 return false; 00741 } 00742 00743 Value FunFalse::doEvaluate() const 00744 { 00745 return Value( false ); 00746 } 00747 00748 bool FunFalse::isConstant() const 00749 { 00750 return true; 00751 } 00752 00753 Value FunNumber::doEvaluate() const 00754 { 00755 Value vi; 00756 if ( argCount() == 0 ) { 00757 // Spec'd: convert context node to singleton nodeset, call 00758 // string on that --> that's just stringValue on that node. 00759 // then we call number on that string 00760 vi = Value(stringValue(evaluationContext().node)); 00761 } else { 00762 vi = arg( 0 )->evaluate(); 00763 } 00764 00765 return Value( vi.toNumber() ); 00766 } 00767 00768 Value FunSum::doEvaluate() const 00769 { 00770 Value a = arg( 0 )->evaluate(); 00771 if ( !a.isNodeset() ) { 00772 Expression::reportInvalidExpressionErr(); 00773 kWarning() << "sum() expects <nodeset>"; 00774 return Value( 0.0 ); 00775 } 00776 00777 double sum = 0.0; 00778 const DomNodeList nodes = a.toNodeset(); 00779 for (unsigned long n = 0; n < nodes->length(); ++n) { 00780 NodeImpl* node = nodes->item(n); 00781 sum += Value( stringValue( node ) ).toNumber(); 00782 } 00783 return Value( sum ); 00784 } 00785 00786 Value FunFloor::doEvaluate() const 00787 { 00788 const double num = arg( 0 )->evaluate().toNumber(); 00789 00790 if ( KJS::isNaN( num ) || KJS::isInf( num ) ) { 00791 return Value( num ); 00792 } 00793 00794 return Value( floor( num ) ); 00795 } 00796 00797 Value FunCeiling::doEvaluate() const 00798 { 00799 const double num = arg( 0 )->evaluate().toNumber(); 00800 00801 if ( KJS::isNaN( num ) || KJS::isInf( num ) ) { 00802 return Value( num ); 00803 } 00804 00805 return Value( ceil( num ) ); 00806 } 00807 00808 Value FunRound::doEvaluate() const 00809 { 00810 return Value( double( qRound( arg( 0 )->evaluate().toNumber() ) ) ); 00811 } 00812 00813 struct FunctionLibrary::FunctionRec 00814 { 00815 typedef Function *(*FactoryFn )(); 00816 00817 FactoryFn factoryFn; 00818 Interval args; 00819 }; 00820 00821 struct FunctionMapping 00822 { 00823 const char *name; 00824 FunctionLibrary::FunctionRec function; 00825 }; 00826 00827 static FunctionMapping functions[] = { 00828 { "last", { &createFunLast, 0 } }, 00829 { "last", { &createFunLast, 0 } }, 00830 { "position", { &createFunPosition, 0 } }, 00831 { "count", { &createFunCount, 1 } }, 00832 { "sum", { &createFunSum, 1 } }, 00833 { "local-name", { &createFunLocalName, Interval( 0, 1 ) } }, 00834 { "namespace-uri", { &createFunNamespaceURI, Interval( 0, 1 ) } }, 00835 { "id", { &createFunId, 1 } }, 00836 { "name", { &createFunName, Interval( 0, 1 ) } }, 00837 00838 00839 { "string", { &createFunString, Interval( 0, 1 ) } }, 00840 { "concat", { &createFunConcat, Interval( 2, Interval::Inf ) } }, 00841 { "starts-with", { &createFunStartsWith, 2 } }, 00842 { "contains", { &createFunContains, 2 } }, 00843 { "substring-before", { &createFunSubstringBefore, 2 } }, 00844 { "substring-after", { &createFunSubstringAfter, 2 } }, 00845 { "substring", { &createFunSubstring, Interval( 2, 3 ) } }, 00846 { "string-length", { &createFunStringLength, Interval( 0, 1 ) } }, 00847 { "normalize-space", { &createFunNormalizeSpace, Interval( 0, 1 ) } }, 00848 { "translate", { &createFunTranslate, 3 } }, 00849 00850 { "boolean", { &createFunBoolean, 1 } }, 00851 { "not", { &createFunNot, 1 } }, 00852 { "true", { &createFunTrue, 0 } }, 00853 { "false", { &createFunFalse, 0 } }, 00854 { "lang", { &createFunLang, 1 } }, 00855 00856 { "number", { &createFunNumber, Interval( 0, 1 ) } }, 00857 { "floor", { &createFunFloor, 1 } }, 00858 { "ceiling", { &createFunCeiling, 1 } }, 00859 { "round", { &createFunRound, 1 } } 00860 }; 00861 static const unsigned int numFunctions = sizeof( functions ) / sizeof( functions[ 0 ] ); 00862 00863 FunctionLibrary &FunctionLibrary::self() 00864 { 00865 static FunctionLibrary instance; 00866 return instance; 00867 } 00868 00869 FunctionLibrary::FunctionLibrary() 00870 { 00871 for ( unsigned int i = 0; i < numFunctions; ++i ) { 00872 m_functionDict.insert( functions[ i ].name, functions[ i ].function ); 00873 } 00874 } 00875 00876 Function *FunctionLibrary::getFunction( const DOM::DOMString& name, 00877 const QList<Expression *> &args ) const 00878 { 00879 if ( !m_functionDict.contains( name ) ) { 00880 kWarning() << "Function '" << name << "' not supported by this implementation."; 00881 00882 return 0; 00883 } 00884 00885 FunctionRec functionRec = m_functionDict[ name ]; 00886 if ( !functionRec.args.contains( args.count() ) ) { 00887 kWarning() << "Function '" << name << "' requires " << functionRec.args.asString() << " arguments, but " << args.count() << " given."; 00888 return 0; 00889 } 00890 00891 Function *function = functionRec.factoryFn(); 00892 function->setArguments( args ); 00893 function->setName( name ); 00894 return function; 00895 } 00896 00897 } //namespace XPath 00898 } //namespace khtml 00899 00900 // kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;
KDE 4.6 API Reference