1 /* 2 * Copyright (C) 2005 Frerich Raabe <raabe (at) kde.org> 3 * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. 4 * Copyright (C) 2007 Alexey Proskuryakov <ap (at) webkit.org> 5 * 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 */ 27 28 #include "config.h" 29 #include "core/xml/XPathStep.h" 30 31 #include "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" 38 39 namespace WebCore { 40 namespace XPath { 41 42 Step::Step(Axis axis, const NodeTest& nodeTest) 43 : m_axis(axis) 44 , m_nodeTest(nodeTest) 45 { 46 } 47 48 Step::Step(Axis axis, const NodeTest& nodeTest, Vector<OwnPtr<Predicate> >& predicates) 49 : m_axis(axis) 50 , m_nodeTest(nodeTest) 51 { 52 m_predicates.swap(predicates); 53 } 54 55 Step::~Step() 56 { 57 } 58 59 void 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]. 64 Vector<OwnPtr<Predicate> > remainingPredicates; 65 for (size_t i = 0; i < m_predicates.size(); ++i) { 66 OwnPtr<Predicate> predicate(m_predicates[i].release()); 67 if ((!predicate->isContextPositionSensitive() || m_nodeTest.mergedPredicates().isEmpty()) && !predicate->isContextSizeSensitive() && remainingPredicates.isEmpty()) { 68 m_nodeTest.mergedPredicates().append(predicate.release()); 69 } else { 70 remainingPredicates.append(predicate.release()); 71 } 72 } 73 swap(remainingPredicates, m_predicates); 74 } 75 76 void optimizeStepPair(Step* first, Step* second, bool& dropSecondStep) 77 { 78 dropSecondStep = false; 79 80 if (first->m_axis == Step::DescendantOrSelfAxis 81 && first->m_nodeTest.kind() == Step::NodeTest::AnyNodeTest 82 && !first->m_predicates.size() 83 && !first->m_nodeTest.mergedPredicates().size()) { 84 85 ASSERT(first->m_nodeTest.data().isEmpty()); 86 ASSERT(first->m_nodeTest.namespaceURI().isEmpty()); 87 88 // Optimize the common case of "//" AKA /descendant-or-self::node()/child::NodeTest to /descendant::NodeTest. 89 if (second->m_axis == Step::ChildAxis && second->predicatesAreContextListInsensitive()) { 90 first->m_axis = Step::DescendantAxis; 91 first->m_nodeTest = Step::NodeTest(second->m_nodeTest.kind(), second->m_nodeTest.data(), second->m_nodeTest.namespaceURI()); 92 swap(second->m_nodeTest.mergedPredicates(), first->m_nodeTest.mergedPredicates()); 93 swap(second->m_predicates, first->m_predicates); 94 first->optimize(); 95 dropSecondStep = true; 96 } 97 } 98 } 99 100 bool Step::predicatesAreContextListInsensitive() const 101 { 102 for (size_t i = 0; i < m_predicates.size(); ++i) { 103 Predicate* predicate = m_predicates[i].get(); 104 if (predicate->isContextPositionSensitive() || predicate->isContextSizeSensitive()) 105 return false; 106 } 107 108 for (size_t i = 0; i < m_nodeTest.mergedPredicates().size(); ++i) { 109 Predicate* predicate = m_nodeTest.mergedPredicates()[i].get(); 110 if (predicate->isContextPositionSensitive() || predicate->isContextSizeSensitive()) 111 return false; 112 } 113 114 return true; 115 } 116 117 void Step::evaluate(Node* context, NodeSet& nodes) const 118 { 119 EvaluationContext& evaluationContext = Expression::evaluationContext(); 120 evaluationContext.position = 0; 121 122 nodesInAxis(context, nodes); 123 124 // Check predicates that couldn't be merged into node test. 125 for (unsigned i = 0; i < m_predicates.size(); i++) { 126 Predicate* predicate = m_predicates[i].get(); 127 128 NodeSet newNodes; 129 if (!nodes.isSorted()) 130 newNodes.markSorted(false); 131 132 for (unsigned j = 0; j < nodes.size(); j++) { 133 Node* node = nodes[j]; 134 135 evaluationContext.node = node; 136 evaluationContext.size = nodes.size(); 137 evaluationContext.position = j + 1; 138 if (predicate->evaluate()) 139 newNodes.append(node); 140 } 141 142 nodes.swap(newNodes); 143 } 144 } 145 146 #if !ASSERT_DISABLED 147 static inline Node::NodeType primaryNodeType(Step::Axis axis) 148 { 149 switch (axis) { 150 case Step::AttributeAxis: 151 return Node::ATTRIBUTE_NODE; 152 case Step::NamespaceAxis: 153 return Node::XPATH_NAMESPACE_NODE; 154 default: 155 return Node::ELEMENT_NODE; 156 } 157 } 158 #endif 159 160 // Evaluate NodeTest without considering merged predicates. 161 static inline bool nodeMatchesBasicTest(Node* node, Step::Axis axis, const Step::NodeTest& nodeTest) 162 { 163 switch (nodeTest.kind()) { 164 case Step::NodeTest::TextNodeTest: 165 return node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE; 166 case Step::NodeTest::CommentNodeTest: 167 return node->nodeType() == Node::COMMENT_NODE; 168 case Step::NodeTest::ProcessingInstructionNodeTest: { 169 const AtomicString& name = nodeTest.data(); 170 return node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE && (name.isEmpty() || node->nodeName() == name); 171 } 172 case Step::NodeTest::AnyNodeTest: 173 return true; 174 case Step::NodeTest::NameTest: { 175 const AtomicString& name = nodeTest.data(); 176 const AtomicString& namespaceURI = nodeTest.namespaceURI(); 177 178 if (axis == Step::AttributeAxis) { 179 ASSERT(node->isAttributeNode()); 180 181 // In XPath land, namespace nodes are not accessible on the attribute axis. 182 if (node->namespaceURI() == XMLNSNames::xmlnsNamespaceURI) 183 return false; 184 185 if (name == starAtom) 186 return namespaceURI.isEmpty() || node->namespaceURI() == namespaceURI; 187 188 return node->localName() == name && node->namespaceURI() == namespaceURI; 189 } 190 191 // Node test on the namespace axis is not implemented yet, the caller has a check for it. 192 ASSERT(axis != Step::NamespaceAxis); 193 194 // For other axes, the principal node type is element. 195 ASSERT(primaryNodeType(axis) == Node::ELEMENT_NODE); 196 if (node->nodeType() != Node::ELEMENT_NODE) 197 return false; 198 199 if (name == starAtom) 200 return namespaceURI.isEmpty() || namespaceURI == node->namespaceURI(); 201 202 if (node->document().isHTMLDocument()) { 203 if (node->isHTMLElement()) { 204 // Paths without namespaces should match HTML elements in HTML documents despite those having an XHTML namespace. Names are compared case-insensitively. 205 return equalIgnoringCase(toElement(node)->localName(), name) && (namespaceURI.isNull() || namespaceURI == node->namespaceURI()); 206 } 207 // An expression without any prefix shouldn't match no-namespace nodes (because HTML5 says so). 208 return toElement(node)->hasLocalName(name) && namespaceURI == node->namespaceURI() && !namespaceURI.isNull(); 209 } 210 return toElement(node)->hasLocalName(name) && namespaceURI == node->namespaceURI(); 211 } 212 } 213 ASSERT_NOT_REACHED(); 214 return false; 215 } 216 217 static inline bool nodeMatches(Node* node, Step::Axis axis, const Step::NodeTest& nodeTest) 218 { 219 if (!nodeMatchesBasicTest(node, axis, nodeTest)) 220 return false; 221 222 EvaluationContext& evaluationContext = Expression::evaluationContext(); 223 224 // Only the first merged predicate may depend on position. 225 ++evaluationContext.position; 226 227 const Vector<OwnPtr<Predicate> >& mergedPredicates = nodeTest.mergedPredicates(); 228 for (unsigned i = 0; i < mergedPredicates.size(); i++) { 229 Predicate* predicate = mergedPredicates[i].get(); 230 231 evaluationContext.node = node; 232 // No need to set context size - we only get here when evaluating predicates that do not depend on it. 233 if (!predicate->evaluate()) 234 return false; 235 } 236 237 return true; 238 } 239 240 // Result nodes are ordered in axis order. Node test (including merged predicates) is applied. 241 void Step::nodesInAxis(Node* context, NodeSet& nodes) const 242 { 243 ASSERT(nodes.isEmpty()); 244 switch (m_axis) { 245 case ChildAxis: 246 if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children. 247 return; 248 249 for (Node* n = context->firstChild(); n; n = n->nextSibling()) 250 if (nodeMatches(n, ChildAxis, m_nodeTest)) 251 nodes.append(n); 252 return; 253 case DescendantAxis: 254 if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children. 255 return; 256 257 for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context)) 258 if (nodeMatches(n, DescendantAxis, m_nodeTest)) 259 nodes.append(n); 260 return; 261 case ParentAxis: 262 if (context->isAttributeNode()) { 263 Element* n = toAttr(context)->ownerElement(); 264 if (nodeMatches(n, ParentAxis, m_nodeTest)) 265 nodes.append(n); 266 } else { 267 ContainerNode* n = context->parentNode(); 268 if (n && nodeMatches(n, ParentAxis, m_nodeTest)) 269 nodes.append(n); 270 } 271 return; 272 case AncestorAxis: { 273 Node* n = context; 274 if (context->isAttributeNode()) { 275 n = toAttr(context)->ownerElement(); 276 if (nodeMatches(n, AncestorAxis, m_nodeTest)) 277 nodes.append(n); 278 } 279 for (n = n->parentNode(); n; n = n->parentNode()) 280 if (nodeMatches(n, AncestorAxis, m_nodeTest)) 281 nodes.append(n); 282 nodes.markSorted(false); 283 return; 284 } 285 case FollowingSiblingAxis: 286 if (context->nodeType() == Node::ATTRIBUTE_NODE || 287 context->nodeType() == Node::XPATH_NAMESPACE_NODE) 288 return; 289 290 for (Node* n = context->nextSibling(); n; n = n->nextSibling()) 291 if (nodeMatches(n, FollowingSiblingAxis, m_nodeTest)) 292 nodes.append(n); 293 return; 294 case PrecedingSiblingAxis: 295 if (context->nodeType() == Node::ATTRIBUTE_NODE || 296 context->nodeType() == Node::XPATH_NAMESPACE_NODE) 297 return; 298 299 for (Node* n = context->previousSibling(); n; n = n->previousSibling()) 300 if (nodeMatches(n, PrecedingSiblingAxis, m_nodeTest)) 301 nodes.append(n); 302 303 nodes.markSorted(false); 304 return; 305 case FollowingAxis: 306 if (context->isAttributeNode()) { 307 Node* p = toAttr(context)->ownerElement(); 308 while ((p = NodeTraversal::next(*p))) { 309 if (nodeMatches(p, FollowingAxis, m_nodeTest)) 310 nodes.append(p); 311 } 312 } else { 313 for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) { 314 for (Node* n = p->nextSibling(); n; n = n->nextSibling()) { 315 if (nodeMatches(n, FollowingAxis, m_nodeTest)) 316 nodes.append(n); 317 for (Node* c = n->firstChild(); c; c = NodeTraversal::next(*c, n)) 318 if (nodeMatches(c, FollowingAxis, m_nodeTest)) 319 nodes.append(c); 320 } 321 } 322 } 323 return; 324 case PrecedingAxis: { 325 if (context->isAttributeNode()) 326 context = toAttr(context)->ownerElement(); 327 328 Node* n = context; 329 while (ContainerNode* parent = n->parentNode()) { 330 for (n = NodeTraversal::previous(*n); n != parent; n = NodeTraversal::previous(*n)) 331 if (nodeMatches(n, PrecedingAxis, m_nodeTest)) 332 nodes.append(n); 333 n = parent; 334 } 335 nodes.markSorted(false); 336 return; 337 } 338 case AttributeAxis: { 339 if (!context->isElementNode()) 340 return; 341 342 Element* contextElement = toElement(context); 343 344 // Avoid lazily creating attribute nodes for attributes that we do not need anyway. 345 if (m_nodeTest.kind() == NodeTest::NameTest && m_nodeTest.data() != starAtom) { 346 RefPtr<Node> n = contextElement->getAttributeNodeNS(m_nodeTest.namespaceURI(), m_nodeTest.data()); 347 if (n && n->namespaceURI() != XMLNSNames::xmlnsNamespaceURI) { // In XPath land, namespace nodes are not accessible on the attribute axis. 348 if (nodeMatches(n.get(), AttributeAxis, m_nodeTest)) // Still need to check merged predicates. 349 nodes.append(n.release()); 350 } 351 return; 352 } 353 354 if (!contextElement->hasAttributes()) 355 return; 356 357 for (unsigned i = 0; i < contextElement->attributeCount(); ++i) { 358 RefPtr<Attr> attr = contextElement->ensureAttr(contextElement->attributeItem(i)->name()); 359 if (nodeMatches(attr.get(), AttributeAxis, m_nodeTest)) 360 nodes.append(attr.release()); 361 } 362 return; 363 } 364 case NamespaceAxis: 365 // XPath namespace nodes are not implemented yet. 366 return; 367 case SelfAxis: 368 if (nodeMatches(context, SelfAxis, m_nodeTest)) 369 nodes.append(context); 370 return; 371 case DescendantOrSelfAxis: 372 if (nodeMatches(context, DescendantOrSelfAxis, m_nodeTest)) 373 nodes.append(context); 374 if (context->isAttributeNode()) // In XPath model, attribute nodes do not have children. 375 return; 376 377 for (Node* n = context->firstChild(); n; n = NodeTraversal::next(*n, context)) 378 if (nodeMatches(n, DescendantOrSelfAxis, m_nodeTest)) 379 nodes.append(n); 380 return; 381 case AncestorOrSelfAxis: { 382 if (nodeMatches(context, AncestorOrSelfAxis, m_nodeTest)) 383 nodes.append(context); 384 Node* n = context; 385 if (context->isAttributeNode()) { 386 n = toAttr(context)->ownerElement(); 387 if (nodeMatches(n, AncestorOrSelfAxis, m_nodeTest)) 388 nodes.append(n); 389 } 390 for (n = n->parentNode(); n; n = n->parentNode()) 391 if (nodeMatches(n, AncestorOrSelfAxis, m_nodeTest)) 392 nodes.append(n); 393 394 nodes.markSorted(false); 395 return; 396 } 397 } 398 ASSERT_NOT_REACHED(); 399 } 400 401 402 } 403 } 404