#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 "../exceptions/XPath2TypeCastException.hpp" #include #include #include #include #include #include #include DataItemOperator::DataItemOperator(const XMLCh* opName, const VectorOfDataItems &args, XPath2MemoryManager* memMgr) : DataItemImpl(memMgr), _args(args) { _opName=opName; setType(DataItem::OPERATOR); } void DataItemOperator::addArgument(DataItem* arg) { _args.push_back(arg); } DataItem* DataItemOperator::getArgument(unsigned int index) { assert(index<_args.size()); return _args[index]; } void DataItemOperator::setArgument(unsigned int index, DataItem *arg) { assert(index<_args.size()); _args[index] = arg; } void DataItemOperator::removeArgument(unsigned int index) { assert(index<_args.size()); _args.erase(_args.begin() + index); } unsigned int DataItemOperator::getNumArgs() const { return _args.size(); } const XMLCh* DataItemOperator::getOperatorName() const { return _opName; } Sequence DataItemOperator::getArithmeticOperatorArguments(DynamicContext* context) const { assert(getNumArgs() > 0); const Item* arg1 = 0; const Item* arg2 = 0; // An arithmetic expression is evaluated by applying the following rules, in order, // until an error is raised or a value is computed: // 1. Atomization is applied to each operand. // 2. If either operand is an empty sequence, the result of the operation is an empty sequence. // (to be enforced by the caller) // 3. If either operand is now a sequence of length greater than one, then: // * If XPath 1.0 compatibility mode is true, any items after the first item in the sequence are discarded. // Otherwise, a type error is raised. Sequence sequence(_args[0]->collapseTree(context).atomize(context)); if(sequence.isEmpty()) arg1=0; else if(sequence.getLength()>1 && !context->getXPath1CompatibilityMode()) DSLthrow(XPath2TypeCastException,X("DataItemOperator::getArithmeticOperatorArguments"), X("The first parameter of the operator is not an empty sequence or a single atomic value")); else arg1=sequence.first(); if(getNumArgs()>1) { Sequence sequence(_args[1]->collapseTree(context).atomize(context)); if(sequence.isEmpty()) arg2=0; else if(sequence.getLength()>1 && !context->getXPath1CompatibilityMode()) DSLthrow(XPath2TypeCastException,X("DataItemOperator::getArithmeticOperatorArguments"), X("The second parameter of the operator is not an empty sequence or a single atomic value")); else arg2=sequence.first(); } // 4. If either operand is now of type xdt:untypedAtomic, it is cast to the default type for the given operator. // The default type for the idiv operator is xs:integer; the default type for all other arithmetic operators // is xs:double. If the cast fails, a type error is raised. // if(arg1 != 0 && arg1->isAtomicValue() && ((const AnyAtomicType*)arg1)->getPrimitiveTypeIndex() == AnyAtomicType::UNTYPED_ATOMIC) { // let the caller deal with idiv? revisit -- crioux arg1 = ((const AnyAtomicType*)arg1)->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DOUBLE, context); } if(getNumArgs()>1 && arg2 != 0 && arg2->isAtomicValue() && ((const AnyAtomicType*)arg2)->getPrimitiveTypeIndex() == AnyAtomicType::UNTYPED_ATOMIC) { arg2 = ((const AnyAtomicType*)arg2)->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_DOUBLE, context); } Sequence result(context->getMemoryManager()); if(arg1 != 0) { result.addItem(arg1); } if(getNumArgs()>1 && arg2!=0) { result.addItem(arg2); } return result; } Sequence DataItemOperator::getComparisonOperatorArguments(DynamicContext* context) const { const Item* arg1 = 0; const Item* arg2 = 0; // Value comparisons are intended for comparing single values. The result of a value comparison is // defined by applying the following rules, in order: // 1. Atomization is applied to each operand. If the result, called an atomized operand, does not contain // exactly one atomic value, a type error is raised. Sequence sequence1(_args[0]->collapseTree(context).atomize(context)); if(sequence1.isEmpty()) arg1=0; else if(sequence1.getLength()>1) DSLthrow(XPath2TypeCastException,X("DataItemOperator::getComparisonOperatorArguments"), X("The first parameter of the operator is not an empty sequence or a single atomic value")); else arg1=sequence1.first(); Sequence sequence2=_args[1]->collapseTree(context).atomize(context); if(sequence2.isEmpty()) arg2=0; else if(sequence2.getLength()>1) DSLthrow(XPath2TypeCastException,X("DataItemOperator::getComparisonOperatorArguments"), X("The second parameter of the operator is not an empty sequence or a single atomic value")); else arg2=sequence2.first(); // 2. Any atomized operand that has the dynamic type xdt:untypedAtomic is cast to the type xs:string. if(arg1 != 0 && arg1->isAtomicValue() && ((const AnyAtomicType*)arg1)->getPrimitiveTypeIndex() == AnyAtomicType::UNTYPED_ATOMIC) { arg1=((const AnyAtomicType*)arg1)->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_STRING, context); } if(arg2 != 0 && arg2->isAtomicValue() && ((const AnyAtomicType*)arg2)->getPrimitiveTypeIndex() == AnyAtomicType::UNTYPED_ATOMIC) { arg2=((const AnyAtomicType*)arg2)->castAs(XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgURI_SCHEMAFORSCHEMA, XERCES_CPP_NAMESPACE_QUALIFIER SchemaSymbols::fgDT_STRING, context); } Sequence result(context->getMemoryManager()); if(arg1 != 0) { result.addItem(arg1); } if(getNumArgs()>1 && arg2!=0) { result.addItem(arg2); } return result; } bool DataItemOperator::getBooleanParam(unsigned int index,DynamicContext* context) const { assert(_args.size() > index); return _args[index]->collapseTree(context,DataItem::UNORDERED | DataItem::RETURN_TWO).getEffectiveBooleanValue(context); } const Node* DataItemOperator::getNodeParam(unsigned int index,DynamicContext* context) const { assert(_args.size() > index); // The result of a node comparison is defined by applying the following rules, in order: /* node()? */ static SequenceType gNode(new SequenceType::ItemType(SequenceType::ItemType::TEST_NODE), SequenceType::QUESTION_MARK); // 1. Each operand must be either a single node or an empty sequence; otherwise a type error is raised. Sequence sequence(_args[index]->collapseTree(context).castAs(&gNode, context)); if(sequence.isEmpty()) return NULL; if(sequence.getLength()>1 || !sequence.first()->isNode()) DSLthrow(XPath2TypeCastException,X("DataItemOperator::getNodeParam"), X("The parameter of the operator is not a single node or an empty sequence")); return (const Node*)sequence.first(); } bool DataItemOperator::checkSequenceIsNodes(const Sequence &s) const { for(Sequence::const_iterator cur = s.begin(); cur != s.end(); ++cur) { if(!(*cur)->isNode()) { return false; } } return true; } DataItem* DataItemOperator::staticResolution(StaticContext *context, StaticResolutionContext *src) { return resolveDataItemsForDateOrTime(_args, context, src, true); } const VectorOfDataItems &DataItemOperator::getArguments() const { return _args; }