2 * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
3 * Copyright (C) 2006, 2009 Apple Inc.
4 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "core/xml/XPathFunctions.h"
32 #include "core/dom/Attr.h"
33 #include "core/dom/Element.h"
34 #include "core/dom/ProcessingInstruction.h"
35 #include "core/dom/TreeScope.h"
36 #include "core/xml/XPathUtil.h"
37 #include "core/xml/XPathValue.h"
38 #include "wtf/MathExtras.h"
39 #include "wtf/text/StringBuilder.h"
44 static inline bool isWhitespace(UChar c)
46 return c == ' ' || c == '\n' || c == '\r' || c == '\t';
50 #define DEFINE_FUNCTION_CREATOR(Class) static Function* create##Class() { return new Class; }
54 static const int Inf = -1;
58 Interval(int min, int max);
60 bool contains(int value) const;
68 typedef Function *(*FactoryFn)();
73 static HashMap<String, FunctionRec>* functionMap;
75 class FunLast FINAL : public Function {
76 virtual Value evaluate() const OVERRIDE;
77 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
79 FunLast() { setIsContextSizeSensitive(true); }
82 class FunPosition FINAL : public Function {
83 virtual Value evaluate() const OVERRIDE;
84 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
86 FunPosition() { setIsContextPositionSensitive(true); }
89 class FunCount FINAL : public Function {
90 virtual Value evaluate() const OVERRIDE;
91 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
94 class FunId FINAL : public Function {
95 virtual Value evaluate() const OVERRIDE;
96 virtual Value::Type resultType() const OVERRIDE { return Value::NodeSetValue; }
99 class FunLocalName FINAL : public Function {
100 virtual Value evaluate() const OVERRIDE;
101 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
103 FunLocalName() { setIsContextNodeSensitive(true); } // local-name() with no arguments uses context node.
106 class FunNamespaceURI FINAL : public Function {
107 virtual Value evaluate() const OVERRIDE;
108 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
110 FunNamespaceURI() { setIsContextNodeSensitive(true); } // namespace-uri() with no arguments uses context node.
113 class FunName FINAL : public Function {
114 virtual Value evaluate() const OVERRIDE;
115 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
117 FunName() { setIsContextNodeSensitive(true); } // name() with no arguments uses context node.
120 class FunString FINAL : public Function {
121 virtual Value evaluate() const OVERRIDE;
122 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
124 FunString() { setIsContextNodeSensitive(true); } // string() with no arguments uses context node.
127 class FunConcat FINAL : public Function {
128 virtual Value evaluate() const OVERRIDE;
129 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
132 class FunStartsWith FINAL : public Function {
133 virtual Value evaluate() const OVERRIDE;
134 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
137 class FunContains FINAL : public Function {
138 virtual Value evaluate() const OVERRIDE;
139 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
142 class FunSubstringBefore FINAL : public Function {
143 virtual Value evaluate() const OVERRIDE;
144 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
147 class FunSubstringAfter FINAL : public Function {
148 virtual Value evaluate() const OVERRIDE;
149 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
152 class FunSubstring FINAL : public Function {
153 virtual Value evaluate() const OVERRIDE;
154 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
157 class FunStringLength FINAL : public Function {
158 virtual Value evaluate() const OVERRIDE;
159 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
161 FunStringLength() { setIsContextNodeSensitive(true); } // string-length() with no arguments uses context node.
164 class FunNormalizeSpace FINAL : public Function {
165 virtual Value evaluate() const OVERRIDE;
166 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
168 FunNormalizeSpace() { setIsContextNodeSensitive(true); } // normalize-space() with no arguments uses context node.
171 class FunTranslate FINAL : public Function {
172 virtual Value evaluate() const OVERRIDE;
173 virtual Value::Type resultType() const OVERRIDE { return Value::StringValue; }
176 class FunBoolean FINAL : public Function {
177 virtual Value evaluate() const OVERRIDE;
178 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
181 class FunNot FINAL : public Function {
182 virtual Value evaluate() const OVERRIDE;
183 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
186 class FunTrue FINAL : public Function {
187 virtual Value evaluate() const OVERRIDE;
188 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
191 class FunFalse FINAL : public Function {
192 virtual Value evaluate() const OVERRIDE;
193 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
196 class FunLang FINAL : public Function {
197 virtual Value evaluate() const OVERRIDE;
198 virtual Value::Type resultType() const OVERRIDE { return Value::BooleanValue; }
200 FunLang() { setIsContextNodeSensitive(true); } // lang() always works on context node.
203 class FunNumber FINAL : public Function {
204 virtual Value evaluate() const OVERRIDE;
205 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
207 FunNumber() { setIsContextNodeSensitive(true); } // number() with no arguments uses context node.
210 class FunSum FINAL : public Function {
211 virtual Value evaluate() const OVERRIDE;
212 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
215 class FunFloor FINAL : public Function {
216 virtual Value evaluate() const OVERRIDE;
217 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
220 class FunCeiling FINAL : public Function {
221 virtual Value evaluate() const OVERRIDE;
222 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
225 class FunRound FINAL : public Function {
226 virtual Value evaluate() const OVERRIDE;
227 virtual Value::Type resultType() const OVERRIDE { return Value::NumberValue; }
229 static double round(double);
232 DEFINE_FUNCTION_CREATOR(FunLast)
233 DEFINE_FUNCTION_CREATOR(FunPosition)
234 DEFINE_FUNCTION_CREATOR(FunCount)
235 DEFINE_FUNCTION_CREATOR(FunId)
236 DEFINE_FUNCTION_CREATOR(FunLocalName)
237 DEFINE_FUNCTION_CREATOR(FunNamespaceURI)
238 DEFINE_FUNCTION_CREATOR(FunName)
240 DEFINE_FUNCTION_CREATOR(FunString)
241 DEFINE_FUNCTION_CREATOR(FunConcat)
242 DEFINE_FUNCTION_CREATOR(FunStartsWith)
243 DEFINE_FUNCTION_CREATOR(FunContains)
244 DEFINE_FUNCTION_CREATOR(FunSubstringBefore)
245 DEFINE_FUNCTION_CREATOR(FunSubstringAfter)
246 DEFINE_FUNCTION_CREATOR(FunSubstring)
247 DEFINE_FUNCTION_CREATOR(FunStringLength)
248 DEFINE_FUNCTION_CREATOR(FunNormalizeSpace)
249 DEFINE_FUNCTION_CREATOR(FunTranslate)
251 DEFINE_FUNCTION_CREATOR(FunBoolean)
252 DEFINE_FUNCTION_CREATOR(FunNot)
253 DEFINE_FUNCTION_CREATOR(FunTrue)
254 DEFINE_FUNCTION_CREATOR(FunFalse)
255 DEFINE_FUNCTION_CREATOR(FunLang)
257 DEFINE_FUNCTION_CREATOR(FunNumber)
258 DEFINE_FUNCTION_CREATOR(FunSum)
259 DEFINE_FUNCTION_CREATOR(FunFloor)
260 DEFINE_FUNCTION_CREATOR(FunCeiling)
261 DEFINE_FUNCTION_CREATOR(FunRound)
263 #undef DEFINE_FUNCTION_CREATOR
265 inline Interval::Interval()
266 : m_min(Inf), m_max(Inf)
270 inline Interval::Interval(int value)
271 : m_min(value), m_max(value)
275 inline Interval::Interval(int min, int max)
276 : m_min(min), m_max(max)
280 inline bool Interval::contains(int value) const
282 if (m_min == Inf && m_max == Inf)
286 return value <= m_max;
289 return value >= m_min;
291 return value >= m_min && value <= m_max;
294 void Function::setArguments(Vector<OwnPtr<Expression> >& args)
296 ASSERT(!subExprCount());
298 // Some functions use context node as implicit argument, so when explicit arguments are added, they may no longer be context node sensitive.
299 if (m_name != "lang" && !args.isEmpty())
300 setIsContextNodeSensitive(false);
302 Vector<OwnPtr<Expression> >::iterator end = args.end();
303 for (Vector<OwnPtr<Expression> >::iterator it = args.begin(); it != end; ++it)
304 addSubExpression(it->release());
307 Value FunLast::evaluate() const
309 return Expression::evaluationContext().size;
312 Value FunPosition::evaluate() const
314 return Expression::evaluationContext().position;
317 Value FunId::evaluate() const
319 Value a = arg(0)->evaluate();
320 StringBuilder idList; // A whitespace-separated list of IDs
323 const NodeSet& nodes = a.toNodeSet();
324 for (size_t i = 0; i < nodes.size(); ++i) {
325 String str = stringValue(nodes[i]);
330 String str = a.toString();
334 TreeScope& contextScope = evaluationContext().node->treeScope();
336 HashSet<Node*> resultSet;
338 unsigned startPos = 0;
339 unsigned length = idList.length();
341 while (startPos < length && isWhitespace(idList[startPos]))
344 if (startPos == length)
347 size_t endPos = startPos;
348 while (endPos < length && !isWhitespace(idList[endPos]))
351 // If there are several nodes with the same id, id() should return the first one.
352 // In WebKit, getElementById behaves so, too, although its behavior in this case is formally undefined.
353 Node* node = contextScope.getElementById(AtomicString(idList.substring(startPos, endPos - startPos)));
354 if (node && resultSet.add(node).isNewEntry)
360 result.markSorted(false);
362 return Value(result, Value::adopt);
365 static inline String expandedNameLocalPart(Node* node)
367 // The local part of an XPath expanded-name matches DOM local name for most node types, except for namespace nodes and processing instruction nodes.
368 // But note that Blink does not support namespace nodes.
369 if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE)
370 return toProcessingInstruction(node)->target();
371 return node->localName().string();
374 static inline String expandedName(Node* node)
378 switch (node->nodeType()) {
379 case Node::ELEMENT_NODE:
380 prefix = toElement(node)->prefix();
382 case Node::ATTRIBUTE_NODE:
383 prefix = toAttr(node)->prefix();
389 return prefix.isEmpty() ? expandedNameLocalPart(node) : prefix + ":" + expandedNameLocalPart(node);
392 Value FunLocalName::evaluate() const
394 if (argCount() > 0) {
395 Value a = arg(0)->evaluate();
399 Node* node = a.toNodeSet().firstNode();
400 return node ? expandedNameLocalPart(node) : "";
403 return expandedNameLocalPart(evaluationContext().node.get());
406 Value FunNamespaceURI::evaluate() const
408 if (argCount() > 0) {
409 Value a = arg(0)->evaluate();
413 Node* node = a.toNodeSet().firstNode();
414 return node ? node->namespaceURI().string() : "";
417 return evaluationContext().node->namespaceURI().string();
420 Value FunName::evaluate() const
422 if (argCount() > 0) {
423 Value a = arg(0)->evaluate();
427 Node* node = a.toNodeSet().firstNode();
428 return node ? expandedName(node) : "";
431 return expandedName(evaluationContext().node.get());
434 Value FunCount::evaluate() const
436 Value a = arg(0)->evaluate();
438 return double(a.toNodeSet().size());
441 Value FunString::evaluate() const
444 return Value(Expression::evaluationContext().node.get()).toString();
445 return arg(0)->evaluate().toString();
448 Value FunConcat::evaluate() const
450 StringBuilder result;
451 result.reserveCapacity(1024);
453 unsigned count = argCount();
454 for (unsigned i = 0; i < count; ++i) {
455 String str(arg(i)->evaluate().toString());
459 return result.toString();
462 Value FunStartsWith::evaluate() const
464 String s1 = arg(0)->evaluate().toString();
465 String s2 = arg(1)->evaluate().toString();
470 return s1.startsWith(s2);
473 Value FunContains::evaluate() const
475 String s1 = arg(0)->evaluate().toString();
476 String s2 = arg(1)->evaluate().toString();
481 return s1.contains(s2) != 0;
484 Value FunSubstringBefore::evaluate() const
486 String s1 = arg(0)->evaluate().toString();
487 String s2 = arg(1)->evaluate().toString();
492 size_t i = s1.find(s2);
500 Value FunSubstringAfter::evaluate() const
502 String s1 = arg(0)->evaluate().toString();
503 String s2 = arg(1)->evaluate().toString();
505 size_t i = s1.find(s2);
509 return s1.substring(i + s2.length());
512 Value FunSubstring::evaluate() const
514 String s = arg(0)->evaluate().toString();
515 double doublePos = arg(1)->evaluate().toNumber();
516 if (std::isnan(doublePos))
518 long pos = static_cast<long>(FunRound::round(doublePos));
519 bool haveLength = argCount() == 3;
522 double doubleLen = arg(2)->evaluate().toNumber();
523 if (std::isnan(doubleLen))
525 len = static_cast<long>(FunRound::round(doubleLen));
528 if (pos > long(s.length()))
540 return s.substring(pos - 1, len);
543 Value FunStringLength::evaluate() const
546 return Value(Expression::evaluationContext().node.get()).toString().length();
547 return arg(0)->evaluate().toString().length();
550 Value FunNormalizeSpace::evaluate() const
553 String s = Value(Expression::evaluationContext().node.get()).toString();
554 return s.simplifyWhiteSpace();
557 String s = arg(0)->evaluate().toString();
558 return s.simplifyWhiteSpace();
561 Value FunTranslate::evaluate() const
563 String s1 = arg(0)->evaluate().toString();
564 String s2 = arg(1)->evaluate().toString();
565 String s3 = arg(2)->evaluate().toString();
566 StringBuilder result;
568 for (unsigned i1 = 0; i1 < s1.length(); ++i1) {
570 size_t i2 = s2.find(ch);
574 else if (i2 < s3.length())
575 result.append(s3[i2]);
578 return result.toString();
581 Value FunBoolean::evaluate() const
583 return arg(0)->evaluate().toBoolean();
586 Value FunNot::evaluate() const
588 return !arg(0)->evaluate().toBoolean();
591 Value FunTrue::evaluate() const
596 Value FunLang::evaluate() const
598 String lang = arg(0)->evaluate().toString();
600 const Attribute* languageAttribute = 0;
601 Node* node = evaluationContext().node.get();
603 if (node->isElementNode()) {
604 Element* element = toElement(node);
605 if (element->hasAttributes())
606 languageAttribute = element->getAttributeItem(XMLNames::langAttr);
608 if (languageAttribute)
610 node = node->parentNode();
613 if (!languageAttribute)
616 String langValue = languageAttribute->value();
618 if (equalIgnoringCase(langValue, lang))
621 // Remove suffixes one by one.
622 size_t index = langValue.reverseFind('-');
623 if (index == kNotFound)
625 langValue = langValue.left(index);
631 Value FunFalse::evaluate() const
636 Value FunNumber::evaluate() const
639 return Value(Expression::evaluationContext().node.get()).toNumber();
640 return arg(0)->evaluate().toNumber();
643 Value FunSum::evaluate() const
645 Value a = arg(0)->evaluate();
650 const NodeSet& nodes = a.toNodeSet();
651 // To be really compliant, we should sort the node-set, as floating point addition is not associative.
652 // However, this is unlikely to ever become a practical issue, and sorting is slow.
654 for (unsigned i = 0; i < nodes.size(); i++)
655 sum += Value(stringValue(nodes[i])).toNumber();
660 Value FunFloor::evaluate() const
662 return floor(arg(0)->evaluate().toNumber());
665 Value FunCeiling::evaluate() const
667 return ceil(arg(0)->evaluate().toNumber());
670 double FunRound::round(double val)
672 if (!std::isnan(val) && !std::isinf(val)) {
673 if (std::signbit(val) && val >= -0.5)
674 val *= 0; // negative zero
676 val = floor(val + 0.5);
681 Value FunRound::evaluate() const
683 return round(arg(0)->evaluate().toNumber());
686 struct FunctionMapping {
688 FunctionRec function;
691 static void createFunctionMap()
693 static const FunctionMapping functions[] = {
694 { "boolean", { &createFunBoolean, 1 } },
695 { "ceiling", { &createFunCeiling, 1 } },
696 { "concat", { &createFunConcat, Interval(2, Interval::Inf) } },
697 { "contains", { &createFunContains, 2 } },
698 { "count", { &createFunCount, 1 } },
699 { "false", { &createFunFalse, 0 } },
700 { "floor", { &createFunFloor, 1 } },
701 { "id", { &createFunId, 1 } },
702 { "lang", { &createFunLang, 1 } },
703 { "last", { &createFunLast, 0 } },
704 { "local-name", { &createFunLocalName, Interval(0, 1) } },
705 { "name", { &createFunName, Interval(0, 1) } },
706 { "namespace-uri", { &createFunNamespaceURI, Interval(0, 1) } },
707 { "normalize-space", { &createFunNormalizeSpace, Interval(0, 1) } },
708 { "not", { &createFunNot, 1 } },
709 { "number", { &createFunNumber, Interval(0, 1) } },
710 { "position", { &createFunPosition, 0 } },
711 { "round", { &createFunRound, 1 } },
712 { "starts-with", { &createFunStartsWith, 2 } },
713 { "string", { &createFunString, Interval(0, 1) } },
714 { "string-length", { &createFunStringLength, Interval(0, 1) } },
715 { "substring", { &createFunSubstring, Interval(2, 3) } },
716 { "substring-after", { &createFunSubstringAfter, 2 } },
717 { "substring-before", { &createFunSubstringBefore, 2 } },
718 { "sum", { &createFunSum, 1 } },
719 { "translate", { &createFunTranslate, 3 } },
720 { "true", { &createFunTrue, 0 } },
723 functionMap = new HashMap<String, FunctionRec>;
724 for (size_t i = 0; i < WTF_ARRAY_LENGTH(functions); ++i)
725 functionMap->set(functions[i].name, functions[i].function);
729 Function* createFunction(const String& name)
731 Vector<OwnPtr<Expression> > args;
732 return createFunction(name, args);
735 Function* createFunction(const String& name, Vector<OwnPtr<Expression> >& args)
740 HashMap<String, FunctionRec>::iterator functionMapIter = functionMap->find(name);
741 FunctionRec* functionRec = 0;
743 if (functionMapIter == functionMap->end() || !(functionRec = &functionMapIter->value)->args.contains(args.size()))
746 Function* function = functionRec->factoryFn();
747 function->setArguments(args);
748 function->setName(name);