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#include "Document.h" 31#include "Node.h" 32#include "ExceptionCode.h" 33#include "XPathEvaluator.h" 34#include "XPathException.h" 35 36namespace WebCore { 37 38using namespace XPath; 39 40XPathResult::XPathResult(Document* document, const Value& value) 41 : m_value(value) 42 , m_nodeSetPosition(0) 43 , m_domTreeVersion(0) 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 66XPathResult::~XPathResult() 67{ 68} 69 70void 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 116unsigned short XPathResult::resultType() const 117{ 118 return m_resultType; 119} 120 121double 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 130String 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 139bool 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 148Node* 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 162bool 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 171unsigned 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 181Node* 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 203Node* 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