• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 = 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 
convertTo(unsigned short type,ExceptionState & exceptionState)70 void XPathResult::convertTo(unsigned short type, ExceptionState& exceptionState)
71 {
72     switch (type) {
73         case ANY_TYPE:
74             break;
75         case NUMBER_TYPE:
76             m_resultType = type;
77             m_value = m_value.toNumber();
78             break;
79         case STRING_TYPE:
80             m_resultType = type;
81             m_value = m_value.toString();
82             break;
83         case BOOLEAN_TYPE:
84             m_resultType = type;
85             m_value = m_value.toBoolean();
86             break;
87         case UNORDERED_NODE_ITERATOR_TYPE:
88         case UNORDERED_NODE_SNAPSHOT_TYPE:
89         case ANY_UNORDERED_NODE_TYPE:
90         case FIRST_ORDERED_NODE_TYPE: // This is correct - singleNodeValue() will take care of ordering.
91             if (!m_value.isNodeSet()) {
92                 exceptionState.throwTypeError("The result is not a node set, and therefore cannot be converted to the desired type.");
93                 return;
94             }
95             m_resultType = type;
96             break;
97         case ORDERED_NODE_ITERATOR_TYPE:
98             if (!m_value.isNodeSet()) {
99                 exceptionState.throwTypeError("The result is not a node set, and therefore cannot be converted to the desired type.");
100                 return;
101             }
102             m_nodeSet.sort();
103             m_resultType = type;
104             break;
105         case ORDERED_NODE_SNAPSHOT_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             m_value.toNodeSet().sort();
111             m_resultType = type;
112             break;
113     }
114 }
115 
resultType() const116 unsigned short XPathResult::resultType() const
117 {
118     return m_resultType;
119 }
120 
numberValue(ExceptionState & exceptionState) const121 double XPathResult::numberValue(ExceptionState& exceptionState) const
122 {
123     if (resultType() != NUMBER_TYPE) {
124         exceptionState.throwTypeError("The result type is not a number.");
125         return 0.0;
126     }
127     return m_value.toNumber();
128 }
129 
stringValue(ExceptionState & exceptionState) const130 String XPathResult::stringValue(ExceptionState& exceptionState) const
131 {
132     if (resultType() != STRING_TYPE) {
133         exceptionState.throwTypeError("The result type is not a string.");
134         return String();
135     }
136     return m_value.toString();
137 }
138 
booleanValue(ExceptionState & exceptionState) const139 bool XPathResult::booleanValue(ExceptionState& exceptionState) const
140 {
141     if (resultType() != BOOLEAN_TYPE) {
142         exceptionState.throwTypeError("The result type is not a boolean.");
143         return false;
144     }
145     return m_value.toBoolean();
146 }
147 
singleNodeValue(ExceptionState & exceptionState) const148 Node* XPathResult::singleNodeValue(ExceptionState& exceptionState) const
149 {
150     if (resultType() != ANY_UNORDERED_NODE_TYPE && resultType() != FIRST_ORDERED_NODE_TYPE) {
151         exceptionState.throwTypeError("The result type is not a single node.");
152         return 0;
153     }
154 
155     const NodeSet& nodes = m_value.toNodeSet();
156     if (resultType() == FIRST_ORDERED_NODE_TYPE)
157         return nodes.firstNode();
158     else
159         return nodes.anyNode();
160 }
161 
invalidIteratorState() const162 bool XPathResult::invalidIteratorState() const
163 {
164     if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE)
165         return false;
166 
167     ASSERT(m_document);
168     return m_document->domTreeVersion() != m_domTreeVersion;
169 }
170 
snapshotLength(ExceptionState & exceptionState) const171 unsigned long XPathResult::snapshotLength(ExceptionState& exceptionState) const
172 {
173     if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) {
174         exceptionState.throwTypeError("The result type is not a snapshot.");
175         return 0;
176     }
177 
178     return m_value.toNodeSet().size();
179 }
180 
iterateNext(ExceptionState & exceptionState)181 Node* XPathResult::iterateNext(ExceptionState& exceptionState)
182 {
183     if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE) {
184         exceptionState.throwTypeError("The result type is not an iterator.");
185         return 0;
186     }
187 
188     if (invalidIteratorState()) {
189         exceptionState.throwDOMException(InvalidStateError, "The document has mutated since the result was returned.");
190         return 0;
191     }
192 
193     if (m_nodeSetPosition + 1 > m_nodeSet.size())
194         return 0;
195 
196     Node* node = m_nodeSet[m_nodeSetPosition];
197 
198     m_nodeSetPosition++;
199 
200     return node;
201 }
202 
snapshotItem(unsigned long index,ExceptionState & exceptionState)203 Node* XPathResult::snapshotItem(unsigned long index, ExceptionState& exceptionState)
204 {
205     if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) {
206         exceptionState.throwTypeError("The result type is not a snapshot.");
207         return 0;
208     }
209 
210     const NodeSet& nodes = m_value.toNodeSet();
211     if (index >= nodes.size())
212         return 0;
213 
214     return nodes[index];
215 }
216 
217 }
218