Warning, file /frameworks/khtml/src/xpath/functions.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 * functions.cc - Copyright 2005 Frerich Raabe <raabe@kde.org> 0003 * 0004 * Redistribution and use in source and binary forms, with or without 0005 * modification, are permitted provided that the following conditions 0006 * are met: 0007 * 0008 * 1. Redistributions of source code must retain the above copyright 0009 * notice, this list of conditions and the following disclaimer. 0010 * 2. Redistributions in binary form must reproduce the above copyright 0011 * notice, this list of conditions and the following disclaimer in the 0012 * documentation and/or other materials provided with the distribution. 0013 * 0014 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0015 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0016 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0017 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0018 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0019 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0020 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0021 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0022 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0023 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0024 */ 0025 #include "functions.h" 0026 0027 #include "xml/dom_docimpl.h" 0028 #include "xml/dom_nodeimpl.h" 0029 #include "xml/dom_nodelistimpl.h" 0030 #include "xml/dom_elementimpl.h" 0031 #include "kjs/operations.h" 0032 0033 #include <QtDebug> 0034 0035 #include <math.h> 0036 0037 using namespace DOM; 0038 0039 namespace khtml 0040 { 0041 namespace XPath 0042 { 0043 0044 #define DEFINE_FUNCTION_CREATOR(Class) \ 0045 static Function *create##Class() { return new Class; } 0046 0047 class Interval 0048 { 0049 public: 0050 static const int Inf = -1; 0051 0052 Interval(); 0053 Interval(int value); 0054 Interval(int min, int max); 0055 0056 bool contains(int value) const; 0057 0058 QString asString() const; 0059 0060 private: 0061 int m_min; 0062 int m_max; 0063 }; 0064 0065 class FunLast : public Function 0066 { 0067 public: 0068 bool isConstant() const override; 0069 0070 private: 0071 Value doEvaluate() const override; 0072 }; 0073 0074 class FunPosition : public Function 0075 { 0076 public: 0077 bool isConstant() const override; 0078 0079 private: 0080 Value doEvaluate() const override; 0081 }; 0082 0083 class FunCount : public Function 0084 { 0085 public: 0086 bool isConstant() const override; 0087 0088 private: 0089 Value doEvaluate() const override; 0090 }; 0091 0092 // Base for various node-property functions, that have 0093 // the same node picking logic. It passes the proper node, 0094 // if any, or otherwise returns an empty string by itself 0095 class NodeFunction : public Function 0096 { 0097 private: 0098 Value doEvaluate() const override; 0099 virtual Value evaluateOnNode(DOM::NodeImpl *node) const = 0; 0100 }; 0101 0102 class FunLocalName : public NodeFunction 0103 { 0104 public: 0105 bool isConstant() const override; 0106 0107 private: 0108 Value evaluateOnNode(DOM::NodeImpl *node) const override; 0109 }; 0110 0111 class FunNamespaceURI : public NodeFunction 0112 { 0113 public: 0114 bool isConstant() const override; 0115 0116 private: 0117 Value evaluateOnNode(DOM::NodeImpl *node) const override; 0118 }; 0119 0120 class FunName : public NodeFunction 0121 { 0122 public: 0123 bool isConstant() const override; 0124 0125 private: 0126 Value evaluateOnNode(DOM::NodeImpl *node) const override; 0127 }; 0128 0129 class FunId : public Function 0130 { 0131 private: 0132 Value doEvaluate() const override; 0133 }; 0134 0135 class FunString : public Function 0136 { 0137 private: 0138 Value doEvaluate() const override; 0139 }; 0140 0141 class FunConcat : public Function 0142 { 0143 private: 0144 Value doEvaluate() const override; 0145 }; 0146 0147 class FunStartsWith : public Function 0148 { 0149 private: 0150 Value doEvaluate() const override; 0151 }; 0152 0153 class FunContains : public Function 0154 { 0155 private: 0156 Value doEvaluate() const override; 0157 }; 0158 0159 class FunSubstringBefore : public Function 0160 { 0161 private: 0162 Value doEvaluate() const override; 0163 }; 0164 0165 class FunSubstringAfter : public Function 0166 { 0167 private: 0168 Value doEvaluate() const override; 0169 }; 0170 0171 class FunSubstring : public Function 0172 { 0173 private: 0174 Value doEvaluate() const override; 0175 }; 0176 0177 class FunStringLength : public Function 0178 { 0179 private: 0180 Value doEvaluate() const override; 0181 }; 0182 0183 class FunNormalizeSpace : public Function 0184 { 0185 private: 0186 Value doEvaluate() const override; 0187 }; 0188 0189 class FunTranslate : public Function 0190 { 0191 private: 0192 Value doEvaluate() const override; 0193 }; 0194 0195 class FunBoolean : public Function 0196 { 0197 private: 0198 Value doEvaluate() const override; 0199 }; 0200 0201 class FunNot : public Function 0202 { 0203 private: 0204 Value doEvaluate() const override; 0205 }; 0206 0207 class FunTrue : public Function 0208 { 0209 public: 0210 bool isConstant() const override; 0211 0212 private: 0213 Value doEvaluate() const override; 0214 }; 0215 0216 class FunFalse : public Function 0217 { 0218 public: 0219 bool isConstant() const override; 0220 0221 private: 0222 Value doEvaluate() const override; 0223 }; 0224 0225 class FunLang : public Function 0226 { 0227 public: 0228 bool isConstant() const override; 0229 0230 private: 0231 Value doEvaluate() const override; 0232 }; 0233 0234 class FunNumber : public Function 0235 { 0236 private: 0237 Value doEvaluate() const override; 0238 }; 0239 0240 class FunSum : public Function 0241 { 0242 private: 0243 Value doEvaluate() const override; 0244 }; 0245 0246 class FunFloor : public Function 0247 { 0248 private: 0249 Value doEvaluate() const override; 0250 }; 0251 0252 class FunCeiling : public Function 0253 { 0254 private: 0255 Value doEvaluate() const override; 0256 }; 0257 0258 class FunRound : public Function 0259 { 0260 private: 0261 Value doEvaluate() const override; 0262 }; 0263 0264 DEFINE_FUNCTION_CREATOR(FunLast) 0265 DEFINE_FUNCTION_CREATOR(FunPosition) 0266 DEFINE_FUNCTION_CREATOR(FunCount) 0267 DEFINE_FUNCTION_CREATOR(FunLocalName) 0268 DEFINE_FUNCTION_CREATOR(FunNamespaceURI) 0269 DEFINE_FUNCTION_CREATOR(FunName) 0270 DEFINE_FUNCTION_CREATOR(FunId) 0271 0272 DEFINE_FUNCTION_CREATOR(FunString) 0273 DEFINE_FUNCTION_CREATOR(FunConcat) 0274 DEFINE_FUNCTION_CREATOR(FunStartsWith) 0275 DEFINE_FUNCTION_CREATOR(FunContains) 0276 DEFINE_FUNCTION_CREATOR(FunSubstringBefore) 0277 DEFINE_FUNCTION_CREATOR(FunSubstringAfter) 0278 DEFINE_FUNCTION_CREATOR(FunSubstring) 0279 DEFINE_FUNCTION_CREATOR(FunStringLength) 0280 DEFINE_FUNCTION_CREATOR(FunNormalizeSpace) 0281 DEFINE_FUNCTION_CREATOR(FunTranslate) 0282 0283 DEFINE_FUNCTION_CREATOR(FunBoolean) 0284 DEFINE_FUNCTION_CREATOR(FunNot) 0285 DEFINE_FUNCTION_CREATOR(FunTrue) 0286 DEFINE_FUNCTION_CREATOR(FunFalse) 0287 DEFINE_FUNCTION_CREATOR(FunLang) 0288 0289 DEFINE_FUNCTION_CREATOR(FunNumber) 0290 DEFINE_FUNCTION_CREATOR(FunSum) 0291 DEFINE_FUNCTION_CREATOR(FunFloor) 0292 DEFINE_FUNCTION_CREATOR(FunCeiling) 0293 DEFINE_FUNCTION_CREATOR(FunRound) 0294 0295 #undef DEFINE_FUNCTION_CREATOR 0296 0297 Interval::Interval() 0298 : m_min(Inf), 0299 m_max(Inf) 0300 { 0301 } 0302 0303 Interval::Interval(int value) 0304 : m_min(value), 0305 m_max(value) 0306 { 0307 } 0308 0309 Interval::Interval(int min, int max) 0310 : m_min(min), 0311 m_max(max) 0312 { 0313 } 0314 0315 bool Interval::contains(int value) const 0316 { 0317 if (m_min == Inf && m_max == Inf) { 0318 return true; 0319 } 0320 0321 if (m_min == Inf) { 0322 return value <= m_max; 0323 } 0324 0325 if (m_max == Inf) { 0326 return value >= m_min; 0327 } 0328 0329 return value >= m_min && value <= m_max; 0330 } 0331 0332 QString Interval::asString() const 0333 { 0334 QString s = "["; 0335 0336 if (m_min == Inf) { 0337 s += "-Infinity"; 0338 } else { 0339 s += QString::number(m_min); 0340 } 0341 0342 s += ".."; 0343 0344 if (m_max == Inf) { 0345 s += "Infinity"; 0346 } else { 0347 s += QString::number(m_max); 0348 } 0349 0350 s += "]"; 0351 0352 return s; 0353 } 0354 0355 void Function::setArguments(const QList<Expression *> &args) 0356 { 0357 foreach (Expression *arg, args) { 0358 addSubExpression(arg); 0359 } 0360 } 0361 0362 void Function::setName(const DOM::DOMString &name) 0363 { 0364 m_name = name; 0365 } 0366 0367 QString Function::dump() const 0368 { 0369 if (argCount() == 0) { 0370 return QString("<function name=\"%1\"/>").arg(name().string()); 0371 } 0372 0373 QString s = QString("<function name=\"%1\">").arg(name().string()); 0374 for (unsigned int i = 0; i < argCount(); ++i) { 0375 s += "<operand>" + arg(i)->dump() + "</operand>"; 0376 } 0377 s += "</function>"; 0378 return s; 0379 } 0380 0381 Expression *Function::arg(int i) 0382 { 0383 return subExpr(i); 0384 } 0385 0386 const Expression *Function::arg(int i) const 0387 { 0388 return subExpr(i); 0389 } 0390 0391 unsigned int Function::argCount() const 0392 { 0393 return subExprCount(); 0394 } 0395 0396 DOM::DOMString Function::name() const 0397 { 0398 return m_name; 0399 } 0400 0401 Value FunLast::doEvaluate() const 0402 { 0403 return Value(double(Expression::evaluationContext().size)); 0404 } 0405 0406 bool FunLast::isConstant() const 0407 { 0408 return false; 0409 } 0410 0411 Value FunPosition::doEvaluate() const 0412 { 0413 return Value(double(Expression::evaluationContext().position)); 0414 } 0415 0416 bool FunPosition::isConstant() const 0417 { 0418 return false; 0419 } 0420 0421 Value NodeFunction::doEvaluate() const 0422 { 0423 NodeImpl *node = nullptr; 0424 if (argCount() > 0) { 0425 Value a = arg(0)->evaluate(); 0426 if (a.isNodeset() && a.toNodeset()->length()) { 0427 node = a.toNodeset()->first(); 0428 } 0429 } else { 0430 // no argument -> default to context node 0431 node = evaluationContext().node; 0432 } 0433 0434 if (!node) { 0435 return Value(DOMString()); 0436 } 0437 0438 return evaluateOnNode(node); 0439 } 0440 0441 bool FunLocalName::isConstant() const 0442 { 0443 return false; 0444 } 0445 0446 Value FunLocalName::evaluateOnNode(DOM::NodeImpl *node) const 0447 { 0448 DOM::DOMString n; 0449 switch (node->nodeType()) { 0450 case Node::PROCESSING_INSTRUCTION_NODE: 0451 n = node->nodeName(); // target name 0452 break; 0453 default: 0454 n = node->localName(); 0455 } 0456 return Value(n); 0457 } 0458 0459 bool FunNamespaceURI::isConstant() const 0460 { 0461 return false; 0462 } 0463 0464 Value FunNamespaceURI::evaluateOnNode(DOM::NodeImpl *node) const 0465 { 0466 return Value(node->namespaceURI()); 0467 } 0468 0469 Value FunId::doEvaluate() const 0470 { 0471 Value a = arg(0)->evaluate(); 0472 0473 WTF::Vector<DOM::DOMString> ids; 0474 0475 QString queryString; // whitespace-separated IDs 0476 if (a.isNodeset()) { 0477 DomNodeList set = a.toNodeset(); 0478 for (unsigned long i = 0; i < set->length(); ++i) { 0479 queryString += stringValue(set->item(i)).string() + QLatin1Char(' '); 0480 } 0481 } else { 0482 queryString = a.toString().string(); 0483 } 0484 0485 QStringList qids = queryString.simplified().split(' '); 0486 for (int i = 0; i < qids.size(); ++i) { 0487 ids.append(DOM::DOMString(qids[i])); 0488 } 0489 0490 DomNodeList out = new StaticNodeListImpl(); 0491 DOM::DocumentImpl *doc = Expression::evaluationContext().node->document(); 0492 0493 for (unsigned i = 0; i < ids.size(); ++i) { 0494 DOM::ElementImpl *e = doc->getElementById(ids[i]); 0495 0496 if (e) { 0497 out->append(e); 0498 } 0499 } 0500 0501 return Value(out); 0502 } 0503 0504 bool FunName::isConstant() const 0505 { 0506 return false; 0507 } 0508 0509 Value FunName::evaluateOnNode(DOM::NodeImpl *node) const 0510 { 0511 DOM::DOMString n; 0512 switch (node->nodeType()) { 0513 case Node::TEXT_NODE: 0514 case Node::CDATA_SECTION_NODE: 0515 case Node::COMMENT_NODE: 0516 case Node::DOCUMENT_NODE: 0517 // All of these have an empty XPath name 0518 break; 0519 case Node::ELEMENT_NODE: { 0520 n = static_cast<DOM::ElementImpl *>(node)->nonCaseFoldedTagName(); 0521 break; 0522 } 0523 default: 0524 n = node->nodeName(); 0525 } 0526 return Value(n); 0527 } 0528 0529 Value FunCount::doEvaluate() const 0530 { 0531 Value a = arg(0)->evaluate(); 0532 if (!a.isNodeset()) { 0533 Expression::reportInvalidExpressionErr(); 0534 qCWarning(KHTML_LOG) << "count() expects <nodeset>"; 0535 return Value(); 0536 } 0537 a.toNodeset()->normalizeUpto(StaticNodeListImpl::AxisOrder); 0538 0539 return Value(double(a.toNodeset()->length())); 0540 } 0541 0542 bool FunCount::isConstant() const 0543 { 0544 return false; 0545 } 0546 0547 Value FunString::doEvaluate() const 0548 { 0549 if (argCount() == 0) { 0550 DOMString s = Value(Expression::evaluationContext().node).toString(); 0551 return Value(s); 0552 } 0553 return Value(arg(0)->evaluate().toString()); 0554 } 0555 0556 Value FunConcat::doEvaluate() const 0557 { 0558 QString str; 0559 for (unsigned int i = 0; i < argCount(); ++i) { 0560 str.append(arg(i)->evaluate().toString().string()); 0561 } 0562 return Value(DOMString(str)); 0563 } 0564 0565 Value FunStartsWith::doEvaluate() const 0566 { 0567 DOMString s1 = arg(0)->evaluate().toString(); 0568 DOMString s2 = arg(1)->evaluate().toString(); 0569 0570 if (s2.isEmpty()) { 0571 return Value(true); 0572 } 0573 0574 return Value(s1.startsWith(s2)); 0575 } 0576 0577 Value FunContains::doEvaluate() const 0578 { 0579 QString s1 = arg(0)->evaluate().toString().string(); 0580 QString s2 = arg(1)->evaluate().toString().string(); 0581 0582 if (s2.isEmpty()) { 0583 return Value(true); 0584 } 0585 0586 return Value(s1.contains(s2)); 0587 } 0588 0589 Value FunSubstringBefore::doEvaluate() const 0590 { 0591 QString s1 = arg(0)->evaluate().toString().string(); 0592 QString s2 = arg(1)->evaluate().toString().string(); 0593 0594 if (s2.isEmpty()) { 0595 return Value(DOMString()); 0596 } 0597 0598 int i = s1.indexOf(s2); 0599 if (i == -1) { 0600 return Value(DOMString()); 0601 } 0602 0603 return Value(DOMString(s1.left(i))); 0604 } 0605 0606 Value FunSubstringAfter::doEvaluate() const 0607 { 0608 QString s1 = arg(0)->evaluate().toString().string(); 0609 QString s2 = arg(1)->evaluate().toString().string(); 0610 0611 if (s2.isEmpty()) { 0612 return Value(s1); 0613 } 0614 0615 int i = s1.indexOf(s2); 0616 if (i == -1) { 0617 return Value(DOMString()); 0618 } 0619 0620 return Value(DOMString(s1.mid(i + s2.length()))); 0621 } 0622 0623 Value FunSubstring::doEvaluate() const 0624 { 0625 QString s = arg(0)->evaluate().toString().string(); 0626 long pos = long(qRound(arg(1)->evaluate().toNumber())); 0627 bool haveLength = argCount() == 3; 0628 long len = -1; 0629 if (haveLength) { 0630 len = long(qRound(arg(2)->evaluate().toNumber())); 0631 } 0632 0633 if (pos > long(s.length())) { 0634 return Value(DOMString()); 0635 } 0636 0637 if (haveLength && pos < 1) { 0638 len -= 1 - pos; 0639 pos = 1; 0640 if (len < 1) { 0641 return Value(DOMString()); 0642 } 0643 } 0644 0645 return Value(DOMString(s.mid(pos - 1, len))); 0646 } 0647 0648 Value FunStringLength::doEvaluate() const 0649 { 0650 if (argCount() == 0) { 0651 DOMString s = Value(Expression::evaluationContext().node).toString(); 0652 return Value(double(s.length())); 0653 } 0654 0655 return Value(double(arg(0)->evaluate().toString().length())); 0656 } 0657 0658 Value FunNormalizeSpace::doEvaluate() const 0659 { 0660 if (argCount() == 0) { 0661 DOMString s = Value(Expression::evaluationContext().node).toString(); 0662 return Value(DOMString(s.string().simplified())); 0663 } 0664 0665 QString s = arg(0)->evaluate().toString().string(); 0666 s = s.simplified(); 0667 return Value(DOMString(s)); 0668 } 0669 0670 Value FunTranslate::doEvaluate() const 0671 { 0672 QString s1 = arg(0)->evaluate().toString().string(); 0673 QString s2 = arg(1)->evaluate().toString().string(); 0674 QString s3 = arg(2)->evaluate().toString().string(); 0675 QString newString; 0676 0677 for (int i1 = 0; i1 < s1.length(); ++i1) { 0678 QChar ch = s1[ i1 ]; 0679 int i2 = s2.indexOf(ch); 0680 if (i2 == -1) { 0681 newString += ch; 0682 } else if (i2 < s3.length()) { 0683 newString += s3[ i2 ]; 0684 } 0685 } 0686 0687 return Value(DOMString(newString)); 0688 } 0689 0690 Value FunBoolean::doEvaluate() const 0691 { 0692 return Value(arg(0)->evaluate().toBoolean()); 0693 } 0694 0695 Value FunNot::doEvaluate() const 0696 { 0697 return Value(!arg(0)->evaluate().toBoolean()); 0698 } 0699 0700 Value FunTrue::doEvaluate() const 0701 { 0702 return Value(true); 0703 } 0704 0705 bool FunTrue::isConstant() const 0706 { 0707 return true; 0708 } 0709 0710 #ifdef __GNUC__ 0711 #warning "This looks bogus" 0712 #endif 0713 0714 Value FunLang::doEvaluate() const 0715 { 0716 QString lang = arg(0)->evaluate().toString().string(); 0717 0718 NodeImpl *node = evaluationContext().node; 0719 0720 DOMString langNodeValue; 0721 0722 while (node) { 0723 if (node->isElementNode()) { 0724 langNodeValue = static_cast<ElementImpl *>(node)->getAttribute("xml:lang"); 0725 if (!langNodeValue.isNull()) { 0726 break; 0727 } 0728 } 0729 node = xpathParentNode(node); 0730 } 0731 0732 if (langNodeValue.isNull()) { 0733 return Value(false); 0734 } 0735 0736 // extract 'en' out of 'en-us' 0737 QString langNodeValueString = langNodeValue.string(); 0738 QString langNodeBaseString = langNodeValueString.left(langNodeValueString.indexOf('-')); 0739 0740 return Value(langNodeValueString.toLower() == lang.toLower() || 0741 langNodeBaseString.toLower() == lang.toLower()); 0742 } 0743 0744 bool FunLang::isConstant() const 0745 { 0746 return false; 0747 } 0748 0749 Value FunFalse::doEvaluate() const 0750 { 0751 return Value(false); 0752 } 0753 0754 bool FunFalse::isConstant() const 0755 { 0756 return true; 0757 } 0758 0759 Value FunNumber::doEvaluate() const 0760 { 0761 Value vi; 0762 if (argCount() == 0) { 0763 // Spec'd: convert context node to singleton nodeset, call 0764 // string on that --> that's just stringValue on that node. 0765 // then we call number on that string 0766 vi = Value(stringValue(evaluationContext().node)); 0767 } else { 0768 vi = arg(0)->evaluate(); 0769 } 0770 0771 return Value(vi.toNumber()); 0772 } 0773 0774 Value FunSum::doEvaluate() const 0775 { 0776 Value a = arg(0)->evaluate(); 0777 if (!a.isNodeset()) { 0778 Expression::reportInvalidExpressionErr(); 0779 qCWarning(KHTML_LOG) << "sum() expects <nodeset>"; 0780 return Value(0.0); 0781 } 0782 0783 double sum = 0.0; 0784 const DomNodeList nodes = a.toNodeset(); 0785 for (unsigned long n = 0; n < nodes->length(); ++n) { 0786 NodeImpl *node = nodes->item(n); 0787 sum += Value(stringValue(node)).toNumber(); 0788 } 0789 return Value(sum); 0790 } 0791 0792 Value FunFloor::doEvaluate() const 0793 { 0794 const double num = arg(0)->evaluate().toNumber(); 0795 0796 if (KJS::isNaN(num) || KJS::isInf(num)) { 0797 return Value(num); 0798 } 0799 0800 return Value(floor(num)); 0801 } 0802 0803 Value FunCeiling::doEvaluate() const 0804 { 0805 const double num = arg(0)->evaluate().toNumber(); 0806 0807 if (KJS::isNaN(num) || KJS::isInf(num)) { 0808 return Value(num); 0809 } 0810 0811 return Value(ceil(num)); 0812 } 0813 0814 Value FunRound::doEvaluate() const 0815 { 0816 return Value(double(qRound(arg(0)->evaluate().toNumber()))); 0817 } 0818 0819 struct FunctionLibrary::FunctionRec { 0820 typedef Function *(*FactoryFn)(); 0821 0822 FactoryFn factoryFn; 0823 Interval args; 0824 }; 0825 0826 struct FunctionMapping { 0827 const char *name; 0828 FunctionLibrary::FunctionRec function; 0829 }; 0830 0831 static FunctionMapping functions[] = { 0832 { "last", { &createFunLast, 0 } }, 0833 { "last", { &createFunLast, 0 } }, 0834 { "position", { &createFunPosition, 0 } }, 0835 { "count", { &createFunCount, 1 } }, 0836 { "sum", { &createFunSum, 1 } }, 0837 { "local-name", { &createFunLocalName, Interval(0, 1) } }, 0838 { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } }, 0839 { "id", { &createFunId, 1 } }, 0840 { "name", { &createFunName, Interval(0, 1) } }, 0841 0842 { "string", { &createFunString, Interval(0, 1) } }, 0843 { "concat", { &createFunConcat, Interval(2, Interval::Inf) } }, 0844 { "starts-with", { &createFunStartsWith, 2 } }, 0845 { "contains", { &createFunContains, 2 } }, 0846 { "substring-before", { &createFunSubstringBefore, 2 } }, 0847 { "substring-after", { &createFunSubstringAfter, 2 } }, 0848 { "substring", { &createFunSubstring, Interval(2, 3) } }, 0849 { "string-length", { &createFunStringLength, Interval(0, 1) } }, 0850 { "normalize-space", { &createFunNormalizeSpace, Interval(0, 1) } }, 0851 { "translate", { &createFunTranslate, 3 } }, 0852 0853 { "boolean", { &createFunBoolean, 1 } }, 0854 { "not", { &createFunNot, 1 } }, 0855 { "true", { &createFunTrue, 0 } }, 0856 { "false", { &createFunFalse, 0 } }, 0857 { "lang", { &createFunLang, 1 } }, 0858 0859 { "number", { &createFunNumber, Interval(0, 1) } }, 0860 { "floor", { &createFunFloor, 1 } }, 0861 { "ceiling", { &createFunCeiling, 1 } }, 0862 { "round", { &createFunRound, 1 } } 0863 }; 0864 static const unsigned int numFunctions = sizeof(functions) / sizeof(functions[ 0 ]); 0865 0866 FunctionLibrary &FunctionLibrary::self() 0867 { 0868 static FunctionLibrary instance; 0869 return instance; 0870 } 0871 0872 FunctionLibrary::FunctionLibrary() 0873 { 0874 for (unsigned int i = 0; i < numFunctions; ++i) { 0875 m_functionDict.insert(functions[ i ].name, functions[ i ].function); 0876 } 0877 } 0878 0879 Function *FunctionLibrary::getFunction(const DOM::DOMString &name, 0880 const QList<Expression *> &args) const 0881 { 0882 if (!m_functionDict.contains(name)) { 0883 qCWarning(KHTML_LOG) << "Function '" << name << "' not supported by this implementation."; 0884 0885 return nullptr; 0886 } 0887 0888 FunctionRec functionRec = m_functionDict[ name ]; 0889 if (!functionRec.args.contains(args.count())) { 0890 qCWarning(KHTML_LOG) << "Function '" << name << "' requires " << functionRec.args.asString() << " arguments, but " << args.count() << " given."; 0891 return nullptr; 0892 } 0893 0894 Function *function = functionRec.factoryFn(); 0895 function->setArguments(args); 0896 function->setName(name); 0897 return function; 0898 } 0899 0900 } //namespace XPath 0901 } //namespace khtml 0902