2 * Copyright 2005 Frerich Raabe <raabe@kde.org>
3 * Copyright (C) 2006 Apple Computer, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 #include "XPathFunctions.h"
32 #include "NamedAttrMap.h"
33 #include "XPathValue.h"
34 #include <wtf/MathExtras.h>
39 #define DEFINE_FUNCTION_CREATOR(Class) static Function* create##Class() { return new Class; }
43 static const int Inf = -1;
47 Interval(int min, int max);
49 bool contains(int value) const;
57 typedef Function *(*FactoryFn)();
62 static HashMap<String, FunctionRec>* functionMap;
64 class FunLast : public Function {
65 virtual bool isConstant() const;
66 virtual Value doEvaluate() const;
69 class FunPosition : public Function {
70 virtual bool isConstant() const;
71 virtual Value doEvaluate() const;
74 class FunCount : public Function {
75 virtual bool isConstant() const;
76 virtual Value doEvaluate() const;
79 class FunLocalName : public Function {
80 virtual bool isConstant() const;
81 virtual Value doEvaluate() const;
84 class FunNamespaceURI : public Function {
85 virtual bool isConstant() const;
86 virtual Value doEvaluate() const;
89 class FunName : public Function {
90 virtual bool isConstant() const;
91 virtual Value doEvaluate() const;
94 class FunString : public Function {
95 virtual Value doEvaluate() const;
98 class FunConcat : public Function {
99 virtual Value doEvaluate() const;
102 class FunStartsWith : public Function {
103 virtual Value doEvaluate() const;
106 class FunContains : public Function {
107 virtual Value doEvaluate() const;
110 class FunSubstringBefore : public Function {
111 virtual Value doEvaluate() const;
114 class FunSubstringAfter : public Function {
115 virtual Value doEvaluate() const;
118 class FunSubstring : public Function {
119 virtual Value doEvaluate() const;
122 class FunStringLength : public Function {
123 virtual Value doEvaluate() const;
126 class FunNormalizeSpace : public Function {
127 virtual Value doEvaluate() const;
130 class FunTranslate : public Function {
131 virtual Value doEvaluate() const;
134 class FunBoolean : public Function {
135 virtual Value doEvaluate() const;
138 class FunNot : public Function {
139 virtual Value doEvaluate() const;
142 class FunTrue : public Function {
143 virtual bool isConstant() const;
144 virtual Value doEvaluate() const;
147 class FunFalse : public Function {
148 virtual bool isConstant() const;
149 virtual Value doEvaluate() const;
152 class FunLang : public Function {
153 virtual bool isConstant() const;
154 virtual Value doEvaluate() const;
157 class FunNumber : public Function {
158 virtual Value doEvaluate() const;
161 class FunSum : public Function {
162 virtual Value doEvaluate() const;
165 class FunFloor : public Function {
166 virtual Value doEvaluate() const;
169 class FunCeiling : public Function {
170 virtual Value doEvaluate() const;
173 class FunRound : public Function {
174 virtual Value doEvaluate() const;
177 DEFINE_FUNCTION_CREATOR(FunLast)
178 DEFINE_FUNCTION_CREATOR(FunPosition)
179 DEFINE_FUNCTION_CREATOR(FunCount)
180 DEFINE_FUNCTION_CREATOR(FunLocalName)
181 DEFINE_FUNCTION_CREATOR(FunNamespaceURI)
182 DEFINE_FUNCTION_CREATOR(FunName)
184 DEFINE_FUNCTION_CREATOR(FunString)
185 DEFINE_FUNCTION_CREATOR(FunConcat)
186 DEFINE_FUNCTION_CREATOR(FunStartsWith)
187 DEFINE_FUNCTION_CREATOR(FunContains)
188 DEFINE_FUNCTION_CREATOR(FunSubstringBefore)
189 DEFINE_FUNCTION_CREATOR(FunSubstringAfter)
190 DEFINE_FUNCTION_CREATOR(FunSubstring)
191 DEFINE_FUNCTION_CREATOR(FunStringLength)
192 DEFINE_FUNCTION_CREATOR(FunNormalizeSpace)
193 DEFINE_FUNCTION_CREATOR(FunTranslate)
195 DEFINE_FUNCTION_CREATOR(FunBoolean)
196 DEFINE_FUNCTION_CREATOR(FunNot)
197 DEFINE_FUNCTION_CREATOR(FunTrue)
198 DEFINE_FUNCTION_CREATOR(FunFalse)
199 DEFINE_FUNCTION_CREATOR(FunLang)
201 DEFINE_FUNCTION_CREATOR(FunNumber)
202 DEFINE_FUNCTION_CREATOR(FunSum)
203 DEFINE_FUNCTION_CREATOR(FunFloor)
204 DEFINE_FUNCTION_CREATOR(FunCeiling)
205 DEFINE_FUNCTION_CREATOR(FunRound)
207 #undef DEFINE_FUNCTION_CREATOR
209 inline Interval::Interval()
210 : m_min(Inf), m_max(Inf)
214 inline Interval::Interval(int value)
215 : m_min(value), m_max(value)
219 inline Interval::Interval(int min, int max)
220 : m_min(min), m_max(max)
224 inline bool Interval::contains(int value) const
226 if (m_min == Inf && m_max == Inf)
230 return value <= m_max;
233 return value >= m_min;
235 return value >= m_min && value <= m_max;
238 void Function::setArguments(const Vector<Expression*>& args)
240 Vector<Expression*>::const_iterator end = args.end();
242 for (Vector<Expression*>::const_iterator it = args.begin(); it != end; it++)
243 addSubExpression(*it);
246 void Function::setName(const String& name)
251 Expression* Function::arg(int i)
256 const Expression* Function::arg(int i) const
261 unsigned int Function::argCount() const
263 return subExprCount();
266 String Function::name() const
271 Value FunLast::doEvaluate() const
273 return Expression::evaluationContext().size;
276 bool FunLast::isConstant() const
281 Value FunPosition::doEvaluate() const
283 return Expression::evaluationContext().position;
286 bool FunPosition::isConstant() const
291 bool FunLocalName::isConstant() const
296 Value FunLocalName::doEvaluate() const
299 if (argCount() > 0) {
300 Value a = arg(0)->evaluate();
301 if (!a.isNodeVector() || a.toNodeVector().size() == 0)
304 node = a.toNodeVector()[0].get();
308 node = evaluationContext().node.get();
310 return Value(node->localName());
313 bool FunNamespaceURI::isConstant() const
318 Value FunNamespaceURI::doEvaluate() const
321 if (argCount() > 0) {
322 Value a = arg(0)->evaluate();
323 if (!a.isNodeVector() || a.toNodeVector().size() == 0)
326 node = a.toNodeVector()[0].get();
330 node = evaluationContext().node.get();
332 return Value(node->namespaceURI());
335 bool FunName::isConstant() const
340 Value FunName::doEvaluate() const
343 if (argCount() > 0) {
344 Value a = arg(0)->evaluate();
345 if (!a.isNodeVector() || a.toNodeVector().size() == 0)
348 node = a.toNodeVector()[0].get();
352 node = evaluationContext().node.get();
354 const AtomicString& prefix = node->prefix();
355 return prefix.isEmpty() ? node->localName().domString() : node->prefix() + ":" + node->localName();
358 Value FunCount::doEvaluate() const
360 Value a = arg(0)->evaluate();
362 if (!a.isNodeVector())
365 return a.toNodeVector().size();
368 bool FunCount::isConstant() const
373 Value FunString::doEvaluate() const
376 return Value(Expression::evaluationContext().node).toString();
377 return arg(0)->evaluate().toString();
380 Value FunConcat::doEvaluate() const
384 for (unsigned i = 0; i < argCount(); ++i)
385 str += arg(i)->evaluate().toString();
390 Value FunStartsWith::doEvaluate() const
392 String s1 = arg(0)->evaluate().toString();
393 String s2 = arg(1)->evaluate().toString();
398 return s1.startsWith(s2);
401 Value FunContains::doEvaluate() const
403 String s1 = arg(0)->evaluate().toString();
404 String s2 = arg(1)->evaluate().toString();
409 return s1.contains(s2) != 0;
412 Value FunSubstringBefore::doEvaluate() const
414 String s1 = arg(0)->evaluate().toString();
415 String s2 = arg(1)->evaluate().toString();
428 Value FunSubstringAfter::doEvaluate() const
430 String s1 = arg(0)->evaluate().toString();
431 String s2 = arg(1)->evaluate().toString();
440 return s1.substring(i + 1);
443 Value FunSubstring::doEvaluate() const
445 String s = arg(0)->evaluate().toString();
446 long pos = lround(arg(1)->evaluate().toNumber());
447 bool haveLength = argCount() == 3;
450 len = lround(arg(2)->evaluate().toNumber());
452 if (pos > long(s.length()))
455 if (haveLength && pos < 1) {
462 return s.substring(pos - 1, len);
465 Value FunStringLength::doEvaluate() const
468 return Value(Expression::evaluationContext().node).toString().length();
469 return arg(0)->evaluate().toString().length();
472 Value FunNormalizeSpace::doEvaluate() const
474 if (argCount() == 0) {
475 String s = Value(Expression::evaluationContext().node).toString();
476 return Value(s.simplifyWhiteSpace());
479 String s = arg(0)->evaluate().toString();
480 return Value(s.simplifyWhiteSpace());
483 Value FunTranslate::doEvaluate() const
485 String s1 = arg(0)->evaluate().toString();
486 String s2 = arg(1)->evaluate().toString();
487 String s3 = arg(2)->evaluate().toString();
490 // FIXME: Building a String a character at a time is quite slow.
491 for (unsigned i1 = 0; i1 < s1.length(); ++i1) {
493 int i2 = s2.find(ch);
496 newString += String(&ch, 1);
497 else if ((unsigned)i2 < s3.length()) {
499 newString += String(&c2, 1);
506 Value FunBoolean::doEvaluate() const
508 return arg(0)->evaluate().toBoolean();
511 Value FunNot::doEvaluate() const
513 return !arg(0)->evaluate().toBoolean();
516 Value FunTrue::doEvaluate() const
521 bool FunTrue::isConstant() const
526 Value FunLang::doEvaluate() const
528 String lang = arg(0)->evaluate().toString();
530 RefPtr<Node> langNode = 0;
531 Node* node = evaluationContext().node.get();
532 String xmsnsURI = node->lookupNamespaceURI("xms");
534 NamedAttrMap* attrs = node->attributes();
535 langNode = attrs->getNamedItemNS(xmsnsURI, "lang");
538 node = node->parentNode();
544 String langNodeValue = langNode->nodeValue();
546 // extract 'en' out of 'en-us'
547 int index = langNodeValue.find('-');
549 langNodeValue = langNodeValue.left(index);
551 return equalIgnoringCase(langNodeValue, lang);
554 bool FunLang::isConstant() const
559 Value FunFalse::doEvaluate() const
564 bool FunFalse::isConstant() const
569 Value FunNumber::doEvaluate() const
571 return arg(0)->evaluate().toNumber();
574 Value FunSum::doEvaluate() const
576 Value a = arg(0)->evaluate();
577 if (!a.isNodeVector())
581 NodeVector nodes = a.toNodeVector();
583 for (unsigned i = 0; i < nodes.size(); i++)
584 sum += Value(stringValue(nodes[i].get())).toNumber();
589 Value FunFloor::doEvaluate() const
591 return floor(arg(0)->evaluate().toNumber());
594 Value FunCeiling::doEvaluate() const
596 return ceil(arg(0)->evaluate().toNumber());
599 Value FunRound::doEvaluate() const
601 return round(arg(0)->evaluate().toNumber());
604 static void createFunctionMap()
606 struct FunctionMapping {
608 FunctionRec function;
610 static const FunctionMapping functions[] = {
611 { "boolean", { &createFunBoolean, 1 } },
612 { "ceiling", { &createFunCeiling, 1 } },
613 { "concat", { &createFunConcat, Interval(2, Interval::Inf) } },
614 { "contains", { &createFunContains, 2 } },
615 { "count", { &createFunCount, 1 } },
616 { "false", { &createFunFalse, 0 } },
617 { "floor", { &createFunFloor, 1 } },
618 { "lang", { &createFunLang, 1 } },
619 { "last", { &createFunLast, 0 } },
620 { "local-name", { &createFunLocalName, Interval(0, 1) } },
621 { "name", { &createFunName, Interval(0, 1) } },
622 { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } },
623 { "normalize-space", { &createFunNormalizeSpace, 1 } },
624 { "not", { &createFunNot, 1 } },
625 { "number", { &createFunNumber, 1 } },
626 { "position", { &createFunPosition, 0 } },
627 { "round", { &createFunRound, 1 } },
628 { "starts-with", { &createFunStartsWith, 2 } },
629 { "string", { &createFunString, Interval(0, 1) } },
630 { "string-length", { &createFunStringLength, 1 } },
631 { "substring", { &createFunSubstring, Interval(2, 3) } },
632 { "substring-after", { &createFunSubstringAfter, 2 } },
633 { "substring-before", { &createFunSubstringBefore, 2 } },
634 { "sum", { &createFunSum, 1 } },
635 { "translate", { &createFunTranslate, 3 } },
636 { "true", { &createFunTrue, 0 } },
638 const unsigned int numFunctions = sizeof(functions) / sizeof(functions[0]);
640 functionMap = new HashMap<String, FunctionRec>;
641 for (unsigned i = 0; i < numFunctions; ++i)
642 functionMap->set(functions[i].name, functions[i].function);
645 Function* createFunction(const String& name, const Vector<Expression*>& args)
650 if (!functionMap->contains(name)) {
651 deleteAllValues(args);
653 // Return a dummy function instead of 0.
654 Function* funcTrue = functionMap->get("true").factoryFn();
655 funcTrue->setName("true");
659 FunctionRec functionRec = functionMap->get(name);
660 if (!functionRec.args.contains(args.size())) {
661 deleteAllValues(args);
665 Function* function = functionRec.factoryFn();
666 function->setArguments(args);
667 function->setName(name);
674 #endif // XPATH_SUPPORT