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 = NodeSet::create(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::trace(Visitor* visitor) 71 { 72 visitor->trace(m_value); 73 visitor->trace(m_nodeSet); 74 visitor->trace(m_document); 75 } 76 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 124 unsigned short XPathResult::resultType() const 125 { 126 return m_resultType; 127 } 128 129 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 138 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 147 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 156 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 169 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 178 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 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 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