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 "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 , 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 = m_value.toNodeSet(); 61 m_document = document; 62 m_domTreeVersion = document->domTreeVersion(); 63 return; 64 } 65 ASSERT_NOT_REACHED(); 66 } 67 68 XPathResult::~XPathResult() 69 { 70 } 71 72 void XPathResult::convertTo(unsigned short type, ExceptionCode& ec) 73 { 74 switch (type) { 75 case ANY_TYPE: 76 break; 77 case NUMBER_TYPE: 78 m_resultType = type; 79 m_value = m_value.toNumber(); 80 break; 81 case STRING_TYPE: 82 m_resultType = type; 83 m_value = m_value.toString(); 84 break; 85 case BOOLEAN_TYPE: 86 m_resultType = type; 87 m_value = m_value.toBoolean(); 88 break; 89 case UNORDERED_NODE_ITERATOR_TYPE: 90 case UNORDERED_NODE_SNAPSHOT_TYPE: 91 case ANY_UNORDERED_NODE_TYPE: 92 case FIRST_ORDERED_NODE_TYPE: // This is correct - singleNodeValue() will take care of ordering. 93 if (!m_value.isNodeSet()) { 94 ec = XPathException::TYPE_ERR; 95 return; 96 } 97 m_resultType = type; 98 break; 99 case ORDERED_NODE_ITERATOR_TYPE: 100 if (!m_value.isNodeSet()) { 101 ec = XPathException::TYPE_ERR; 102 return; 103 } 104 m_nodeSet.sort(); 105 m_resultType = type; 106 break; 107 case ORDERED_NODE_SNAPSHOT_TYPE: 108 if (!m_value.isNodeSet()) { 109 ec = XPathException::TYPE_ERR; 110 return; 111 } 112 m_value.toNodeSet().sort(); 113 m_resultType = type; 114 break; 115 } 116 } 117 118 unsigned short XPathResult::resultType() const 119 { 120 return m_resultType; 121 } 122 123 double XPathResult::numberValue(ExceptionCode& ec) const 124 { 125 if (resultType() != NUMBER_TYPE) { 126 ec = XPathException::TYPE_ERR; 127 return 0.0; 128 } 129 return m_value.toNumber(); 130 } 131 132 String XPathResult::stringValue(ExceptionCode& ec) const 133 { 134 if (resultType() != STRING_TYPE) { 135 ec = XPathException::TYPE_ERR; 136 return String(); 137 } 138 return m_value.toString(); 139 } 140 141 bool XPathResult::booleanValue(ExceptionCode& ec) const 142 { 143 if (resultType() != BOOLEAN_TYPE) { 144 ec = XPathException::TYPE_ERR; 145 return false; 146 } 147 return m_value.toBoolean(); 148 } 149 150 Node* XPathResult::singleNodeValue(ExceptionCode& ec) const 151 { 152 if (resultType() != ANY_UNORDERED_NODE_TYPE && resultType() != FIRST_ORDERED_NODE_TYPE) { 153 ec = XPathException::TYPE_ERR; 154 return 0; 155 } 156 157 const NodeSet& nodes = m_value.toNodeSet(); 158 if (resultType() == FIRST_ORDERED_NODE_TYPE) 159 return nodes.firstNode(); 160 else 161 return nodes.anyNode(); 162 } 163 164 bool XPathResult::invalidIteratorState() const 165 { 166 if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE) 167 return false; 168 169 ASSERT(m_document); 170 return m_document->domTreeVersion() != m_domTreeVersion; 171 } 172 173 unsigned long XPathResult::snapshotLength(ExceptionCode& ec) const 174 { 175 if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) { 176 ec = XPathException::TYPE_ERR; 177 return 0; 178 } 179 180 return m_value.toNodeSet().size(); 181 } 182 183 Node* XPathResult::iterateNext(ExceptionCode& ec) 184 { 185 if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE) { 186 ec = XPathException::TYPE_ERR; 187 return 0; 188 } 189 190 if (invalidIteratorState()) { 191 ec = INVALID_STATE_ERR; 192 return 0; 193 } 194 195 if (m_nodeSetPosition + 1 > m_nodeSet.size()) 196 return 0; 197 198 Node* node = m_nodeSet[m_nodeSetPosition]; 199 200 m_nodeSetPosition++; 201 202 return node; 203 } 204 205 Node* XPathResult::snapshotItem(unsigned long index, ExceptionCode& ec) 206 { 207 if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE) { 208 ec = XPathException::TYPE_ERR; 209 return 0; 210 } 211 212 const NodeSet& nodes = m_value.toNodeSet(); 213 if (index >= nodes.size()) 214 return 0; 215 216 return nodes[index]; 217 } 218 219 } 220 221 #endif // ENABLE(XPATH) 222