#include "../config/pathan_config.h" /* * Copyright (c) 2001, DecisionSoft Limited All rights reserved. * Please see LICENSE.TXT for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include DataItemNav::DataItemNav(XPath2MemoryManager* memMgr) : DataItemImpl(memMgr), _steps(PathanAllocator(memMgr)) { setType(DataItem::NAVIGATION); _gotoRoot = false; } DataItemNav::~DataItemNav() { //no-op } void DataItemNav::stepIteration(const DataItem *step, Sequence &candidateList, DynamicContext *context, int flags) const { context->setContextSize(candidateList.getLength()); Sequence newList(context->getMemoryManager()); Sequence::const_iterator sci; Sequence::const_iterator sciEnd = candidateList.end(); //iterate over the candidate list unsigned int index = 1; for(sci = candidateList.begin(); sci != sciEnd; ++sci, ++index) { //set up the new context context->setContextItem(*sci); context->setContextPosition(index); newList.joinSequence(step->collapseTree(context)); if(flags) { if((flags & DataItem::RETURN_ONE) && !newList.isEmpty()) break; if((flags & DataItem::RETURN_TWO) && newList.getLength()>1) break; } } // avoid doing work for simple cases if(newList.getLength() < 2) { // Check for non-nodes... for(Sequence::const_iterator i = newList.begin(); i != newList.end(); ++i) { if(!(*i)->isNode()) DSLthrow(NavigationException,X("DataItemNav::collapseTreeInternal"), X("The result of a step expression (StepExpr) is not a sequence of nodes [err:XP0019]")); } // Return right away, as there can't possibly be any duplicates candidateList = newList; } else { candidateList = removeDuplicates(newList, context); } } Sequence DataItemNav::collapseTreeInternal(DynamicContext* context, int flags) const { const Item* contextItem = context->getContextItem(); Sequence candidateList(context->getMemoryManager()); if(_gotoRoot) { // Do equivalent of root() if(contextItem != 0 && contextItem->isNode()) { const XERCES_CPP_NAMESPACE_QUALIFIER DOMNode *initialContext = FunctionRoot::root(((const Node*)contextItem)->getDOMNode()); if(initialContext->getNodeType()!=XERCES_CPP_NAMESPACE_QUALIFIER DOMNode::DOCUMENT_NODE) { DSLthrow(NavigationException,X("DataItemNav::collapseTreeInternal"), X("The root of the context node is not a document node [err:XP0050]")); } candidateList.addItem(context->getMemoryManager()->createNode(initialContext)); } else { DSLthrow(NavigationException,X("DataItemNav::collapseTreeInternal"), X("An attempt to navigate when the Context Item was not a node was made [err:XP0020]")); } } else { // Do equivalent of . candidateList.addItem(contextItem); } unsigned int oldContextSize=context->getContextSize(); unsigned int oldContextPosition=context->getContextPosition(); const Item* oldCurrentItem = contextItem; VectorOfDataItems::const_iterator end = _steps.end(); VectorOfDataItems::const_iterator lastStep = end - 1; for(VectorOfDataItems::const_iterator it = _steps.begin(); it != end; ++it) { stepIteration(*it, candidateList, context, (it == lastStep) ? flags : 0); } context->setContextSize(oldContextSize); context->setContextPosition(oldContextPosition); context->setContextItem(oldCurrentItem); if(!(flags & DataItem::UNORDERED)) { candidateList.sortIntoDocumentOrder(); } return candidateList; } void DataItemNav::addStep(NavStepImpl* step) { _steps.push_back(new (getMemoryManager()) DataItemStep(step, getMemoryManager())); } void DataItemNav::addStep(DataItem* step) { _steps.push_back(step); } void DataItemNav::addStepFront(DataItem* step) { _steps.insert(_steps.begin(), step); } void DataItemNav::setGotoRootFirst(bool gotoRoot) { _gotoRoot = gotoRoot; } struct node_compare { bool operator()(const XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* n1,const XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* n2) const { if(n1->isSameNode(n2)) return false; return n1getMemoryManager()); std::set noduplicates; Sequence::const_iterator end = nodeList.end(); for(Sequence::const_iterator firstIter= nodeList.begin(); firstIter != end; ++firstIter) { if(!(*firstIter)->isNode()) DSLthrow(NavigationException,X("DataItemNav::collapseTreeInternal"), X("The result of a step expression (StepExpr) is not a sequence of nodes [err:XP0019]")); const XERCES_CPP_NAMESPACE_QUALIFIER DOMNode* node = ((const Node*)*firstIter)->getDOMNode(); std::pair::iterator,bool> inserted=noduplicates.insert(node); if(inserted.second) result.addItem(*firstIter); } return result; } DataItem* DataItemNav::staticResolution(StaticContext *context, StaticResolutionContext *src) { StaticResolutionContext newSrc(context->getMemoryManager()); VectorOfDataItems newSteps(PathanAllocator(context->getMemoryManager())); if(_gotoRoot) { newSrc.contextItemUsed(true); } VectorOfDataItems::iterator begin = _steps.begin(); VectorOfDataItems::iterator end = _steps.end(); for(VectorOfDataItems::iterator it = begin; it != end; ++it) { // Statically resolve our step StaticResolutionContext stepSrc(context->getMemoryManager()); DataItem *step = (*it)->staticResolution(context, &stepSrc); if(stepSrc.areContextFlagsUsed() || newSrc.isNoFoldingForced()) { newSteps.push_back(step); if(it != begin || _gotoRoot) { // Remove context item usage stepSrc.contextItemUsed(false); stepSrc.contextPositionUsed(false); stepSrc.contextSizeUsed(false); } newSrc.add(&stepSrc); } else { // Constant fold, by clearing all our previous steps (and the root pseudo-step) // and just having our most recent step. // This is only possible because the result of steps has to be nodes, and // duplicates are removed, which means we aren't forced to execute a constant // step a set number of times. _gotoRoot = false; newSteps.clear(); newSteps.push_back(step); newSrc.add(&stepSrc); } } _steps = newSteps; if(newSrc.isUsed()) { src->add(&newSrc); return resolvePredicates(context, src); } else { return constantFold(context, src); } } bool DataItemNav::getGotoRootFirst() const { return _gotoRoot; } const VectorOfDataItems &DataItemNav::getSteps() const { return _steps; }