File indexing completed on 2024-04-28 11:39:29

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