Reviewed by Adele.
[WebKit-https.git] / WebCore / xml / XPathStep.cpp
1 /*
2  * Copyright 2005 Frerich Raabe <raabe@kde.org>
3  * Copyright (C) 2006 Apple Computer, Inc.
4  * Copyright (C) 2007 Alexey Proskuryakov <ap@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 "XPathStep.h"
30
31 #if ENABLE(XPATH)
32
33 #include "Document.h"
34 #include "NamedAttrMap.h"
35 #include "XPathNSResolver.h"
36 #include "XPathParser.h"
37
38 namespace WebCore {
39 namespace XPath {
40
41 Step::Step(Axis axis, const NodeTest& nodeTest, const Vector<Predicate*>& predicates)
42     : m_axis(axis)
43     , m_nodeTest(nodeTest)
44     , m_predicates(predicates)
45 {
46 }
47
48 Step::Step(Axis axis, const NodeTest& nodeTest, const String& namespaceURI, const Vector<Predicate*>& predicates)
49     : m_axis(axis)
50     , m_nodeTest(nodeTest)
51     , m_namespaceURI(namespaceURI)
52     , m_predicates(predicates)
53 {
54 }
55
56 Step::~Step()
57 {
58     deleteAllValues(m_predicates);
59 }
60
61 NodeVector Step::evaluate(Node* context) const
62 {
63     NodeVector nodes = nodesInAxis(context);
64     nodes = nodeTestMatches(nodes);
65     
66     EvaluationContext& evaluationContext = Expression::evaluationContext();
67     
68     for (unsigned i = 0; i < m_predicates.size(); i++) {
69         Predicate* predicate = m_predicates[i];
70
71         NodeVector newNodes;
72         evaluationContext.size = nodes.size();
73         evaluationContext.position = 1;
74         for (unsigned j = 0; j < nodes.size(); j++) {
75             Node* node = nodes[j].get();
76
77             Expression::evaluationContext().node = node;
78             EvaluationContext backupCtx = evaluationContext;
79             if (predicate->evaluate())
80                 newNodes.append(node);
81
82             evaluationContext = backupCtx;
83             ++evaluationContext.position;
84         }
85
86         nodes.swap(newNodes);
87     }
88     return nodes;
89 }
90
91 NodeVector Step::nodesInAxis(Node* context) const
92 {
93     NodeVector nodes;
94     switch (m_axis) {
95         case ChildAxis:
96             for (Node* n = context->firstChild(); n; n = n->nextSibling())
97                 nodes.append(n);
98             return nodes;
99         case DescendantAxis: 
100             for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context))
101                 nodes.append(n);
102             return nodes;
103         case ParentAxis: {
104             Node* parent = context->parentNode();
105             if (parent)
106                 nodes.append(parent);
107             return nodes;
108         }
109         case AncestorAxis:
110             for (Node* n = context->parentNode(); n; n = n->parentNode())
111                 nodes.append(n);
112             return nodes;
113         case FollowingSiblingAxis:
114             if (context->nodeType() == Node::ATTRIBUTE_NODE ||
115                  context->nodeType() == Node::XPATH_NAMESPACE_NODE) 
116                 return NodeVector();
117             
118             for (Node* n = context->nextSibling(); n; n = n->nextSibling())
119                 nodes.append(n);
120             return nodes;
121         case PrecedingSiblingAxis:
122             if (context->nodeType() == Node::ATTRIBUTE_NODE ||
123                  context->nodeType() == Node::XPATH_NAMESPACE_NODE)
124                 return NodeVector();
125             
126             for (Node* n = context->previousSibling(); n; n = n->previousSibling())
127                 nodes.append(n);
128             return nodes;
129         case FollowingAxis: 
130             for (Node *p = context; !isRootDomNode(p); p = p->parentNode()) {
131                 for (Node* n = p->nextSibling(); n; n = n->nextSibling()) {
132                     nodes.append(n);
133                     for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n))
134                         nodes.append(c);
135                 }
136             }
137             return nodes;
138         case PrecedingAxis:
139             for (Node* p = context; !isRootDomNode(p); p = p->parentNode()) {
140                 for (Node* n = p->previousSibling(); n ; n = n->previousSibling()) {
141                     nodes.append(n);
142                     for (Node* c = n->firstChild(); c; c = c->traverseNextNode(n))
143                         nodes.append(c);
144                 }
145             }
146             return nodes;
147         case AttributeAxis: {
148             if (context->nodeType() != Node::ELEMENT_NODE)
149                 return NodeVector();
150
151             NamedAttrMap* attrs = context->attributes();
152             if (!attrs)
153                 return nodes;
154
155             for (unsigned long i = 0; i < attrs->length(); ++i) 
156                 nodes.append (attrs->item(i));
157             return nodes;
158         }
159         case NamespaceAxis:
160             // XPath namespace nodes are not implemented yet.
161             return NodeVector();
162         case SelfAxis:
163             nodes.append(context);
164             return nodes;
165         case DescendantOrSelfAxis:
166             nodes.append(context);
167             for (Node* n = context->firstChild(); n; n = n->traverseNextNode(context))
168                 nodes.append(n);
169             return nodes;
170         case AncestorOrSelfAxis:
171             nodes.append(context);
172             for (Node* n = context->parentNode(); n; n = n->parentNode())
173                 nodes.append(n);
174             return nodes;
175     }
176     ASSERT_NOT_REACHED();
177     return NodeVector();
178 }
179
180
181 NodeVector Step::nodeTestMatches(const NodeVector& nodes) const
182 {
183     NodeVector matches;
184
185     switch (m_nodeTest.kind()) {
186         case NodeTest::TextNodeTest:
187             for (unsigned i = 0; i < nodes.size(); i++) {
188                 Node* node = nodes[i].get();
189                 if ((node->nodeType() == Node::TEXT_NODE || node->nodeType() == Node::CDATA_SECTION_NODE))
190                     matches.append(node);
191             }
192             return matches;
193         case NodeTest::CommentNodeTest:
194             for (unsigned i = 0; i < nodes.size(); i++) {
195                 Node* node = nodes[i].get();
196                 if (node->nodeType() == Node::COMMENT_NODE)
197                     matches.append(node);
198             }
199             return matches;
200         case NodeTest::ProcessingInstructionNodeTest:
201             for (unsigned i = 0; i < nodes.size(); i++) {
202                 Node* node = nodes[i].get();
203                 const String& name = m_nodeTest.data();
204                 if (node->nodeType() == Node::PROCESSING_INSTRUCTION_NODE && (name.isEmpty() || node->nodeName() == name))
205                         matches.append(node);
206             }    
207             return matches;
208         case NodeTest::ElementNodeTest:
209             for (unsigned i = 0; i < nodes.size(); i++) {
210                 Node* node = nodes[i].get();
211                 if (node->isElementNode())
212                     matches.append(node);
213             }
214             return matches;
215         case NodeTest::AnyNodeTest:
216             return nodes;
217         case NodeTest::NameTest: {
218             const String& name = m_nodeTest.data();
219             if (name == "*") {
220                 for (unsigned i = 0; i < nodes.size(); i++) {
221                     Node* node = nodes[i].get();
222                     if (node->nodeType() == primaryNodeType(m_axis) &&
223                         (m_namespaceURI.isEmpty() || m_namespaceURI == node->namespaceURI()))
224                         matches.append(node);
225                 }
226                 return matches;
227             }
228             if (m_axis == AttributeAxis) {
229                 // In XPath land, namespace nodes are not accessible
230                 // on the attribute axis.
231                 if (name == "xmlns")
232                     return matches;
233
234                 for (unsigned i = 0; i < nodes.size(); i++) {
235                     Node* node = nodes[i].get();
236                     
237                     if (node->nodeName() == name) {
238                         matches.append(node);
239                         break; // There can only be one.
240                     }
241                 }
242
243                 return matches;
244             } else if (m_axis == NamespaceAxis) {
245                 // Node test on the namespace axis is not implemented yet
246             } else {
247                 for (unsigned i = 0; i < nodes.size(); i++) {
248                     Node* node = nodes[i].get();
249
250                     // We use tagQName here because we don't want the element name in uppercase 
251                     // like we get with HTML elements.
252                     // Paths without namespaces should match HTML elements in HTML documents despite those having an XHTML namespace.
253                     if (node->nodeType() == Node::ELEMENT_NODE
254                         && static_cast<Element*>(node)->tagQName().localName() == name
255                         && ((node->isHTMLElement() && node->document()->isHTMLDocument() && m_namespaceURI.isNull()) || m_namespaceURI == node->namespaceURI()))
256                         matches.append(node);
257                 }
258
259                 return matches;
260             }
261         }
262     }
263     ASSERT_NOT_REACHED();
264     return NodeVector();
265 }
266
267 Node::NodeType Step::primaryNodeType(Axis axis) const
268 {
269     switch (axis) {
270         case AttributeAxis:
271             return Node::ATTRIBUTE_NODE;
272         case NamespaceAxis:
273             return Node::XPATH_NAMESPACE_NODE;
274         default:
275             return Node::ELEMENT_NODE;
276     }
277 }
278
279 }
280 }
281
282 #endif // ENABLE(XPATH)