File indexing completed on 2024-04-28 15:24:47
0001 /* 0002 * dom3_xpathimpl.cpp - Copyright 2005 Frerich Raabe <raabe@kde.org> 0003 * Copyright 2010 Maksim Orlovich <maksim@kde.org> 0004 * 0005 * Redistribution and use in source and binary forms, with or without 0006 * modification, are permitted provided that the following conditions 0007 * are met: 0008 * 0009 * 1. Redistributions of source code must retain the above copyright 0010 * notice, this list of conditions and the following disclaimer. 0011 * 2. Redistributions in binary form must reproduce the above copyright 0012 * notice, this list of conditions and the following disclaimer in the 0013 * documentation and/or other materials provided with the distribution. 0014 * 0015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0017 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0018 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0019 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0020 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0021 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0022 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0023 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0024 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0025 */ 0026 #include <dom/dom_exception.h> 0027 #include <dom/dom3_xpath.h> 0028 #include <xml/dom3_xpathimpl.h> 0029 #include <xml/dom_nodeimpl.h> 0030 #include <xml/dom_nodelistimpl.h> 0031 0032 #include "xpath/util.h" 0033 0034 using namespace DOM; 0035 using namespace khtml; 0036 using namespace khtml::XPath; 0037 using namespace DOM::XPath; 0038 0039 XPathResultImpl::XPathResultImpl() 0040 { 0041 } 0042 0043 XPathResultImpl::XPathResultImpl(const Value &value) 0044 : m_value(value) 0045 { 0046 switch (m_value.type()) { 0047 case Value::Boolean: 0048 m_resultType = BOOLEAN_TYPE; 0049 break; 0050 case Value::Number: 0051 m_resultType = NUMBER_TYPE; 0052 break; 0053 case Value::String: 0054 m_resultType = STRING_TYPE; 0055 break; 0056 case Value::Nodeset: 0057 m_resultType = UNORDERED_NODE_ITERATOR_TYPE; 0058 m_nodeIterator = 0; 0059 } 0060 } 0061 0062 void XPathResultImpl::convertTo(unsigned short type, int &exceptioncode) 0063 { 0064 switch (type) { 0065 case ANY_TYPE: 0066 break; 0067 case NUMBER_TYPE: 0068 m_resultType = type; 0069 m_value = Value(m_value.toNumber()); 0070 break; 0071 case STRING_TYPE: 0072 m_resultType = type; 0073 m_value = Value(m_value.toString()); 0074 break; 0075 case BOOLEAN_TYPE: 0076 m_resultType = type; 0077 m_value = Value(m_value.toBoolean()); 0078 break; 0079 case UNORDERED_NODE_ITERATOR_TYPE: 0080 case ORDERED_NODE_ITERATOR_TYPE: 0081 case UNORDERED_NODE_SNAPSHOT_TYPE: 0082 case ORDERED_NODE_SNAPSHOT_TYPE: 0083 case ANY_UNORDERED_NODE_TYPE: 0084 case FIRST_ORDERED_NODE_TYPE: 0085 if (!m_value.isNodeset()) { 0086 exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); 0087 return; 0088 } 0089 m_resultType = type; 0090 break; 0091 default: 0092 // qCDebug(KHTML_LOG) << "Cannot convert XPathResultImpl to unknown type" << type; 0093 exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); 0094 } 0095 } 0096 0097 unsigned short XPathResultImpl::resultType() const 0098 { 0099 return m_resultType; 0100 } 0101 0102 double XPathResultImpl::numberValue(int &exceptioncode) const 0103 { 0104 if (resultType() != NUMBER_TYPE) { 0105 exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); 0106 return 0.0; 0107 } 0108 return m_value.toNumber(); 0109 } 0110 0111 DOM::DOMString XPathResultImpl::stringValue(int &exceptioncode) const 0112 { 0113 if (resultType() != STRING_TYPE) { 0114 exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); 0115 return DOMString(); 0116 } 0117 return m_value.toString(); 0118 } 0119 0120 bool XPathResultImpl::booleanValue(int &exceptioncode) const 0121 { 0122 if (resultType() != BOOLEAN_TYPE) { 0123 exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); 0124 return false; 0125 } 0126 return m_value.toBoolean(); 0127 } 0128 0129 NodeImpl *XPathResultImpl::singleNodeValue(int &exceptioncode) const 0130 { 0131 if (resultType() != ANY_UNORDERED_NODE_TYPE && 0132 resultType() != FIRST_ORDERED_NODE_TYPE) { 0133 exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); 0134 return nullptr; 0135 } 0136 DomNodeList nodes = m_value.toNodeset(); 0137 0138 if (nodes && nodes->length()) { 0139 return nodes->item(0); 0140 } else { 0141 return nullptr; 0142 } 0143 } 0144 0145 bool XPathResultImpl::invalidIteratorState() const 0146 { 0147 if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && 0148 resultType() != ORDERED_NODE_ITERATOR_TYPE) { 0149 return false; 0150 } 0151 // XXX How to tell whether the document was changed since this 0152 // result was returned? 0153 return true; 0154 } 0155 0156 unsigned long XPathResultImpl::snapshotLength(int &exceptioncode) const 0157 { 0158 if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && 0159 resultType() != ORDERED_NODE_SNAPSHOT_TYPE) { 0160 exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); 0161 return 0; 0162 } 0163 0164 SharedPtr<DOM::StaticNodeListImpl> nodes = m_value.toNodeset(); 0165 return nodes ? nodes->length() : 0; 0166 } 0167 0168 NodeImpl *XPathResultImpl::iterateNext(int &exceptioncode) 0169 { 0170 if (resultType() != UNORDERED_NODE_ITERATOR_TYPE && 0171 resultType() != ORDERED_NODE_ITERATOR_TYPE) { 0172 exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); 0173 return nullptr; 0174 } 0175 // XXX How to tell whether the document was changed since this 0176 // result was returned? We need to throw an INVALID_STATE_ERR if that 0177 // is the case. 0178 SharedPtr<DOM::StaticNodeListImpl> nodes = m_value.toNodeset(); 0179 if (!nodes || m_nodeIterator >= nodes->length()) { 0180 return nullptr; 0181 } else { 0182 NodeImpl *n = nodes->item(m_nodeIterator); 0183 ++m_nodeIterator; 0184 return n; 0185 } 0186 } 0187 0188 NodeImpl *XPathResultImpl::snapshotItem(unsigned long index, int &exceptioncode) 0189 { 0190 if (resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && 0191 resultType() != ORDERED_NODE_SNAPSHOT_TYPE) { 0192 exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); 0193 return nullptr; 0194 } 0195 DomNodeList nodes = m_value.toNodeset(); 0196 if (!nodes || index >= nodes->length()) { 0197 return nullptr; 0198 } 0199 return nodes->item(index); 0200 } 0201 0202 // --------------------------------------------------------------------------- 0203 0204 DefaultXPathNSResolverImpl::DefaultXPathNSResolverImpl(NodeImpl *node) 0205 : m_node(node) 0206 { 0207 } 0208 0209 DOMString DefaultXPathNSResolverImpl::lookupNamespaceURI(const DOMString &prefix) 0210 { 0211 // Apparently Node::lookupNamespaceURI doesn't do this. 0212 // ### check 0213 if (prefix.string() == "xml") { 0214 return DOMString("http://www.w3.org/XML/1998/namespace"); 0215 } 0216 return m_node->lookupNamespaceURI(prefix); 0217 } 0218 0219 // --------------------------------------------------------------------------- 0220 XPathExpressionImpl::XPathExpressionImpl(const DOMString &expression, XPathNSResolverImpl *resolver): m_statement(expression, resolver) 0221 { 0222 } 0223 0224 XPathResultImpl *XPathExpressionImpl::evaluate(NodeImpl *contextNode, 0225 unsigned short type, 0226 XPathResultImpl * /*result_*/, 0227 int &exceptioncode) 0228 { 0229 if (!isValidContextNode(contextNode)) { 0230 exceptioncode = DOMException::NOT_SUPPORTED_ERR; 0231 return nullptr; 0232 } 0233 0234 // We are permitted, but not required, to re-use result_. We don't. 0235 Value xpathRes = m_statement.evaluate(contextNode, exceptioncode); 0236 XPathResultImpl *result = new XPathResultImpl(exceptioncode ? Value() : xpathRes); 0237 0238 if (type != ANY_TYPE) { 0239 result->convertTo(type, exceptioncode); 0240 if (exceptioncode) { 0241 // qCDebug(KHTML_LOG) << "couldn't convert XPathResult to" << type << "from" << xpathRes.type(); 0242 delete result; 0243 return nullptr; 0244 } 0245 } 0246 0247 return result; 0248 } 0249 0250 int XPathExpressionImpl::parseExceptionCode() 0251 { 0252 return m_statement.exceptionCode(); 0253 } 0254