2 * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
3 * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
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/XPathStep.h"
31 #include "core/XMLNSNames.h"
32 #include "core/dom/Attr.h"
33 #include "core/dom/Document.h"
34 #include "core/dom/Element.h"
35 #include "core/dom/NodeTraversal.h"
36 #include "core/xml/XPathParser.h"
37 #include "core/xml/XPathUtil.h"
42 Step::Step(Axis axis, const NodeTest& nodeTest)
44 , m_nodeTest(adoptPtrWillBeNoop(new NodeTest(nodeTest)))
48 Step::Step(Axis axis, const NodeTest& nodeTest, WillBeHeapVector<OwnPtrWillBeMember<Predicate> >& predicates)
50 , m_nodeTest(adoptPtrWillBeNoop(new NodeTest(nodeTest)))
52 m_predicates.swap(predicates);
59 void Step::trace(Visitor* visitor)
61 visitor->trace(m_nodeTest);
62 visitor->trace(m_predicates);
63 ParseNode::trace(visitor);
68 // Evaluate predicates as part of node test if possible to avoid building
69 // unnecessary NodeSets.
70 // E.g., there is no need to build a set of all "foo" nodes to evaluate
71 // "foo[@bar]", we can check the predicate while enumerating.
72 // This optimization can be applied to predicates that are not context node
73 // list sensitive, or to first predicate that is only context position
74 // sensitive, e.g. foo[position() mod 2 = 0].
75 WillBeHeapVector<OwnPtrWillBeMember<Predicate> > remainingPredicates;
76 for (size_t i = 0; i < m_predicates.size(); ++i) {
77 OwnPtrWillBeRawPtr<Predicate> predicate(m_predicates[i].release());
78 if ((!predicate->isContextPositionSensitive() || nodeTest().mergedPredicates().isEmpty()) && !predicate->isContextSizeSensitive() && remainingPredicates.isEmpty()) {
79 nodeTest().mergedPredicates().append(predicate.release());
81 remainingPredicates.append(predicate.release());
84 swap(remainingPredicates, m_predicates);
87 void optimizeStepPair(Step* first, Step* second, bool& dropSecondStep)
89 dropSecondStep = false;
91 if (first->m_axis == Step::DescendantOrSelfAxis
92 && first->nodeTest().kind() == Step::NodeTest::AnyNodeTest
93 && !first->m_predicates.size()
94 && !first->nodeTest().mergedPredicates().size()) {
96 ASSERT(first->nodeTest().data().isEmpty());
97 ASSERT(first->nodeTest().namespaceURI().isEmpty());
99 // Optimize the common case of "//" AKA
100 // /descendant-or-self::node()/child::NodeTest to /descendant::NodeTest.
101 if (second->m_axis == Step::ChildAxis && second->predicatesAreContextListInsensitive()) {
102 first->m_axis = Step::DescendantAxis;
103 first->nodeTest() = Step::NodeTest(second->nodeTest().kind(), second->nodeTest().data(), second->nodeTest().namespaceURI());
104 swap(second->nodeTest().mergedPredicates(), first->nodeTest().mergedPredicates());
105 swap(second->m_predicates, first->m_predicates);
107 dropSecondStep = true;
112 bool Step::predicatesAreContextListInsensitive() const
114 for (size_t i = 0; i < m_predicates.size(); ++i) {
115 Predicate* predicate = m_predicates[i].get();
116 if (predicate->isContextPositionSensitive() || predicate->isContextSizeSensitive())
120 for (size_t i = 0; i < nodeTest().mergedPredicates().size(); ++i) {
121 Predicate* predicate = nodeTest().mergedPredicates()[i].get();
122 if (predicate->isContextPositionSensitive() || predicate->isContextSizeSensitive())
129 void Step::evaluate(Node* context, NodeSet& nodes) const
131 EvaluationContext& evaluationContext = Expression::evaluationContext();
132 evaluationContext.position = 0;
134 nodesInAxis(context, nodes);
136 // Check predicates that couldn't be merged into node test.
137 for (unsigned i = 0; i < m_predicates.size(); i++) {
138 Predicate* predicate = m_predicates[i].get();
140 OwnPtrWillBeRawPtr<NodeSet> newNodes(NodeSet::create());
141 if (!nodes.isSorted())
142 newNodes->markSorted(false);
144 for (unsigned j = 0; j < nodes.size(); j++) {
145 Node* node = nodes[j];
147 evaluationContext.node = node;
148 evaluationContext.size = nodes.size();
149 evaluationContext.position = j + 1;
150 if (predicate->evaluate())
151 newNodes->append(node);
154 nodes.swap(*newNodes);
159 static inline Node::NodeType primaryNodeType(Step::Axis axis)
162 case Step::AttributeAxis:
163 return Node::ATTRIBUTE_NODE;
165 return Node::ELEMENT_NODE;
170 // Evaluate NodeTest without considering merged predicates.
171 static inline bool nodeMatchesBasicTest(Node* node, Step::Axis axis, const Step::NodeTest& nodeTest)
173 switch (nodeTest.kind()) {
174 case Step::NodeTest::TextNodeTest: {
175 Node::NodeType type = node->nodeType();
176 return type == Node::TEXT_NODE || type == Node::CDATA_SECTION_NODE;
178 case Step::NodeTest::CommentNodeTest:
179 return node->nodeType() == Node::COMMENT_NODE;
180 case Step::NodeTest::ProcessingInstructionNodeTest: {
181 const AtomicString& name = nodeTest.data();
182 return node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE && (name.isEmpty() || node->nodeName() == name);
184 case Step::NodeTest::AnyNodeTest:
186 case Step::NodeTest::NameTest: {
187 const AtomicString& name = nodeTest.data();
188 const AtomicString& namespaceURI = nodeTest.namespaceURI();
190 if (axis == Step::AttributeAxis) {
191 ASSERT(node->isAttributeNode());
193 // In XPath land, namespace nodes are not accessible on the
195 if (node->namespaceURI() == XMLNSNames::xmlnsNamespaceURI)
198 if (name == starAtom)
199 return namespaceURI.isEmpty() || node->namespaceURI() == namespaceURI;
201 return node->localName() == name && node->namespaceURI() == namespaceURI;
204 // Node test on the namespace axis is not implemented yet, the caller
205 // has a check for it.
206 ASSERT(axis != Step::NamespaceAxis);
208 // For other axes, the principal node type is element.
209 ASSERT(primaryNodeType(axis) == Node::ELEMENT_NODE);
210 if (!node->isElementNode())
212 Element& element = toElement(*node);
214 if (name == starAtom)
215 return namespaceURI.isEmpty() || namespaceURI == element.namespaceURI();
217 if (element.document().isHTMLDocument()) {
218 if (element.isHTMLElement()) {
219 // Paths without namespaces should match HTML elements in HTML
220 // documents despite those having an XHTML namespace. Names are
221 // compared case-insensitively.
222 return equalIgnoringCase(element.localName(), name) && (namespaceURI.isNull() || namespaceURI == element.namespaceURI());
224 // An expression without any prefix shouldn't match no-namespace
225 // nodes (because HTML5 says so).
226 return element.hasLocalName(name) && namespaceURI == element.namespaceURI() && !namespaceURI.isNull();
228 return element.hasLocalName(name) && namespaceURI == element.namespaceURI();
231 ASSERT_NOT_REACHED();
235 static inline bool nodeMatches(Node* node, Step::Axis axis, const Step::NodeTest& nodeTest)
237 if (!nodeMatchesBasicTest(node, axis, nodeTest))
240 EvaluationContext& evaluationContext = Expression::evaluationContext();
242 // Only the first merged predicate may depend on position.
243 ++evaluationContext.position;
245 const WillBeHeapVector<OwnPtrWillBeMember<Predicate> >& mergedPredicates = nodeTest.mergedPredicates();
246 for (unsigned i = 0; i < mergedPredicates.size(); i++) {
247 Predicate* predicate = mergedPredicates[i].get();
249 evaluationContext.node = node;
250 // No need to set context size - we only get here when evaluating
251 // predicates that do not depend on it.
252 if (!predicate->evaluate())
259 // Result nodes are ordered in axis order. Node test (including merged
260 // predicates) is applied.
261 void Step::nodesInAxis(Node* context, NodeSet& nodes) const
263 ASSERT(nodes.isEmpty());
266 // In XPath model, attribute nodes do not have children.
267 if (context->isAttributeNode())
270 for (Node* n = context->firstChild(); n; n = n->nextSibling()) {
271 if (nodeMatches(n, ChildAxis, nodeTest()))
277 // In XPath model, attribute nodes do not have children.
278 if (context->isAttributeNode())
281 for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context)) {
282 if (nodeMatches(n, DescendantAxis, nodeTest()))
288 if (context->isAttributeNode()) {
289 Element* n = toAttr(context)->ownerElement();
290 if (nodeMatches(n, ParentAxis, nodeTest()))
293 ContainerNode* n = context->parentNode();
294 if (n && nodeMatches(n, ParentAxis, nodeTest()))
301 if (context->isAttributeNode()) {
302 n = toAttr(context)->ownerElement();
303 if (nodeMatches(n, AncestorAxis, nodeTest()))
306 for (n = n->parentNode(); n; n = n->parentNode()) {
307 if (nodeMatches(n, AncestorAxis, nodeTest()))
310 nodes.markSorted(false);
314 case FollowingSiblingAxis:
315 if (context->nodeType() == Node::ATTRIBUTE_NODE)
318 for (Node* n = context->nextSibling(); n; n = n->nextSibling()) {
319 if (nodeMatches(n, FollowingSiblingAxis, nodeTest()))
324 case PrecedingSiblingAxis:
325 if (context->nodeType() == Node::ATTRIBUTE_NODE)
328 for (Node* n = context->previousSibling(); n; n = n->previousSibling()) {
329 if (nodeMatches(n, PrecedingSiblingAxis, nodeTest()))
332 nodes.markSorted(false);
336 if (context->isAttributeNode()) {
337 Node* p = toAttr(context)->ownerElement();
338 while ((p = NodeTraversal::next(*p))) {
339 if (nodeMatches(p, FollowingAxis, nodeTest()))
343 for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
344 for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
345 if (nodeMatches(n, FollowingAxis, nodeTest()))
347 for (Node* c = n->firstChild(); c; c = NodeTraversal::next(*c, n)) {
348 if (nodeMatches(c, FollowingAxis, nodeTest()))
356 case PrecedingAxis: {
357 if (context->isAttributeNode())
358 context = toAttr(context)->ownerElement();
361 while (ContainerNode* parent = n->parentNode()) {
362 for (n = NodeTraversal::previous(*n); n != parent; n = NodeTraversal::previous(*n)) {
363 if (nodeMatches(n, PrecedingAxis, nodeTest()))
368 nodes.markSorted(false);
372 case AttributeAxis: {
373 if (!context->isElementNode())
376 Element* contextElement = toElement(context);
377 // Avoid lazily creating attribute nodes for attributes that we do not
379 if (nodeTest().kind() == NodeTest::NameTest && nodeTest().data() != starAtom) {
380 RefPtrWillBeRawPtr<Node> n = contextElement->getAttributeNodeNS(nodeTest().namespaceURI(), nodeTest().data());
381 // In XPath land, namespace nodes are not accessible on the attribute axis.
382 if (n && n->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) {
383 // Still need to check merged predicates.
384 if (nodeMatches(n.get(), AttributeAxis, nodeTest()))
385 nodes.append(n.release());
390 if (!contextElement->hasAttributes())
393 AttributeCollection attributes = contextElement->attributes();
394 AttributeCollection::const_iterator end = attributes.end();
395 for (AttributeCollection::const_iterator it = attributes.begin(); it != end; ++it) {
396 RefPtrWillBeRawPtr<Attr> attr = contextElement->ensureAttr(it->name());
397 if (nodeMatches(attr.get(), AttributeAxis, nodeTest()))
398 nodes.append(attr.release());
404 // XPath namespace nodes are not implemented.
408 if (nodeMatches(context, SelfAxis, nodeTest()))
409 nodes.append(context);
412 case DescendantOrSelfAxis:
413 if (nodeMatches(context, DescendantOrSelfAxis, nodeTest()))
414 nodes.append(context);
415 // In XPath model, attribute nodes do not have children.
416 if (context->isAttributeNode())
419 for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context)) {
420 if (nodeMatches(n, DescendantOrSelfAxis, nodeTest()))
425 case AncestorOrSelfAxis: {
426 if (nodeMatches(context, AncestorOrSelfAxis, nodeTest()))
427 nodes.append(context);
429 if (context->isAttributeNode()) {
430 n = toAttr(context)->ownerElement();
431 if (nodeMatches(n, AncestorOrSelfAxis, nodeTest()))
434 for (n = n->parentNode(); n; n = n->parentNode()) {
435 if (nodeMatches(n, AncestorOrSelfAxis, nodeTest()))
438 nodes.markSorted(false);
442 ASSERT_NOT_REACHED();