/* * dom3_xpathimpl.cpp - Copyright 2005 Frerich Raabe * Copyright 2010 Maksim Orlovich * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #include #include #include "xpath/expression.h" #include "xpath/util.h" using namespace DOM; using namespace khtml; using namespace khtml::XPath; using namespace DOM::XPath; XPathResultImpl::XPathResultImpl() { } XPathResultImpl::XPathResultImpl( const Value &value ) : m_value( value ) { switch ( m_value.type() ) { case Value::Boolean: m_resultType = BOOLEAN_TYPE; break; case Value::Number: m_resultType = NUMBER_TYPE; break; case Value::String: m_resultType = STRING_TYPE; break; case Value::Nodeset: m_resultType = UNORDERED_NODE_ITERATOR_TYPE; m_nodeIterator = 0; } } void XPathResultImpl::convertTo( unsigned short type, int &exceptioncode ) { switch ( type ) { case ANY_TYPE: break; case NUMBER_TYPE: m_resultType = type; m_value = Value( m_value.toNumber() ); break; case STRING_TYPE: m_resultType = type; m_value = Value( m_value.toString() ); break; case BOOLEAN_TYPE: m_resultType = type; m_value = Value( m_value.toBoolean() ); break; case UNORDERED_NODE_ITERATOR_TYPE: case ORDERED_NODE_ITERATOR_TYPE: case UNORDERED_NODE_SNAPSHOT_TYPE: case ORDERED_NODE_SNAPSHOT_TYPE: case ANY_UNORDERED_NODE_TYPE: case FIRST_ORDERED_NODE_TYPE: if ( !m_value.isNodeset() ) { exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); return; } m_resultType = type; break; default: kDebug(6011) << "Cannot convert XPathResultImpl to unknown type" << type; exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); } } unsigned short XPathResultImpl::resultType() const { return m_resultType; } double XPathResultImpl::numberValue(int &exceptioncode) const { if ( resultType() != NUMBER_TYPE ) { exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); return 0.0; } return m_value.toNumber(); } DOM::DOMString XPathResultImpl::stringValue(int &exceptioncode) const { if ( resultType() != STRING_TYPE ) { exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); return DOMString(); } return m_value.toString(); } bool XPathResultImpl::booleanValue(int &exceptioncode) const { if ( resultType() != BOOLEAN_TYPE ) { exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); return false; } return m_value.toBoolean(); } NodeImpl *XPathResultImpl::singleNodeValue(int &exceptioncode) const { if ( resultType() != ANY_UNORDERED_NODE_TYPE && resultType() != FIRST_ORDERED_NODE_TYPE ) { exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); return 0; } DomNodeList nodes = m_value.toNodeset(); if (nodes && nodes->length()) return nodes->item(0); else return 0; } bool XPathResultImpl::invalidIteratorState() const { if ( resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE ) { return false; } // XXX How to tell whether the document was changed since this // result was returned? return true; } unsigned long XPathResultImpl::snapshotLength(int &exceptioncode) const { if ( resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE ) { exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); return 0; } SharedPtr nodes = m_value.toNodeset(); return nodes ? nodes->length() : 0; } NodeImpl *XPathResultImpl::iterateNext(int &exceptioncode) { if ( resultType() != UNORDERED_NODE_ITERATOR_TYPE && resultType() != ORDERED_NODE_ITERATOR_TYPE ) { exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); return 0; } // XXX How to tell whether the document was changed since this // result was returned? We need to throw an INVALID_STATE_ERR if that // is the case. SharedPtr nodes = m_value.toNodeset(); if ( !nodes || m_nodeIterator >= nodes->length() ) { return 0; } else { NodeImpl* n = nodes->item(m_nodeIterator); ++m_nodeIterator; return n; } } NodeImpl *XPathResultImpl::snapshotItem( unsigned long index, int &exceptioncode ) { if ( resultType() != UNORDERED_NODE_SNAPSHOT_TYPE && resultType() != ORDERED_NODE_SNAPSHOT_TYPE ) { exceptioncode = XPathException::toCode(XPathException::TYPE_ERR); return 0; } DomNodeList nodes = m_value.toNodeset(); if ( !nodes || index >= nodes->length() ) { return 0; } return nodes->item( index ); } // --------------------------------------------------------------------------- DefaultXPathNSResolverImpl::DefaultXPathNSResolverImpl( NodeImpl *node ) : m_node( node ) { } DOMString DefaultXPathNSResolverImpl::lookupNamespaceURI( const DOMString& prefix ) { // Apparently Node::lookupNamespaceURI doesn't do this. // ### check if ( prefix.string() == "xml" ) { return DOMString( "http://www.w3.org/XML/1998/namespace" ); } return m_node->lookupNamespaceURI( prefix ); } // --------------------------------------------------------------------------- XPathExpressionImpl::XPathExpressionImpl( const DOMString& expression, XPathNSResolverImpl *resolver ): m_statement(expression, resolver) { } XPathResultImpl *XPathExpressionImpl::evaluate( NodeImpl *contextNode, unsigned short type, XPathResultImpl* /*result_*/, int &exceptioncode ) { if ( !isValidContextNode( contextNode ) ) { exceptioncode = DOMException::NOT_SUPPORTED_ERR; return 0; } // We are permitted, but not required, to re-use result_. We don't. Value xpathRes = m_statement.evaluate( contextNode, exceptioncode ); XPathResultImpl* result = new XPathResultImpl( exceptioncode ? Value() : xpathRes ); if ( type != ANY_TYPE ) { result->convertTo( type, exceptioncode ); if( exceptioncode ) { kDebug(6011) << "couldn't convert XPathResult to" << type << "from" << xpathRes.type(); delete result; return 0; } } return result; } int XPathExpressionImpl::parseExceptionCode() { return m_statement.exceptionCode(); } // kate: indent-width 4; replace-tabs off; tab-width 4; space-indent off;