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/core/v8/ExceptionState.h" 31 #include "core/dom/Document.h" 32 #include "core/dom/ExceptionCode.h" 33 #include "core/xml/XPathEvaluator.h" 34 #include "core/xml/XPathExpressionNode.h" 35 36 namespace blink { 37 38 using namespace XPath; 39 40 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(XPathResult); 41 42 XPathResult::XPathResult(EvaluationContext& context, const Value& value) 43 : m_value(value) 44 , m_nodeSetPosition(0) 45 , m_domTreeVersion(0) 46 { 47 switch (m_value.type()) { 48 case Value::BooleanValue: 49 m_resultType = BOOLEAN_TYPE; 50 return; 51 case Value::NumberValue: 52 m_resultType = NUMBER_TYPE; 53 return; 54 case Value::StringValue: 55 m_resultType = STRING_TYPE; 56 return; 57 case Value::NodeSetValue: 58 m_resultType = UNORDERED_NODE_ITERATOR_TYPE; 59 m_nodeSetPosition = 0; 60 m_nodeSet = NodeSet::create(m_value.toNodeSet(&context)); 61 m_document = &context.node->document(); 62 m_domTreeVersion = m_document->domTreeVersion(); 63 return; 64 } 65 ASSERT_NOT_REACHED(); 66 } 67 68 void XPathResult::trace(Visitor* visitor) 69 { 70 visitor->trace(m_value); 71 visitor->trace(m_nodeSet); 72 visitor->trace(m_document); 73 } 74 75 void XPathResult::convertTo(unsigned short type, ExceptionState& exceptionState) 76 { 77 switch (type) { 78 case ANY_TYPE: 79 break; 80 case NUMBER_TYPE: 81 m_resultType = type; 82 m_value = m_value.toNumber(); 83 break; 84 case STRING_TYPE: 85 m_resultType = type; 86 m_value = m_value.toString(); 87 break; 88 case BOOLEAN_TYPE: 89 m_resultType = type; 90 m_value = m_value.toBoolean(); 91 break; 92 case UNORDERED_NODE_ITERATOR_TYPE: 93 case UNORDERED_NODE_SNAPSHOT_TYPE: 94 case ANY_UNORDERED_NODE_TYPE: 95 // This is correct - singleNodeValue() will take care of ordering. 96 case FIRST_ORDERED_NODE_TYPE: 97 if (!m_value.isNodeSet()) { 98 exceptionState.throwTypeError("The result is not a node set, and therefore cannot be converted to the desired type."); 99 return; 100 } 101 m_resultType = type; 102 break; 103 case ORDERED_NODE_ITERATOR_TYPE: 104 if (!m_value.isNodeSet()) { 105 exceptionState.throwTypeError("The result is not a node set, and therefore cannot be converted to the desired type."); 106 return; 107 } 108 nodeSet().sort(); 109 m_resultType = type; 110 break; 111 case ORDERED_NODE_SNAPSHOT_TYPE: 112 if (!m_value.isNodeSet()) { 113 exceptionState.throwTypeError("The result is not a node set, and therefore cannot be converted to the desired type."); 114 return; 115 } 116 m_value.toNodeSet(0).sort(); 117 m_resultType = type; 118 break; 119 } 120 } 121 122 unsigned short XPathResult::resultType() const 123 { 124 return m_resultType; 125 } 126 127 double XPathResult::numberValue(ExceptionState& exceptionState) const 128 { 129 if (resultType() != NUMBER_TYPE) { 130 exceptionState.throwTypeError("The result type is not a number."); 131 return 0.0; 132 } 133 return m_value.toNumber(); 134 } 135 136 String XPathResult::stringValue(ExceptionState& exceptionState) const 137 { 138 if (resultType() != STRING_TYPE) { 139 exceptionState.throwTypeError("The result type is not a string."); 140 return String(); 141 } 142 return m_value.toString(); 143 } 144 145 bool XPathResult::booleanValue(ExceptionState& exceptionState) const 146 { 147 if (resultType() != BOOLEAN_TYPE) { 148 exceptionState.throwTypeError("The result type is not a boolean."); 149 return false; 150 } 151 return m_value.toBoolean(); 152 } 153 154 Node* XPathResult::singleNodeValue(ExceptionState& exceptionState) const 155 { 156 if (resultType() != ANY_UNORDERED_NODE_TYPE && resultType() != FIRST_ORDERED_NODE_TYPE) { 157 exceptionState.throwTypeError("The result type is not a single node."); 158 return 0; 159 } 160 161 const NodeSet& nodes = m_value.toNodeSet(0); 162 if (resultType() == FIRST_ORDERED_NODE_TYPE) 163 return nodes.firstNode(); 164 return nodes.anyNode(); 165 } 166 167 bool XPathResult::invalidIteratorState() const 168 { 169 if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE) 170 return false; 171 172 ASSERT(m_document); 173 return m_document->domTreeVersion() != m_domTreeVersion; 174 } 175 176 unsigned long XPathResult::snapshotLength(ExceptionState& exceptionState) const 177 { 178 if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) { 179 exceptionState.throwTypeError("The result type is not a snapshot."); 180 return 0; 181 } 182 183 return m_value.toNodeSet(0).size(); 184 } 185 186 Node* XPathResult::iterateNext(ExceptionState& exceptionState) 187 { 188 if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE) { 189 exceptionState.throwTypeError("The result type is not an iterator."); 190 return 0; 191 } 192 193 if (invalidIteratorState()) { 194 exceptionState.throwDOMException(InvalidStateError, "The document has mutated since the result was returned."); 195 return 0; 196 } 197 198 if (m_nodeSetPosition + 1 > nodeSet().size()) 199 return 0; 200 201 Node* node = nodeSet()[m_nodeSetPosition]; 202 203 m_nodeSetPosition++; 204 205 return node; 206 } 207 208 Node* XPathResult::snapshotItem(unsigned long index, ExceptionState& exceptionState) 209 { 210 if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) { 211 exceptionState.throwTypeError("The result type is not a snapshot."); 212 return 0; 213 } 214 215 const NodeSet& nodes = m_value.toNodeSet(0); 216 if (index >= nodes.size()) 217 return 0; 218 219 return nodes[index]; 220 } 221 222 } 223