#include "../config/pathan_config.h" /* * Copyright (c) 2003, DecisionSoft Limited All rights reserved. * Please see LICENSE.TXT for more information. */ #include #include #include #include #include #include #include #include #include #include "../exceptions/XPath2TypeCastException.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include XPath2Result::XPath2Result(const ResultType resultType, const DataItem *expression, DynamicContext *dynamicContext, XERCES_CPP_NAMESPACE_QUALIFIER MemoryManager* memMgr) : _createdWith(memMgr), _memMgr(memMgr), _resultSequence(&_memMgr), _resultType(resultType), _context(dynamicContext), _curIndex(0), _changes(-1), _documentRoot(0) { if(_resultType == XPath2Result::ITERATOR_RESULT) { beforeStart = true; } evaluate(expression); } XPath2Result::XPath2Result(const ResultType resultType, const DataItem *expression, XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* contextNode, DynamicContext *staticContext, XERCES_CPP_NAMESPACE_QUALIFIER MemoryManager* memMgr) : _createdWith(memMgr), _memMgr(memMgr), _resultSequence(&_memMgr), _resultType(resultType), _curIndex(0), _changes(-1), _documentRoot(contextNode->getOwnerDocument()) { if(_documentRoot != 0) { _changes = ((XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl*)_documentRoot)->changes(); } if(_resultType == XPath2Result::ITERATOR_RESULT) { beforeStart = true; } _context = staticContext->createDynamicContext(&_memMgr); //Check for illegal contextNode types if(contextNode != 0) { //More illegal types here? switch (contextNode->getNodeType()) { case XERCES_CPP_NAMESPACE_QUALIFIER DOMNode::ENTITY_REFERENCE_NODE: throw XERCES_CPP_NAMESPACE_QUALIFIER DOMException(XERCES_CPP_NAMESPACE_QUALIFIER DOMException::NOT_SUPPORTED_ERR, X("Context node of illegal type.")); break; } _context->setContextItem(_memMgr.createNode(contextNode)); } evaluate(expression); } XPath2Result::~XPath2Result() { // no-op } void XPath2Result::release() { _memMgr.reset(); _createdWith->deallocate(this); } void XPath2Result::evaluate(const DataItem *expression) { int flags = 0; if(_resultType == FIRST_RESULT) { flags |= DataItem::UNORDERED | DataItem::RETURN_ONE; } try { _resultSequence = expression->collapseTree(_context, flags); } catch(const DataItemException &e) { if(PathanException::getDebug()) { e.printDebug( X("Caught exception in Interface") ); } throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("PathanExpressionImpl::evaluateToSequence(): request and result types different")); } catch(const DSLException &e) { if(PathanException::getDebug()) { e.printDebug( X("Caught exception at Interface") ); } throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, e.getError()); } catch(const PathanException &e) { //rethrow it throw PathanException(e.getCode(), e.getString()); } catch(XERCES_CPP_NAMESPACE_QUALIFIER DOMException &e) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("PathanExpressionImpl::evaluateToSequence(): DOMException!")); } catch(XERCES_CPP_NAMESPACE_QUALIFIER XMLException &e) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, e.getMessage()); } catch (...) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("PathanExpressionImpl::evaluateToSequence(): Unknown exception caught.")); } } const XPath2Result::ResultType XPath2Result::getResultType() const { return _resultType; } bool XPath2Result::isNode() const { if(_resultSequence.isEmpty() || (_curIndex >=_resultSequence.getLength()) ) { return false; } return _resultSequence.item(_curIndex)->isNode(); } const XERCES_CPP_NAMESPACE_QUALIFIER DOMTypeInfo* XPath2Result::getTypeInfo() const { if(_resultSequence.isEmpty() || (_curIndex >=_resultSequence.getLength()) ) { return 0; } const Item* item = _resultSequence.item(_curIndex); if(item->isNode()) { const Node* node = (const Node*)item; const XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* domnode = node->getDOMNode(); switch(domnode->getNodeType()) { case XERCES_CPP_NAMESPACE_QUALIFIER DOMNode::ATTRIBUTE_NODE: case XERCES_CPP_NAMESPACE_QUALIFIER DOMNode::ELEMENT_NODE: return new (const_cast(&_memMgr)) PathanTypeInfo(node->getTypeURI(), node->getTypeName(), const_cast(&_memMgr)); break; default: return 0; break; } } else { const AnyAtomicType* atom = (const AnyAtomicType*)item; return new (const_cast(&_memMgr)) PathanTypeInfo(atom->getTypeURI(), atom->getTypeName(), const_cast(&_memMgr)); } } int XPath2Result::asInt() const throw (XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException, XERCES_CPP_NAMESPACE_QUALIFIER DOMException) { if(_resultSequence.isEmpty() || (_curIndex >=_resultSequence.getLength()) ) { throw XERCES_CPP_NAMESPACE_QUALIFIER DOMException(XERCES_CPP_NAMESPACE_QUALIFIER DOMException::INVALID_STATE_ERR, XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode("There is no current result in the result")); } const Item* item = _resultSequence.item(_curIndex); if(item->isNode()) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("Cannot convert result to int")); } const AnyAtomicType* atom = (const AnyAtomicType*)item; const ATDecimalOrDerived* integer; try { integer = (const ATDecimalOrDerived*)atom->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_INTEGER, _context); } catch (XPath2TypeCastException &e) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("Cannot convert result to int")); } return atoi(XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode(integer->asString(_context))); } double XPath2Result::asDouble() const throw (XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException, XERCES_CPP_NAMESPACE_QUALIFIER DOMException) { if(_resultSequence.isEmpty() || (_curIndex >=_resultSequence.getLength()) ) { throw XERCES_CPP_NAMESPACE_QUALIFIER DOMException(XERCES_CPP_NAMESPACE_QUALIFIER DOMException::INVALID_STATE_ERR, XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode("There is no current result in the result")); } const Item* item = _resultSequence.item(_curIndex); if(item->isNode()) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("Cannot convert result to double")); } const AnyAtomicType* atom = (const AnyAtomicType*)item; const ATDoubleOrDerived* doubleValue; try { doubleValue = (const ATDoubleOrDerived*)atom->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DOUBLE, _context); } catch (XPath2TypeCastException &e) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("Cannot convert result to double")); } return atof(XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode(doubleValue->asString(_context))); } const XMLCh* XPath2Result::asString() const throw (XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException, XERCES_CPP_NAMESPACE_QUALIFIER DOMException) { if(_resultSequence.isEmpty() || (_curIndex >=_resultSequence.getLength()) ) { throw XERCES_CPP_NAMESPACE_QUALIFIER DOMException(XERCES_CPP_NAMESPACE_QUALIFIER DOMException::INVALID_STATE_ERR, XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode("There is no current result in the result")); } const Item* item = _resultSequence.item(_curIndex); if(item->isNode()) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("Cannot convert result to a string")); } return item->asString(_context); } bool XPath2Result::asBoolean() const throw (XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException, XERCES_CPP_NAMESPACE_QUALIFIER DOMException) { if(_resultSequence.isEmpty() || (_curIndex >=_resultSequence.getLength()) ) { throw XERCES_CPP_NAMESPACE_QUALIFIER DOMException(XERCES_CPP_NAMESPACE_QUALIFIER DOMException::INVALID_STATE_ERR, XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode("There is no current result in the result")); } const Item* item = _resultSequence.item(_curIndex); if(item->isNode()) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("Cannot convert result to a boolean")); } const AnyAtomicType* atom = (const AnyAtomicType*)item; const ATBooleanOrDerived* boolean; try { boolean = (const ATBooleanOrDerived*)atom->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_BOOLEAN, _context); } catch (XPath2TypeCastException &e) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("Cannot convert result to a boolean")); } return boolean->isTrue(); } const XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* XPath2Result::asNode() const throw (XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException, XERCES_CPP_NAMESPACE_QUALIFIER DOMException) { if(_resultSequence.isEmpty() || (_curIndex >=_resultSequence.getLength()) ) { throw XERCES_CPP_NAMESPACE_QUALIFIER DOMException(XERCES_CPP_NAMESPACE_QUALIFIER DOMException::INVALID_STATE_ERR, XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode("There is no current result in the result")); } const Item* item = _resultSequence.item(_curIndex); if(!item->isNode()) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, X("The requested result is not a node")); } return ((const Node*)item)->getDOMNode(); } bool XPath2Result::getInvalidIteratorState() const { if(_resultType != XPath2Result::ITERATOR_RESULT) { return false; } if(_resultSequence.isEmpty() || (_curIndex >=_resultSequence.getLength()) ) { return false; } return this->hasDocumentChanged(_resultSequence.item(_curIndex)); } unsigned long XPath2Result::getSnapshotLength() const throw(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException) { if(_resultType != XPath2Result::SNAPSHOT_RESULT) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, errorMessage(XPath2Result::SNAPSHOT_RESULT, _resultType)); } return _resultSequence.getLength(); } bool XPath2Result::iterateNext() const throw (XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException, XERCES_CPP_NAMESPACE_QUALIFIER DOMException) { if(_resultType != XPath2Result::ITERATOR_RESULT) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, errorMessage(XPath2Result::ITERATOR_RESULT, _resultType)); } // this method is const, need to cast that away if(beforeStart) { ((XPath2Result*)this)->_curIndex = 0; ((XPath2Result*)this)->beforeStart = false; } else { ((XPath2Result*)this)->_curIndex++; } //Reached end of set, return false if(_curIndex >= _resultSequence.getLength()) { return false; } // check for document changes if(this->hasDocumentChanged(_resultSequence.item(_curIndex))) { throw XERCES_CPP_NAMESPACE_QUALIFIER DOMException(XERCES_CPP_NAMESPACE_QUALIFIER DOMException::INVALID_STATE_ERR, XERCES_CPP_NAMESPACE_QUALIFIER XMLString::transcode("Document has changed")); }//if return true; } bool XPath2Result::snapshotItem(unsigned long index) const throw(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException) { if(_resultType != XPath2Result::SNAPSHOT_RESULT) { throw PathanException(XERCES_CPP_NAMESPACE_QUALIFIER DOMXPathException::TYPE_ERR, errorMessage(XPath2Result::SNAPSHOT_RESULT, _resultType)); } //Reached end of set, return false if(_curIndex >= _resultSequence.getLength()) { return false; } // this method is const, need to cast that away ((XPath2Result*)this)->_curIndex = index; return true; } bool XPath2Result::hasDocumentChanged(const Item* item) const { if(item->isNode()) { if(_documentRoot != 0 && ((XERCES_CPP_NAMESPACE_QUALIFIER DOMDocumentImpl*)_documentRoot)->changes() != _changes) { return true; } else { return false; }//if } else { return false; } } const XMLCh* XPath2Result::errorMessage(XPath2Result::ResultType requestedType, XPath2Result::ResultType resultType) const { std::string message = typeName(requestedType) + " was requested from a XPath2Result of type " + typeName(resultType); return X(message.c_str()); } const std::string XPath2Result::typeName(XPath2Result::ResultType type) const { switch(type) { case XPath2Result::FIRST_RESULT: return "FIRST_RESULT"; case XPath2Result::ITERATOR_RESULT: return "ITERATOR_RESULT"; case XPath2Result::SNAPSHOT_RESULT: return "SNAPSHOT_RESULT"; } return ""; }