b608280c9b912d425dbed35a480e0aacaf0d7427
[WebKit-https.git] / Source / WebCore / xml / XPathResult.cpp
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 "XPathResult.h"
29
30 #if ENABLE(XPATH)
31
32 #include "Document.h"
33 #include "Node.h"
34 #include "ExceptionCode.h"
35 #include "XPathEvaluator.h"
36 #include "XPathException.h"
37
38 namespace WebCore {
39
40 using namespace XPath;
41
42 XPathResult::XPathResult(Document* document, const Value& value)
43     : m_value(value)
44 {
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
66 XPathResult::~XPathResult()
67 {
68 }
69
70 void XPathResult::convertTo(unsigned short type, ExceptionCode& ec)
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                 ec = XPathException::TYPE_ERR;
93                 return;
94             }
95             m_resultType = type;
96             break;
97         case ORDERED_NODE_ITERATOR_TYPE:
98             if (!m_value.isNodeSet()) {
99                 ec = XPathException::TYPE_ERR;
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                 ec = XPathException::TYPE_ERR;
108                 return;
109             }
110             m_value.toNodeSet().sort();
111             m_resultType = type;
112             break;
113     }
114 }
115
116 unsigned short XPathResult::resultType() const
117 {
118     return m_resultType;
119 }
120
121 double XPathResult::numberValue(ExceptionCode& ec) const
122 {
123     if (resultType() != NUMBER_TYPE) {
124         ec = XPathException::TYPE_ERR;
125         return 0.0;
126     }
127     return m_value.toNumber();
128 }
129
130 String XPathResult::stringValue(ExceptionCode& ec) const
131 {
132     if (resultType() != STRING_TYPE) {
133         ec = XPathException::TYPE_ERR;
134         return String();
135     }
136     return m_value.toString();
137 }
138
139 bool XPathResult::booleanValue(ExceptionCode& ec) const
140 {
141     if (resultType() != BOOLEAN_TYPE) {
142         ec = XPathException::TYPE_ERR;
143         return false;
144     }
145     return m_value.toBoolean();
146 }
147
148 Node* XPathResult::singleNodeValue(ExceptionCode& ec) const
149 {
150     if (resultType() != ANY_UNORDERED_NODE_TYPE && resultType() != FIRST_ORDERED_NODE_TYPE) {
151         ec = XPathException::TYPE_ERR;
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
162 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
171 unsigned long XPathResult::snapshotLength(ExceptionCode& ec) const
172 {
173     if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) {
174         ec = XPathException::TYPE_ERR;
175         return 0;
176     }
177
178     return m_value.toNodeSet().size();
179 }
180
181 Node* XPathResult::iterateNext(ExceptionCode& ec)
182 {
183     if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE) {
184         ec = XPathException::TYPE_ERR;
185         return 0;
186     }
187     
188     if (invalidIteratorState()) {
189         ec = INVALID_STATE_ERR;
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
203 Node* XPathResult::snapshotItem(unsigned long index, ExceptionCode& ec)
204 {
205     if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) {
206         ec = XPathException::TYPE_ERR;
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
219 #endif // ENABLE(XPATH)