blob: 5b813445bf482e0b9312977a923da48b76976cc7 [file] [log] [blame]
andersca75fd42c2006-05-08 21:27:25 +00001/*
ap@webkit.org66fb8552009-05-28 16:23:32 +00002 * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
ap@webkit.org68a5bc62009-06-02 17:59:09 +00003 * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
weinige2750b32007-02-17 22:09:10 +00004 * Copyright (C) 2007 Alexey Proskuryakov <ap@webkit.org>
andersca75fd42c2006-05-08 21:27:25 +00005 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
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.
15 *
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.
26 */
darina9406af2006-06-04 23:03:41 +000027
andersca75fd42c2006-05-08 21:27:25 +000028#include "config.h"
darina9406af2006-06-04 23:03:41 +000029#include "XPathStep.h"
andersca75fd42c2006-05-08 21:27:25 +000030
darin@apple.com9a925fa2009-05-04 18:00:34 +000031#include "Attr.h"
ap6a2f4882007-02-11 09:05:04 +000032#include "Document.h"
darin@apple.com59755cf2013-10-10 02:46:27 +000033#include "HTMLElement.h"
antti@apple.com5d47b582012-12-11 00:13:29 +000034#include "NodeTraversal.h"
ap@apple.com38221c62010-01-18 22:05:55 +000035#include "XMLNSNames.h"
andersca0315a982006-06-04 08:08:31 +000036#include "XPathParser.h"
apce79f362007-03-20 17:21:07 +000037#include "XPathUtil.h"
andersca75fd42c2006-05-08 21:27:25 +000038
39namespace WebCore {
40namespace XPath {
41
darin@apple.com59755cf2013-10-10 02:46:27 +000042Step::Step(Axis axis, NodeTest nodeTest)
weinige2750b32007-02-17 22:09:10 +000043 : m_axis(axis)
darin@apple.com59755cf2013-10-10 02:46:27 +000044 , m_nodeTest(std::move(nodeTest))
45{
46}
47
48Step::Step(Axis axis, NodeTest nodeTest, Vector<std::unique_ptr<Expression>> predicates)
49 : m_axis(axis)
50 , m_nodeTest(std::move(nodeTest))
51 , m_predicates(std::move(predicates))
andersca75fd42c2006-05-08 21:27:25 +000052{
weinige2750b32007-02-17 22:09:10 +000053}
54
andersca75fd42c2006-05-08 21:27:25 +000055Step::~Step()
56{
ap@webkit.org84b68192009-06-01 04:18:09 +000057}
58
59void Step::optimize()
60{
61 // Evaluate predicates as part of node test if possible to avoid building unnecessary NodeSets.
62 // E.g., there is no need to build a set of all "foo" nodes to evaluate "foo[@bar]", we can check the predicate while enumerating.
63 // This optimization can be applied to predicates that are not context node list sensitive, or to first predicate that is only context position sensitive, e.g. foo[position() mod 2 = 0].
darin@apple.com59755cf2013-10-10 02:46:27 +000064 Vector<std::unique_ptr<Expression>> remainingPredicates;
ap@webkit.org84b68192009-06-01 04:18:09 +000065 for (size_t i = 0; i < m_predicates.size(); ++i) {
darin@apple.com59755cf2013-10-10 02:46:27 +000066 auto& predicate = m_predicates[i];
67 if ((!predicateIsContextPositionSensitive(*predicate) || m_nodeTest.m_mergedPredicates.isEmpty()) && !predicate->isContextSizeSensitive() && remainingPredicates.isEmpty())
68 m_nodeTest.m_mergedPredicates.append(std::move(predicate));
69 else
70 remainingPredicates.append(std::move(predicate));
ap@webkit.org84b68192009-06-01 04:18:09 +000071 }
darin@apple.com59755cf2013-10-10 02:46:27 +000072 m_predicates = std::move(remainingPredicates);
ap@webkit.org84b68192009-06-01 04:18:09 +000073}
74
darin@apple.com59755cf2013-10-10 02:46:27 +000075void optimizeStepPair(Step& first, Step& second, bool& dropSecondStep)
ap@webkit.org84b68192009-06-01 04:18:09 +000076{
77 dropSecondStep = false;
78
darin@apple.com59755cf2013-10-10 02:46:27 +000079 if (first.m_axis != Step::DescendantOrSelfAxis)
80 return;
ap@webkit.org84b68192009-06-01 04:18:09 +000081
darin@apple.com59755cf2013-10-10 02:46:27 +000082 if (first.m_nodeTest.m_kind != Step::NodeTest::AnyNodeTest)
83 return;
ap@webkit.org84b68192009-06-01 04:18:09 +000084
darin@apple.com59755cf2013-10-10 02:46:27 +000085 if (!first.m_predicates.isEmpty())
86 return;
87
88 if (!first.m_nodeTest.m_mergedPredicates.isEmpty())
89 return;
90
91 ASSERT(first.m_nodeTest.m_data.isEmpty());
92 ASSERT(first.m_nodeTest.m_namespaceURI.isEmpty());
93
94 // Optimize the common case of "//" AKA /descendant-or-self::node()/child::NodeTest to /descendant::NodeTest.
95 if (second.m_axis != Step::ChildAxis)
96 return;
97
98 if (!second.predicatesAreContextListInsensitive())
99 return;
100
101 first.m_axis = Step::DescendantAxis;
102 first.m_nodeTest = std::move(second.m_nodeTest);
103 first.m_predicates = std::move(second.m_predicates);
104 first.optimize();
105 dropSecondStep = true;
ap@webkit.org84b68192009-06-01 04:18:09 +0000106}
107
108bool Step::predicatesAreContextListInsensitive() const
109{
110 for (size_t i = 0; i < m_predicates.size(); ++i) {
darin@apple.com59755cf2013-10-10 02:46:27 +0000111 auto& predicate = *m_predicates[i];
112 if (predicateIsContextPositionSensitive(predicate) || predicate.isContextSizeSensitive())
ap@webkit.org84b68192009-06-01 04:18:09 +0000113 return false;
114 }
115
darin@apple.com59755cf2013-10-10 02:46:27 +0000116 for (size_t i = 0; i < m_nodeTest.m_mergedPredicates.size(); ++i) {
117 auto& predicate = *m_nodeTest.m_mergedPredicates[i];
118 if (predicateIsContextPositionSensitive(predicate) || predicate.isContextSizeSensitive())
ap@webkit.org84b68192009-06-01 04:18:09 +0000119 return false;
120 }
121
122 return true;
andersca75fd42c2006-05-08 21:27:25 +0000123}
124
darin@apple.com59755cf2013-10-10 02:46:27 +0000125void Step::evaluate(Node& context, NodeSet& nodes) const
andersca75fd42c2006-05-08 21:27:25 +0000126{
ap94457f12007-03-11 08:21:13 +0000127 EvaluationContext& evaluationContext = Expression::evaluationContext();
ap@webkit.org84b68192009-06-01 04:18:09 +0000128 evaluationContext.position = 0;
129
130 nodesInAxis(context, nodes);
131
132 // Check predicates that couldn't be merged into node test.
andersca75fd42c2006-05-08 21:27:25 +0000133 for (unsigned i = 0; i < m_predicates.size(); i++) {
darin@apple.com59755cf2013-10-10 02:46:27 +0000134 auto& predicate = *m_predicates[i];
andersca75fd42c2006-05-08 21:27:25 +0000135
apce79f362007-03-20 17:21:07 +0000136 NodeSet newNodes;
137 if (!nodes.isSorted())
138 newNodes.markSorted(false);
139
ap94457f12007-03-11 08:21:13 +0000140 for (unsigned j = 0; j < nodes.size(); j++) {
apce79f362007-03-20 17:21:07 +0000141 Node* node = nodes[j];
andersca75fd42c2006-05-08 21:27:25 +0000142
ap@webkit.org84b68192009-06-01 04:18:09 +0000143 evaluationContext.node = node;
ap@webkit.org891af4c2007-11-16 06:04:45 +0000144 evaluationContext.size = nodes.size();
145 evaluationContext.position = j + 1;
darin@apple.com59755cf2013-10-10 02:46:27 +0000146 if (evaluatePredicate(predicate))
ap94457f12007-03-11 08:21:13 +0000147 newNodes.append(node);
andersca75fd42c2006-05-08 21:27:25 +0000148 }
149
darin@apple.com59755cf2013-10-10 02:46:27 +0000150 nodes = std::move(newNodes);
andersca75fd42c2006-05-08 21:27:25 +0000151 }
andersca75fd42c2006-05-08 21:27:25 +0000152}
153
mrowe@apple.com00e249e2013-09-28 10:26:17 +0000154#if !ASSERT_DISABLED
ap@webkit.org66fb8552009-05-28 16:23:32 +0000155static inline Node::NodeType primaryNodeType(Step::Axis axis)
andersca75fd42c2006-05-08 21:27:25 +0000156{
ap@webkit.org66fb8552009-05-28 16:23:32 +0000157 switch (axis) {
158 case Step::AttributeAxis:
159 return Node::ATTRIBUTE_NODE;
160 case Step::NamespaceAxis:
161 return Node::XPATH_NAMESPACE_NODE;
162 default:
163 return Node::ELEMENT_NODE;
andersca75fd42c2006-05-08 21:27:25 +0000164 }
andersca75fd42c2006-05-08 21:27:25 +0000165}
mrowe@apple.com00e249e2013-09-28 10:26:17 +0000166#endif
andersca75fd42c2006-05-08 21:27:25 +0000167
ap@webkit.org84b68192009-06-01 04:18:09 +0000168// Evaluate NodeTest without considering merged predicates.
darin@apple.com59755cf2013-10-10 02:46:27 +0000169inline bool nodeMatchesBasicTest(Node& node, Step::Axis axis, const Step::NodeTest& nodeTest)
andersca75fd42c2006-05-08 21:27:25 +0000170{
darin@apple.com59755cf2013-10-10 02:46:27 +0000171 switch (nodeTest.m_kind) {
ap@webkit.org66fb8552009-05-28 16:23:32 +0000172 case Step::NodeTest::TextNodeTest:
darin@apple.com59755cf2013-10-10 02:46:27 +0000173 return node.nodeType() == Node::TEXT_NODE || node.nodeType() == Node::CDATA_SECTION_NODE;
ap@webkit.org66fb8552009-05-28 16:23:32 +0000174 case Step::NodeTest::CommentNodeTest:
darin@apple.com59755cf2013-10-10 02:46:27 +0000175 return node.nodeType() == Node::COMMENT_NODE;
ap@webkit.org66fb8552009-05-28 16:23:32 +0000176 case Step::NodeTest::ProcessingInstructionNodeTest: {
darin@apple.com59755cf2013-10-10 02:46:27 +0000177 const AtomicString& name = nodeTest.m_data;
178 return node.nodeType() == Node::PROCESSING_INSTRUCTION_NODE && (name.isEmpty() || node.nodeName() == name);
apb4371822007-03-25 08:39:27 +0000179 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000180 case Step::NodeTest::AnyNodeTest:
apb4371822007-03-25 08:39:27 +0000181 return true;
ap@webkit.org66fb8552009-05-28 16:23:32 +0000182 case Step::NodeTest::NameTest: {
darin@apple.com59755cf2013-10-10 02:46:27 +0000183 const AtomicString& name = nodeTest.m_data;
184 const AtomicString& namespaceURI = nodeTest.m_namespaceURI;
apb4371822007-03-25 08:39:27 +0000185
ap@webkit.org66fb8552009-05-28 16:23:32 +0000186 if (axis == Step::AttributeAxis) {
darin@apple.com59755cf2013-10-10 02:46:27 +0000187 ASSERT(node.isAttributeNode());
ap16c9b5f2007-03-28 16:48:16 +0000188
apb4371822007-03-25 08:39:27 +0000189 // In XPath land, namespace nodes are not accessible on the attribute axis.
darin@apple.com59755cf2013-10-10 02:46:27 +0000190 if (node.namespaceURI() == XMLNSNames::xmlnsNamespaceURI)
apb4371822007-03-25 08:39:27 +0000191 return false;
andersca75fd42c2006-05-08 21:27:25 +0000192
ap@webkit.org66fb8552009-05-28 16:23:32 +0000193 if (name == starAtom)
darin@apple.com59755cf2013-10-10 02:46:27 +0000194 return namespaceURI.isEmpty() || node.namespaceURI() == namespaceURI;
ap16c9b5f2007-03-28 16:48:16 +0000195
darin@apple.com59755cf2013-10-10 02:46:27 +0000196 return node.localName() == name && node.namespaceURI() == namespaceURI;
ap94457f12007-03-11 08:21:13 +0000197 }
ap16c9b5f2007-03-28 16:48:16 +0000198
ap@webkit.org66fb8552009-05-28 16:23:32 +0000199 // Node test on the namespace axis is not implemented yet, the caller has a check for it.
200 ASSERT(axis != Step::NamespaceAxis);
ap16c9b5f2007-03-28 16:48:16 +0000201
ap@webkit.org43495fb2009-05-27 17:21:02 +0000202 // For other axes, the principal node type is element.
ap@webkit.org66fb8552009-05-28 16:23:32 +0000203 ASSERT(primaryNodeType(axis) == Node::ELEMENT_NODE);
darin@apple.com59755cf2013-10-10 02:46:27 +0000204 if (!node.isElementNode())
ap@webkit.org43495fb2009-05-27 17:21:02 +0000205 return false;
206
ap@webkit.org66fb8552009-05-28 16:23:32 +0000207 if (name == starAtom)
darin@apple.com59755cf2013-10-10 02:46:27 +0000208 return namespaceURI.isEmpty() || namespaceURI == node.namespaceURI();
ap@webkit.org43495fb2009-05-27 17:21:02 +0000209
darin@apple.com59755cf2013-10-10 02:46:27 +0000210 if (node.document().isHTMLDocument()) {
211 if (node.isHTMLElement()) {
ap@apple.com84ab1192009-11-02 18:41:55 +0000212 // Paths without namespaces should match HTML elements in HTML documents despite those having an XHTML namespace. Names are compared case-insensitively.
darin@apple.com59755cf2013-10-10 02:46:27 +0000213 return equalIgnoringCase(toHTMLElement(node).localName(), name) && (namespaceURI.isNull() || namespaceURI == node.namespaceURI());
ap@apple.com84ab1192009-11-02 18:41:55 +0000214 }
215 // An expression without any prefix shouldn't match no-namespace nodes (because HTML5 says so).
darin@apple.com59755cf2013-10-10 02:46:27 +0000216 return toElement(node).hasLocalName(name) && namespaceURI == node.namespaceURI() && !namespaceURI.isNull();
ap@webkit.org43495fb2009-05-27 17:21:02 +0000217 }
darin@apple.com59755cf2013-10-10 02:46:27 +0000218 return toElement(node).hasLocalName(name) && namespaceURI == node.namespaceURI();
ap94457f12007-03-11 08:21:13 +0000219 }
220 }
221 ASSERT_NOT_REACHED();
apb4371822007-03-25 08:39:27 +0000222 return false;
andersca75fd42c2006-05-08 21:27:25 +0000223}
224
darin@apple.com59755cf2013-10-10 02:46:27 +0000225inline bool nodeMatches(Node& node, Step::Axis axis, const Step::NodeTest& nodeTest)
ap@webkit.org84b68192009-06-01 04:18:09 +0000226{
227 if (!nodeMatchesBasicTest(node, axis, nodeTest))
228 return false;
229
230 EvaluationContext& evaluationContext = Expression::evaluationContext();
231
232 // Only the first merged predicate may depend on position.
233 ++evaluationContext.position;
234
darin@apple.com59755cf2013-10-10 02:46:27 +0000235 auto& mergedPredicates = nodeTest.m_mergedPredicates;
ap@webkit.org84b68192009-06-01 04:18:09 +0000236 for (unsigned i = 0; i < mergedPredicates.size(); i++) {
ap@webkit.org84b68192009-06-01 04:18:09 +0000237 // No need to set context size - we only get here when evaluating predicates that do not depend on it.
darin@apple.com59755cf2013-10-10 02:46:27 +0000238 evaluationContext.node = &node;
239 if (!evaluatePredicate(*mergedPredicates[i]))
ap@webkit.org84b68192009-06-01 04:18:09 +0000240 return false;
241 }
242
243 return true;
244}
245
246// Result nodes are ordered in axis order. Node test (including merged predicates) is applied.
darin@apple.com59755cf2013-10-10 02:46:27 +0000247void Step::nodesInAxis(Node& context, NodeSet& nodes) const
andersca75fd42c2006-05-08 21:27:25 +0000248{
ap@webkit.org66fb8552009-05-28 16:23:32 +0000249 ASSERT(nodes.isEmpty());
250 switch (m_axis) {
251 case ChildAxis:
darin@apple.com59755cf2013-10-10 02:46:27 +0000252 if (context.isAttributeNode()) // In XPath model, attribute nodes do not have children.
ap@webkit.org66fb8552009-05-28 16:23:32 +0000253 return;
darin@apple.com59755cf2013-10-10 02:46:27 +0000254 for (Node* node = context.firstChild(); node; node = node->nextSibling()) {
255 if (nodeMatches(*node, ChildAxis, m_nodeTest))
256 nodes.append(node);
257 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000258 return;
259 case DescendantAxis:
darin@apple.com59755cf2013-10-10 02:46:27 +0000260 if (context.isAttributeNode()) // In XPath model, attribute nodes do not have children.
ap@webkit.org66fb8552009-05-28 16:23:32 +0000261 return;
darin@apple.com59755cf2013-10-10 02:46:27 +0000262 for (Node* node = context.firstChild(); node; node = NodeTraversal::next(node, &context)) {
263 if (nodeMatches(*node, DescendantAxis, m_nodeTest))
264 nodes.append(node);
265 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000266 return;
267 case ParentAxis:
darin@apple.com59755cf2013-10-10 02:46:27 +0000268 if (context.isAttributeNode()) {
269 Element* node = static_cast<Attr&>(context).ownerElement();
270 if (nodeMatches(*node, ParentAxis, m_nodeTest))
271 nodes.append(node);
ap@webkit.org66fb8552009-05-28 16:23:32 +0000272 } else {
darin@apple.com59755cf2013-10-10 02:46:27 +0000273 ContainerNode* node = context.parentNode();
274 if (node && nodeMatches(*node, ParentAxis, m_nodeTest))
275 nodes.append(node);
ap@webkit.org66fb8552009-05-28 16:23:32 +0000276 }
277 return;
278 case AncestorAxis: {
darin@apple.com59755cf2013-10-10 02:46:27 +0000279 Node* node = &context;
280 if (context.isAttributeNode()) {
281 node = static_cast<Attr&>(context).ownerElement();
282 if (nodeMatches(*node, AncestorAxis, m_nodeTest))
283 nodes.append(node);
ap@webkit.org66fb8552009-05-28 16:23:32 +0000284 }
darin@apple.com59755cf2013-10-10 02:46:27 +0000285 for (node = node->parentNode(); node; node = node->parentNode()) {
286 if (nodeMatches(*node, AncestorAxis, m_nodeTest))
287 nodes.append(node);
288 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000289 nodes.markSorted(false);
290 return;
291 }
292 case FollowingSiblingAxis:
darin@apple.com59755cf2013-10-10 02:46:27 +0000293 if (context.nodeType() == Node::ATTRIBUTE_NODE || context.nodeType() == Node::XPATH_NAMESPACE_NODE)
ap@webkit.org66fb8552009-05-28 16:23:32 +0000294 return;
darin@apple.com59755cf2013-10-10 02:46:27 +0000295 for (Node* node = context.nextSibling(); node; node = node->nextSibling()) {
296 if (nodeMatches(*node, FollowingSiblingAxis, m_nodeTest))
297 nodes.append(node);
298 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000299 return;
300 case PrecedingSiblingAxis:
darin@apple.com59755cf2013-10-10 02:46:27 +0000301 if (context.nodeType() == Node::ATTRIBUTE_NODE || context.nodeType() == Node::XPATH_NAMESPACE_NODE)
ap@webkit.org66fb8552009-05-28 16:23:32 +0000302 return;
darin@apple.com59755cf2013-10-10 02:46:27 +0000303 for (Node* node = context.previousSibling(); node; node = node->previousSibling()) {
304 if (nodeMatches(*node, PrecedingSiblingAxis, m_nodeTest))
305 nodes.append(node);
306 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000307 nodes.markSorted(false);
308 return;
309 case FollowingAxis:
darin@apple.com59755cf2013-10-10 02:46:27 +0000310 if (context.isAttributeNode()) {
311 Node* node = static_cast<Attr&>(context).ownerElement();
312 while ((node = NodeTraversal::next(node))) {
313 if (nodeMatches(*node, FollowingAxis, m_nodeTest))
314 nodes.append(node);
315 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000316 } else {
darin@apple.com59755cf2013-10-10 02:46:27 +0000317 for (Node* parent = &context; !isRootDomNode(parent); parent = parent->parentNode()) {
318 for (Node* node = parent->nextSibling(); node; node = node->nextSibling()) {
319 if (nodeMatches(*node, FollowingAxis, m_nodeTest))
320 nodes.append(node);
321 for (Node* child = node->firstChild(); child; child = NodeTraversal::next(child, node)) {
322 if (nodeMatches(*child, FollowingAxis, m_nodeTest))
323 nodes.append(child);
324 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000325 }
326 }
327 }
328 return;
329 case PrecedingAxis: {
darin@apple.com59755cf2013-10-10 02:46:27 +0000330 Node* node;
331 if (context.isAttributeNode())
332 node = static_cast<Attr&>(context).ownerElement();
333 else
334 node = &context;
335 while (ContainerNode* parent = node->parentNode()) {
336 for (node = NodeTraversal::previous(node); node != parent; node = NodeTraversal::previous(node)) {
337 if (nodeMatches(*node, PrecedingAxis, m_nodeTest))
338 nodes.append(node);
339 }
340 node = parent;
ap@webkit.org66fb8552009-05-28 16:23:32 +0000341 }
342 nodes.markSorted(false);
343 return;
344 }
345 case AttributeAxis: {
darin@apple.com59755cf2013-10-10 02:46:27 +0000346 if (!context.isElementNode())
ap@webkit.org66fb8552009-05-28 16:23:32 +0000347 return;
348
darin@apple.com59755cf2013-10-10 02:46:27 +0000349 Element& contextElement = toElement(context);
caio.oliveira@openbossa.org062edfb2012-02-02 00:20:36 +0000350
ap@webkit.org66fb8552009-05-28 16:23:32 +0000351 // Avoid lazily creating attribute nodes for attributes that we do not need anyway.
darin@apple.com59755cf2013-10-10 02:46:27 +0000352 if (m_nodeTest.m_kind == NodeTest::NameTest && m_nodeTest.m_data != starAtom) {
353 RefPtr<Attr> attr = contextElement.getAttributeNodeNS(m_nodeTest.m_namespaceURI, m_nodeTest.m_data);
354 if (attr && attr->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { // In XPath land, namespace nodes are not accessible on the attribute axis.
355 if (nodeMatches(*attr, AttributeAxis, m_nodeTest)) // Still need to check merged predicates.
356 nodes.append(attr.release());
ap@webkit.org84b68192009-06-01 04:18:09 +0000357 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000358 return;
359 }
360
darin@apple.com59755cf2013-10-10 02:46:27 +0000361 if (!contextElement.hasAttributes())
ap@webkit.org66fb8552009-05-28 16:23:32 +0000362 return;
363
benjamin@webkit.org64c95332014-01-21 01:31:37 +0000364 for (const Attribute& attribute : contextElement.attributesIterator()) {
365 RefPtr<Attr> attr = contextElement.ensureAttr(attribute.name());
darin@apple.com59755cf2013-10-10 02:46:27 +0000366 if (nodeMatches(*attr, AttributeAxis, m_nodeTest))
ap@webkit.org66fb8552009-05-28 16:23:32 +0000367 nodes.append(attr.release());
368 }
369 return;
370 }
andersca75fd42c2006-05-08 21:27:25 +0000371 case NamespaceAxis:
ap@webkit.org66fb8552009-05-28 16:23:32 +0000372 // XPath namespace nodes are not implemented yet.
373 return;
374 case SelfAxis:
375 if (nodeMatches(context, SelfAxis, m_nodeTest))
darin@apple.com59755cf2013-10-10 02:46:27 +0000376 nodes.append(&context);
ap@webkit.org66fb8552009-05-28 16:23:32 +0000377 return;
378 case DescendantOrSelfAxis:
379 if (nodeMatches(context, DescendantOrSelfAxis, m_nodeTest))
darin@apple.com59755cf2013-10-10 02:46:27 +0000380 nodes.append(&context);
381 if (context.isAttributeNode()) // In XPath model, attribute nodes do not have children.
ap@webkit.org66fb8552009-05-28 16:23:32 +0000382 return;
darin@apple.com59755cf2013-10-10 02:46:27 +0000383 for (Node* node = context.firstChild(); node; node = NodeTraversal::next(node, &context)) {
384 if (nodeMatches(*node, DescendantOrSelfAxis, m_nodeTest))
385 nodes.append(node);
386 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000387 return;
388 case AncestorOrSelfAxis: {
389 if (nodeMatches(context, AncestorOrSelfAxis, m_nodeTest))
darin@apple.com59755cf2013-10-10 02:46:27 +0000390 nodes.append(&context);
391 Node* node = &context;
392 if (context.isAttributeNode()) {
393 node = static_cast<Attr&>(context).ownerElement();
394 if (nodeMatches(*node, AncestorOrSelfAxis, m_nodeTest))
395 nodes.append(node);
ap@webkit.org66fb8552009-05-28 16:23:32 +0000396 }
darin@apple.com59755cf2013-10-10 02:46:27 +0000397 for (node = node->parentNode(); node; node = node->parentNode()) {
398 if (nodeMatches(*node, AncestorOrSelfAxis, m_nodeTest))
399 nodes.append(node);
400 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000401 nodes.markSorted(false);
402 return;
403 }
andersca75fd42c2006-05-08 21:27:25 +0000404 }
ap@webkit.org66fb8552009-05-28 16:23:32 +0000405 ASSERT_NOT_REACHED();
andersca75fd42c2006-05-08 21:27:25 +0000406}
407
408}
409}