1 /*
2 * Copyright (C) 2005 Frerich Raabe <raabe@kde.org>
3 * Copyright (C) 2006, 2009 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #include "core/xml/XPathResult.h"
29
30 #include "bindings/v8/ExceptionState.h"
31 #include "core/dom/Document.h"
32 #include "core/dom/ExceptionCode.h"
33 #include "core/xml/XPathEvaluator.h"
34
35 namespace WebCore {
36
37 using namespace XPath;
38
XPathResult(Document * document,const Value & value)39 XPathResult::XPathResult(Document* document, const Value& value)
40 : m_value(value)
41 , m_nodeSetPosition(0)
42 , m_domTreeVersion(0)
43 {
44 ScriptWrappable::init(this);
45 switch (m_value.type()) {
46 case Value::BooleanValue:
47 m_resultType = BOOLEAN_TYPE;
48 return;
49 case Value::NumberValue:
50 m_resultType = NUMBER_TYPE;
51 return;
52 case Value::StringValue:
53 m_resultType = STRING_TYPE;
54 return;
55 case Value::NodeSetValue:
56 m_resultType = UNORDERED_NODE_ITERATOR_TYPE;
57 m_nodeSetPosition = 0;
58 m_nodeSet = NodeSet::create(m_value.toNodeSet());
59 m_document = document;
60 m_domTreeVersion = document->domTreeVersion();
61 return;
62 }
63 ASSERT_NOT_REACHED();
64 }
65
~XPathResult()66 XPathResult::~XPathResult()
67 {
68 }
69
trace(Visitor * visitor)70 void XPathResult::trace(Visitor* visitor)
71 {
72 visitor->trace(m_value);
73 visitor->trace(m_nodeSet);
74 visitor->trace(m_document);
75 }
76
convertTo(unsigned short type,ExceptionState & exceptionState)77 void XPathResult::convertTo(unsigned short type, ExceptionState& exceptionState)
78 {
79 switch (type) {
80 case ANY_TYPE:
81 break;
82 case NUMBER_TYPE:
83 m_resultType = type;
84 m_value = m_value.toNumber();
85 break;
86 case STRING_TYPE:
87 m_resultType = type;
88 m_value = m_value.toString();
89 break;
90 case BOOLEAN_TYPE:
91 m_resultType = type;
92 m_value = m_value.toBoolean();
93 break;
94 case UNORDERED_NODE_ITERATOR_TYPE:
95 case UNORDERED_NODE_SNAPSHOT_TYPE:
96 case ANY_UNORDERED_NODE_TYPE:
97 // This is correct - singleNodeValue() will take care of ordering.
98 case FIRST_ORDERED_NODE_TYPE:
99 if (!m_value.isNodeSet()) {
100 exceptionState.throwTypeError("The result is not a node set, and therefore cannot be converted to the desired type.");
101 return;
102 }
103 m_resultType = type;
104 break;
105 case ORDERED_NODE_ITERATOR_TYPE:
106 if (!m_value.isNodeSet()) {
107 exceptionState.throwTypeError("The result is not a node set, and therefore cannot be converted to the desired type.");
108 return;
109 }
110 nodeSet().sort();
111 m_resultType = type;
112 break;
113 case ORDERED_NODE_SNAPSHOT_TYPE:
114 if (!m_value.isNodeSet()) {
115 exceptionState.throwTypeError("The result is not a node set, and therefore cannot be converted to the desired type.");
116 return;
117 }
118 m_value.toNodeSet().sort();
119 m_resultType = type;
120 break;
121 }
122 }
123
resultType() const124 unsigned short XPathResult::resultType() const
125 {
126 return m_resultType;
127 }
128
numberValue(ExceptionState & exceptionState) const129 double XPathResult::numberValue(ExceptionState& exceptionState) const
130 {
131 if (resultType() != NUMBER_TYPE) {
132 exceptionState.throwTypeError("The result type is not a number.");
133 return 0.0;
134 }
135 return m_value.toNumber();
136 }
137
stringValue(ExceptionState & exceptionState) const138 String XPathResult::stringValue(ExceptionState& exceptionState) const
139 {
140 if (resultType() != STRING_TYPE) {
141 exceptionState.throwTypeError("The result type is not a string.");
142 return String();
143 }
144 return m_value.toString();
145 }
146
booleanValue(ExceptionState & exceptionState) const147 bool XPathResult::booleanValue(ExceptionState& exceptionState) const
148 {
149 if (resultType() != BOOLEAN_TYPE) {
150 exceptionState.throwTypeError("The result type is not a boolean.");
151 return false;
152 }
153 return m_value.toBoolean();
154 }
155
singleNodeValue(ExceptionState & exceptionState) const156 Node* XPathResult::singleNodeValue(ExceptionState& exceptionState) const
157 {
158 if (resultType() != ANY_UNORDERED_NODE_TYPE && resultType() != FIRST_ORDERED_NODE_TYPE) {
159 exceptionState.throwTypeError("The result type is not a single node.");
160 return 0;
161 }
162
163 const NodeSet& nodes = m_value.toNodeSet();
164 if (resultType() == FIRST_ORDERED_NODE_TYPE)
165 return nodes.firstNode();
166 return nodes.anyNode();
167 }
168
invalidIteratorState() const169 bool XPathResult::invalidIteratorState() const
170 {
171 if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE)
172 return false;
173
174 ASSERT(m_document);
175 return m_document->domTreeVersion() != m_domTreeVersion;
176 }
177
snapshotLength(ExceptionState & exceptionState) const178 unsigned long XPathResult::snapshotLength(ExceptionState& exceptionState) const
179 {
180 if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) {
181 exceptionState.throwTypeError("The result type is not a snapshot.");
182 return 0;
183 }
184
185 return m_value.toNodeSet().size();
186 }
187
iterateNext(ExceptionState & exceptionState)188 Node* XPathResult::iterateNext(ExceptionState& exceptionState)
189 {
190 if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE) {
191 exceptionState.throwTypeError("The result type is not an iterator.");
192 return 0;
193 }
194
195 if (invalidIteratorState()) {
196 exceptionState.throwDOMException(InvalidStateError, "The document has mutated since the result was returned.");
197 return 0;
198 }
199
200 if (m_nodeSetPosition + 1 > nodeSet().size())
201 return 0;
202
203 Node* node = nodeSet()[m_nodeSetPosition];
204
205 m_nodeSetPosition++;
206
207 return node;
208 }
209
snapshotItem(unsigned long index,ExceptionState & exceptionState)210 Node* XPathResult::snapshotItem(unsigned long index, ExceptionState& exceptionState)
211 {
212 if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) {
213 exceptionState.throwTypeError("The result type is not a snapshot.");
214 return 0;
215 }
216
217 const NodeSet& nodes = m_value.toNodeSet();
218 if (index >= nodes.size())
219 return 0;
220
221 return nodes[index];
222 }
223
224 }
225