const XObjectPtr
VariablesStack::findXObject(
            const XalanQName&               name,
            StylesheetExecutionContext&     executionContext,
            bool                            fIsParam,
            bool                            fSearchGlobalSpace,
            bool&                           fNameFound)
{
    typedef VariableStackStackType::size_type   size_type;

    // findEntry() returns an index into the stack.  We should
    // _never_ take the address of anything in the stack, since
    // the address could change at unexpected times.
    const size_type     theEntryIndex =
        findEntry(name, fIsParam, fSearchGlobalSpace);

    if (theEntryIndex == m_stack.size())
    {
        fNameFound = false;

        return XObjectPtr();
    }
    else
    {
        assert(theEntryIndex < m_stack.size());

        fNameFound = true;

        assert(m_stack[theEntryIndex].getType() == StackEntry::eVariable ||
               m_stack[theEntryIndex].getType() == StackEntry::eParam ||
               m_stack[theEntryIndex].getType() == StackEntry::eActiveParam);

        const XObjectPtr&   theValue = m_stack[theEntryIndex].getValue();

        if (theValue.null() == false)
        {
            return theValue;
        }
        else
        {
            const ElemVariable* const   var = m_stack[theEntryIndex].getVariable();

            XObjectPtr                  theNewValue;

            if (var != 0)
            {
                XalanNode* const    doc = executionContext.getRootDocument();
                assert(doc != 0);

                XALAN_USING_STD(find)

                // See if the ElemVariable instance is already being evaluated...
                if (find(m_guardStack.begin(), m_guardStack.end(), var) != m_guardStack.end())
                {
                    const StylesheetExecutionContext::GetCachedString   theGuard(executionContext);

                    executionContext.error(
                        XalanMessageLoader::getMessage(
                            theGuard.get(),
                            XalanMessages::CircularVariableDefWasDetected),
                        doc,
                        var->getLocator());
                }

                m_guardStack.push_back(var);

#if !defined(XALAN_RECURSIVE_STYLESHEET_EXECUTION)
                executionContext.pushContextMarker();
#else
                // We need to set up a stack frame for the variable's execution...
                typedef StylesheetExecutionContext::PushAndPopContextMarker PushAndPopContextMarker;

                const PushAndPopContextMarker   theContextMarkerPushPop(executionContext);
#endif

                theNewValue = var->getValue(executionContext, doc);
                assert(theNewValue.null() == false);

#if !defined(XALAN_RECURSIVE_STYLESHEET_EXECUTION)
                executionContext.popContextMarker();
#endif

                assert(m_guardStack.empty() == false);

                m_guardStack.pop_back();

                m_stack[theEntryIndex].setValue(theNewValue);
                m_stack[theEntryIndex].activate();
            }

            return theNewValue;
        }
    }
Exemplo n.º 2
0
void
ElemForEach::transformSelectedChildren(
			StylesheetExecutionContext&		executionContext,
			const ElemTemplateElement*		theTemplate) const
{
	assert(m_selectPattern != 0);
	assert(m_sortElemsCount == m_sortElems.size());

	if (m_sortElemsCount == 0)
	{
		selectAndSortChildren(
					executionContext,
					theTemplate,
					0,
					executionContext.getCurrentStackFrameIndex());
	}
	else
	{
		typedef NodeSorter::NodeSortKeyVectorType					NodeSortKeyVectorType;
		typedef StylesheetExecutionContext::BorrowReturnNodeSorter	BorrowReturnNodeSorter;

		BorrowReturnNodeSorter	sorter(executionContext);

		NodeSortKeyVectorType&	keys = sorter->getSortKeys();
		assert(keys.empty() == true);

		CollectionClearGuard<NodeSortKeyVectorType>		guard(keys);

		// Reserve the space now...
		keys.reserve(m_sortElemsCount);

		// Get some temporary strings to use for evaluting the AVTs...
		XPathExecutionContext::GetAndReleaseCachedString	theTemp1(executionContext);

		XalanDOMString&		langString = theTemp1.get();

		XPathExecutionContext::GetAndReleaseCachedString	theTemp2(executionContext);

		XalanDOMString&		scratchString = theTemp2.get();

		// March backwards, performing a sort on each xsl:sort child.
		// Probably not the most efficient method.
		for(SortElemsVectorType::size_type	i = 0; i < m_sortElemsCount; i++)
		{
			const ElemSort* const	sort = m_sortElems[i];
			assert(sort != 0);

			const AVT* avt = sort->getLangAVT();

			if(0 != avt)
			{
				avt->evaluate(langString, *this, executionContext);
			}

			avt = sort->getDataTypeAVT();

			if(0 != avt)
			{
				avt->evaluate(scratchString, *this, executionContext);
			}			

			bool	treatAsNumbers = false;

			if (isEmpty(scratchString) == false)
			{
				if (equals(scratchString, Constants::ATTRVAL_DATATYPE_NUMBER) == true)
				{
					treatAsNumbers = true;
				}
				else if (equals(scratchString, Constants::ATTRVAL_DATATYPE_TEXT) == false)
				{
					const XalanQNameByValue		theQName(scratchString, this);

					if (theQName.getNamespace().length() == 0)
					{
						executionContext.error(
							XalanMessageLoader::getMessage(XalanMessages::XslSortDataTypeMustBe),
							executionContext.getCurrentNode(),
							sort->getLocator());
					}
					else
					{
						executionContext.warn(
							XalanMessageLoader::getMessage(XalanMessages::XslSortHasUnlnownDataType),
							executionContext.getCurrentNode(),
							sort->getLocator());
					}
				}
			}

			clear(scratchString);

			avt = sort->getOrderAVT();

			if(0 != avt)
			{
				avt->evaluate(scratchString, *this, executionContext);
			}			

			bool	descending = false;
			
			if (isEmpty(scratchString) == false)
			{
				if (equals(scratchString, Constants::ATTRVAL_ORDER_DESCENDING) == true)
				{
					descending = true;
				}
				else if (equals(scratchString, Constants::ATTRVAL_ORDER_ASCENDING) == false)
				{
					executionContext.error(
						XalanMessageLoader::getMessage(XalanMessages::XslSortMustBeAscendOrDescend),
						executionContext.getCurrentNode(),
						sort->getLocator());
				}
			}

			clear(scratchString);

			avt = sort->getCaseOrderAVT();

			if(0 != avt)
			{
				avt->evaluate(scratchString, *this, executionContext);
			}			

			XalanCollationServices::eCaseOrder	caseOrder = XalanCollationServices::eDefault;

			if (isEmpty(scratchString) == false)
			{
				if (equals(scratchString, Constants::ATTRVAL_CASEORDER_UPPER) == true)
				{
					caseOrder = XalanCollationServices::eUpperFirst;
				}
				else if (equals(scratchString, Constants::ATTRVAL_CASEORDER_LOWER) == true)
				{
					caseOrder = XalanCollationServices::eLowerFirst;
				}
				else
				{
					executionContext.error(
						XalanMessageLoader::getMessage(XalanMessages::XslSortCaseOrderMustBe),
						executionContext.getCurrentNode(),
						sort->getLocator());
				}
			}

			clear(scratchString);

			keys.push_back(
					NodeSortKey(
						executionContext,
						sort->getSelectPattern(),
						treatAsNumbers,
						descending,
						caseOrder,
						langString,
						*this));
		}

		selectAndSortChildren(
					executionContext,
					theTemplate,
					sorter.get(),
					executionContext.getCurrentStackFrameIndex());
	}
}