1 /* 2 * Copyright (C) 2005 Frerich Raabe <raabe (at) 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 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 66 XPathResult::~XPathResult() 67 { 68 } 69 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 116 unsigned short XPathResult::resultType() const 117 { 118 return m_resultType; 119 } 120 121 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 130 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 139 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 148 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 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(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 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 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