You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xalan.apache.org by jd...@locus.apache.org on 2000/04/19 17:59:28 UTC

cvs commit: xml-xalan/c/src/XSLT ElemNumber.cpp ElemNumber.hpp

jdonohue    00/04/19 08:59:27

  Modified:    c/src/XSLT ElemNumber.cpp ElemNumber.hpp
  Log:
  Replaced with version derived from newer java source
  
  Revision  Changes    Path
  1.10      +485 -333  xml-xalan/c/src/XSLT/ElemNumber.cpp
  
  Index: ElemNumber.cpp
  ===================================================================
  RCS file: /home/cvs/xml-xalan/c/src/XSLT/ElemNumber.cpp,v
  retrieving revision 1.9
  retrieving revision 1.10
  diff -u -r1.9 -r1.10
  --- ElemNumber.cpp	2000/04/12 19:40:59	1.9
  +++ ElemNumber.cpp	2000/04/19 15:59:25	1.10
  @@ -69,6 +69,7 @@
   #include <PlatformSupport/DOMStringHelper.hpp>
   #include <PlatformSupport/NumberFormat.hpp>
   
  +#include <DOMSupport/DOMServices.hpp>
   
   
   #include <XPath/XPath.hpp>
  @@ -85,6 +86,7 @@
   #endif
   
   
  +
   const XalanDOMString	ElemNumber::s_alphaCountTable(XALAN_STATIC_UCODE_STRING("ZABCDEFGHIJKLMNOPQRSTUVWXY"));
   
   
  @@ -119,11 +121,11 @@
   	m_fromMatchPattern(0),
   	m_valueExpr(0),
   	m_level(Constants::NUMBERLEVEL_SINGLE),
  -	m_format_avt(),
  -	m_lang_avt(),  
  -	m_lettervalue_avt(),
  -	m_groupingSeparator_avt(),
  -	m_groupingSize_avt()
  +	m_format_avt(0),
  +	m_lang_avt(0),
  +	m_lettervalue_avt(0),
  +	m_groupingSeparator_avt(0),
  +	m_groupingSize_avt(0)
   	
   {
   	const unsigned int	nAttrs = atts.getLength();
  @@ -159,25 +161,31 @@
   		}
   		else if(equals(aname, Constants::ATTRNAME_FORMAT))
   		{
  -			m_format_avt = atts.getValue(i);
  +			m_format_avt = new AVT(aname, atts.getType(i),
  +						atts.getValue(i), *this, constructionContext);
  +
   		}
   		else if(equals(aname, Constants::ATTRNAME_LANG))
   		{
  -			m_lang_avt = atts.getValue(i);
  +			m_lang_avt = new AVT(aname, atts.getType(i),
  +						atts.getValue(i), *this, constructionContext);
   		}
   		else if(equals(aname, Constants::ATTRNAME_LETTERVALUE))
   		{
   			constructionContext.warn(Constants::ATTRNAME_LETTERVALUE + " not supported yet!");
   
  -			m_lettervalue_avt = atts.getValue(i);
  +			m_lettervalue_avt = new AVT(aname, atts.getType(i),
  +						atts.getValue(i), *this, constructionContext);
   		} 
   		else if(equals(aname,Constants::ATTRNAME_GROUPINGSEPARATOR))
   		{
  -			m_groupingSeparator_avt = atts.getValue(i);
  +			m_groupingSeparator_avt = new AVT(aname, atts.getType(i),
  +						atts.getValue(i), *this, constructionContext);
   		}
   		else if(equals(aname,Constants::ATTRNAME_GROUPINGSIZE))
   		{
  -			m_groupingSize_avt = atts.getValue(i);
  +			m_groupingSize_avt = new AVT(aname, atts.getType(i),
  +						atts.getValue(i), *this, constructionContext);
   		}
   		else if(!isAttrOK(aname, atts, i, constructionContext))
   		{
  @@ -186,6 +194,15 @@
   	}
   }
   
  +	
  +ElemNumber::~ElemNumber()
  +{
  +	delete	m_format_avt;
  +	delete	m_lang_avt;
  +	delete	m_lettervalue_avt;
  +	delete	m_groupingSeparator_avt;
  +	delete	m_groupingSize_avt;
  +}
   
   
   void
  @@ -207,25 +224,21 @@
   }
   
   
  -
  -
   XalanNode*
   ElemNumber::findAncestor(
   			StylesheetExecutionContext&		executionContext,
   			const XPath*					fromMatchPattern,
   			const XPath*					countMatchPattern,
  -			XalanNode*						context,
  +			const XalanNode* const			context,
   			const XalanElement*				/* namespaceContext */) const
   {
  -	XalanNode*	contextCopy = context;
  -
  +	XalanNode*	contextCopy = const_cast<XalanNode*>(context);
   	while(contextCopy != 0)
   	{
   		if(0 != fromMatchPattern)
   		{
  -			if(fromMatchPattern->getMatchScore(contextCopy,
  -											   *this,
  -											   executionContext.getXPathExecutionContext()) !=
  +			if(fromMatchPattern->getMatchScore(contextCopy, *this,
  +						executionContext.getXPathExecutionContext()) !=
   							XPath::s_MatchScoreNone)
   			{
   				break;
  @@ -234,9 +247,8 @@
   		
   		if(0 != countMatchPattern)
   		{
  -			if(countMatchPattern->getMatchScore(context,
  -											    *this,
  -												executionContext.getXPathExecutionContext()) !=
  +			if(countMatchPattern->getMatchScore(contextCopy, *this,
  +						executionContext.getXPathExecutionContext()) !=
   							XPath::s_MatchScoreNone)
   			{
   				break;
  @@ -245,7 +257,6 @@
   		
   		contextCopy = executionContext.getParentOfNode(*contextCopy);
   	}
  -
   	return contextCopy;
   }					
   
  @@ -253,21 +264,20 @@
   
   XalanNode*
   ElemNumber::findPrecedingOrAncestorOrSelf(
  -			StylesheetExecutionContext&		executionContext,
  -			const XPath*					fromMatchPattern,
  -			const XPath*					countMatchPattern,
  -			XalanNode*						context,
  +			StylesheetExecutionContext&	executionContext,
  +			const XPath*						fromMatchPattern,
  +			const XPath*						countMatchPattern,
  +			const XalanNode* const 			context,
   			const XalanElement*				/* namespaceContext */) const
   {  
  -	XalanNode*	contextCopy = context;
  -
  +	XalanNode*	contextCopy = const_cast<XalanNode*>(context);
   	while(contextCopy != 0)
   	{
   		if(0 != fromMatchPattern)
   		{
  -			if(fromMatchPattern->getMatchScore(contextCopy,
  -						*this,
  -						executionContext.getXPathExecutionContext()) != XPath::s_MatchScoreNone)
  +			if(fromMatchPattern->getMatchScore(contextCopy, *this,
  +						executionContext.getXPathExecutionContext()) !=
  +							XPath::s_MatchScoreNone)
   			{
   				contextCopy = 0;
   				break;
  @@ -276,26 +286,26 @@
   		
   		if(0 != countMatchPattern)
   		{
  -			if(countMatchPattern->getMatchScore(contextCopy,
  -											    *this,
  -											    executionContext.getXPathExecutionContext()) != XPath::s_MatchScoreNone)
  +			if(countMatchPattern->getMatchScore(contextCopy, *this,
  +						executionContext.getXPathExecutionContext()) !=
  +							XPath::s_MatchScoreNone)
   			{
   				break;
   			}
   		}
  -
   		XalanNode* const	prevSibling = contextCopy->getPreviousSibling();
  -
   		if(prevSibling == 0)
   		{
   			contextCopy = executionContext.getParentOfNode(*contextCopy);
   		}
   		else
   		{
  -			contextCopy = prevSibling;
  +			// Now go down the chain of children of this sibling 
  +			contextCopy = prevSibling->getLastChild();
  +			if (contextCopy == 0)
  +				contextCopy = prevSibling;
   		}
   	}
  -
   	return contextCopy;
   }
   
  @@ -304,53 +314,51 @@
   const XPath*
   ElemNumber::getCountMatchPattern(
   			StylesheetExecutionContext&		executionContext,
  -			XalanNode*						contextNode) const
  +			const XalanNode* const				contextNode) const
   {
   	const XPath*	countMatchPattern = m_countMatchPattern;
  -
   	if(0 == countMatchPattern)
   	{
   		switch(contextNode->getNodeType())
   		{
   		case XalanNode::ELEMENT_NODE:
  -			countMatchPattern = executionContext.createMatchPattern(contextNode->getNodeName(),
  -				*this);
  +			countMatchPattern =
  +				executionContext.createMatchPattern(contextNode->getNodeName(), *this);
   			break;
   
   		case XalanNode::ATTRIBUTE_NODE:
  -			countMatchPattern = executionContext.createMatchPattern(XalanDOMString(XALAN_STATIC_UCODE_STRING("@")) +
  -																	contextNode->getNodeName(),
  -				*this);
  +			countMatchPattern = executionContext.createMatchPattern(
  +						XalanDOMString(XALAN_STATIC_UCODE_STRING("@")) + contextNode->getNodeName(),
  +						*this);
   			break;
   
   		case XalanNode::CDATA_SECTION_NODE:
   		case XalanNode::TEXT_NODE:
  -			countMatchPattern = executionContext.createMatchPattern(XalanDOMString(XALAN_STATIC_UCODE_STRING("text()")),
  -				*this);
  +			countMatchPattern = executionContext.createMatchPattern(
  +					XalanDOMString(XALAN_STATIC_UCODE_STRING("text()")), *this);
   			break;
   
   		case XalanNode::COMMENT_NODE:
  -			countMatchPattern = executionContext.createMatchPattern(XalanDOMString(XALAN_STATIC_UCODE_STRING("comment()")),
  -				*this);
  +			countMatchPattern = executionContext.createMatchPattern(
  +					XalanDOMString(XALAN_STATIC_UCODE_STRING("comment()")), *this);
   			break;
   
   		case XalanNode::DOCUMENT_NODE:
  -			countMatchPattern = executionContext.createMatchPattern(XalanDOMString(XALAN_STATIC_UCODE_STRING("/")),
  -				*this);
  +			countMatchPattern = executionContext.createMatchPattern(
  +					XalanDOMString(XALAN_STATIC_UCODE_STRING("/")), *this);
   			break;
   
   		case XalanNode::PROCESSING_INSTRUCTION_NODE:
  -			countMatchPattern = executionContext.createMatchPattern(XalanDOMString(XALAN_STATIC_UCODE_STRING("pi(")) + 
  -				contextNode->getNodeName() + XalanDOMString(XALAN_STATIC_UCODE_STRING(")")),
  -				*this);
  +			countMatchPattern = executionContext.createMatchPattern(
  +				XalanDOMString(XALAN_STATIC_UCODE_STRING("pi(")) + 
  +				contextNode->getNodeName() +
  +				XalanDOMString(XALAN_STATIC_UCODE_STRING(")")), *this);
   			break;
   
   		default:
  -			assert(false);
   			break;
   		}
   	}
  -
   	return countMatchPattern;
   }
   
  @@ -359,14 +367,13 @@
   XalanDOMString
   ElemNumber::getCountString(
   			StylesheetExecutionContext&		executionContext,
  -			XalanNode*						/* sourceTree */, 
  -			XalanNode*						sourceNode) const
  +			XalanNode* const					/* sourceTree */, 
  +			XalanNode* const					sourceNode) const
   {
   	assert(sourceNode != 0);
   	IntArrayType	numberList;
  +	CountersTable ctable;
   
  -	IntArrayType	list;
  -
   	if(0 != m_valueExpr)
   	{
   		const XObject* const	countObj =
  @@ -378,279 +385,179 @@
   	}
   	else
   	{
  -		const XPath* const	countMatchPattern =
  -			getCountMatchPattern(executionContext, sourceNode);
  -
  -		if((Constants::NUMBERLEVEL_ANY == m_level) || 
  -			(Constants::NUMBERLEVEL_SINGLE == m_level))
  +		if(Constants::NUMBERLEVEL_ANY == m_level)
   		{
  -			int numberFound;
  -			if(Constants::NUMBERLEVEL_SINGLE == m_level)
  -			{
  -				XalanNode*	target =
  -					findAncestor(executionContext,
  -								 m_fromMatchPattern, 
  -								 countMatchPattern,
  -								 sourceNode,
  -								 this);
  -
  -				if(target == 0) 
  -					target = executionContext.getParentOfNode(*sourceNode);
  -
  -				if(target != 0)
  -				{
  -					numberFound = getSiblingNumber(executionContext, countMatchPattern, target);
  -					if (numberFound > 0)
  -						numberList.push_back(numberFound);
  -				}
  -				else
  -				{
  -					executionContext.warn(XalanDOMString("Warning: count attribute does not match an ancestor in xsl:number! Target = ") 
  -													+ sourceNode->getNodeName(),
  -										  sourceNode,
  -										  0);
  -				}
  -			}
  -			else // if NUMBERLEVEL_ANY
  +			numberList.push_back(ctable.countNode(executionContext, 
  +			const_cast<ElemNumber* const>(this), sourceNode));
  +		}
  +		else
  +		{
  +			MutableNodeRefList ancestors = getMatchingAncestors(executionContext, sourceNode,
  +					Constants.NUMBERLEVEL_SINGLE == m_level);
  +			int lastIndex = ancestors.getLength();
  +			if(lastIndex > 0)
   			{
  -				XalanNode*	from = 0;
  -
  -				if(0 != m_fromMatchPattern)
  +			/*
  +				numberList.reserve(lastIndex+1);
  +				for(int i = lastIndex; i >= 0; i--)
   				{
  -					from = findPrecedingOrAncestorOrSelf(executionContext, m_fromMatchPattern, countMatchPattern,
  -						sourceNode, this);
  -
  -					if(from == 0)
  -					{
  -						from = sourceNode;
  -					}
  +					const XalanNode* target = ancestors.item(i);
  +					numberList[lastIndex-i] = ctable.countNode(executionContext,
  +							const_cast<ElemNumber* const>(this), target);
   				}
  -				else
  +			*/
  +				for(int i = 0; i < lastIndex; i++)
   				{
  -					from = sourceNode->getOwnerDocument();
  +					const XalanNode* target = ancestors.item(lastIndex - i -1);
  +					numberList.push_back(ctable.countNode(executionContext,
  +							const_cast<ElemNumber* const>(this), target));
   				}
  -
  -				XalanNode* const	fromPos = (from != sourceNode) ? getNextInTree(from, from) : from;
  -
  -				numberFound = getNumberInTree(executionContext.getXPathExecutionContext(),
  -						countMatchPattern, fromPos, from, sourceNode, 0);
  -				if (numberFound > 0)
  -					numberList.push_back(numberFound);
   			}
   		}
  -		else // if NUMBERLEVEL_MULTI
  -		{
  -			 numberList = getAncestorNumbers(executionContext, m_fromMatchPattern,
  -			 	countMatchPattern, sourceNode);
  -		}
   	}
  -
   	return numberList.size() > 0 ? formatNumberList(executionContext, numberList, sourceNode) : XalanDOMString();
   }
   
  -
  -
   XalanNode*
  -ElemNumber::getNextInTree(
  -			XalanNode*	pos,
  -			XalanNode*	from)
  -{
  -	assert(pos != 0);
  -	assert(from != 0);
  -
  -	XalanNode*	posCopy = pos;
  -
  -	XalanNode*	nextNode = posCopy->getFirstChild();
  -
  -	while(nextNode == 0)
  -	{
  -		nextNode = posCopy->getNextSibling();
  -
  -		if(nextNode == 0)
  -		{
  -			posCopy = posCopy->getParentNode();
  +ElemNumber::getPreviousNode(
  +		StylesheetExecutionContext&		executionContext,
  +		XalanNode* pos)
  +{    
  +	const XPath* countMatchPattern = getCountMatchPattern(executionContext, pos);
  +	if(Constants::NUMBERLEVEL_ANY == m_level)
  +	{
  +		const XPath* fromMatchPattern = m_fromMatchPattern;
  +
  +		// Do a backwards document-order walk 'till a node is found that matches 
  +		// the 'from' pattern, or a node is found that matches the 'count' pattern, 
  +		// or the top of the tree is found.
  +		while(0 != pos)
  +		{            
  +			// Get the previous sibling, if there is no previous sibling, 
  +			// then count the parent, but if there is a previous sibling, 
  +			// dive down to the lowest right-hand (last) child of that sibling.
  +			XalanNode* next = pos->getPreviousSibling();
  +			if(0 == next)
  +			{
  +				next = pos->getParentNode();
  +				if((0 != next) && ((((0 != fromMatchPattern) &&
  +						(fromMatchPattern->getMatchScore(next, *this,
  +						executionContext.getXPathExecutionContext()) !=
  +									 XPath::s_MatchScoreNone))) || 
  +							(next->getNodeType() == XalanNode::DOCUMENT_NODE)))
  +				{
  +					pos = 0; // return 0 from function.
  +					break; // from while loop
  +				}
  +			}
  +			else
  +			{
  +				// dive down to the lowest right child.
  +				XalanNode* child = next;
  +				while(0 != child)
  +				{
  +					child = next->getLastChild();
  +					if(0 != child)
  +						next = child;
  +				}
  +			}
  +			pos = next;
   
  -			if(posCopy == from)
  +			if((0 != pos) && ((0 == countMatchPattern) ||
  +						(countMatchPattern->getMatchScore(pos, *this,
  +						executionContext.getXPathExecutionContext()) !=
  +						 XPath::s_MatchScoreNone)))
   			{
   				break;
   			}
   		}
   	}
  -
  -	return nextNode;
  -}
  -
  -
  -
  -unsigned int
  -ElemNumber::getNumberInTree(	
  -			XPathExecutionContext&	executionContext,
  -			const XPath*			countMatchPattern, 
  -			XalanNode*				pos, 
  -			XalanNode*				from, 
  -			XalanNode*				target,
  -			int						countFrom) const
  -{
  -	XalanNode*	posCopy = pos;
  -
  -	int			count = countFrom;
  -
  -	if(posCopy != 0)
  +	else // NUMBERLEVEL_MULTI or NUMBERLEVEL_SINGLE
   	{
  -		do
  -		{          
  -			if( (0 == countMatchPattern) || 
  -				(countMatchPattern->getMatchScore(posCopy,
  -												  *this,
  -												  executionContext) != XPath::s_MatchScoreNone))
  +		while(0 != pos)
  +		{            
  +			pos = pos->getPreviousSibling();
  +			if((0 != pos) && ((0 == countMatchPattern) ||
  +						(countMatchPattern->getMatchScore(pos, *this,
  +						executionContext.getXPathExecutionContext()) !=
  +						 XPath::s_MatchScoreNone)))
   			{
  -				count++;
  +				break;
   			}
   		}
  -
  -		while(posCopy != target && 
  -				(posCopy = getNextInTree(posCopy, from)) != 0);
   	}
  -
  -	return count;
  +	return pos;
   }
   
  -
   
  -unsigned int
  -ElemNumber::getSiblingNumber(
  -			StylesheetExecutionContext&		executionContext,
  -			const XPath*					countMatchPattern, 
  -			XalanNode*						target) const
  +XalanNode*
  +ElemNumber::getTargetNode(
  +		StylesheetExecutionContext& executionContext,
  +		const XalanNode* const sourceNode)
   {
  -	assert(target != 0);
  -
  -	int number = 0;
  -
  -	const XalanNode* const	theParent = executionContext.getParentOfNode(*target);
  -	assert(theParent != 0);
  -
  -	// TODO: If target is an Attr, implement special handling. 
  -	XalanNode*		child = theParent->getFirstChild();
  -
  -	while(child != 0)
  +	XalanNode* target = 0;
  +	const XPath* countMatchPattern =
  +		getCountMatchPattern(executionContext, sourceNode);
  +	if(Constants::NUMBERLEVEL_ANY == m_level)
   	{
  -		if(child == target)
  -		{
  -			number++; // always count the target
  -			break;
  -		}
  -		else if(0 == countMatchPattern || 
  -				countMatchPattern->getMatchScore(child,
  -												 *this,
  -												 executionContext.getXPathExecutionContext()) != XPath::s_MatchScoreNone)
  -		{
  -			number++;
  -		}
  -
  -		child = child->getNextSibling();
  +		target = findPrecedingOrAncestorOrSelf(executionContext,
  +				m_fromMatchPattern, countMatchPattern, sourceNode, this);
   	}
  -
  -	return number;
  -}
  -
  -
  -
  -unsigned int
  -ElemNumber::countMatchingAncestors(
  -			StylesheetExecutionContext&		executionContext,
  -			const XPath*					patterns,
  -			XalanNode*						node) const
  -{
  -	int			count = 0;
  -
  -	XalanNode*	nodeCopy = node;
  -
  -	while(nodeCopy != 0)
  +	else
   	{
  -		if(0 != patterns)
  -		{
  -			if(patterns->getMatchScore(nodeCopy,
  -									   *this,
  -									   executionContext.getXPathExecutionContext()) != XPath::s_MatchScoreNone)
  -			{
  -				count++;
  -			}  
  -		}
  -		else
  -		{
  -			count++;
  -		}
  -
  -		nodeCopy = executionContext.getParentOfNode(*nodeCopy);
  +		target = findAncestor(executionContext, m_fromMatchPattern,
  +				countMatchPattern, sourceNode, this);
   	}
  -
  -	return count;
  +	return target;
   }
   
  -
   
  -ElemNumber::IntArrayType
  -ElemNumber::getAncestorNumbers(
  -			StylesheetExecutionContext&		executionContext,
  -			const XPath*					fromMatchPattern,
  -			const XPath*					countMatchPattern, 
  -			XalanNode*						node) const
  +/**
  + * Get the ancestors, up to the root, that match the
  + * pattern.
  + * @param patterns if non-0, count only nodes
  + * that match this pattern, if 0 count all ancestors.
  + * @param node Count this node and it's ancestors.
  + * @return The number of ancestors that match the pattern.
  + */
  +MutableNodeRefList
  +ElemNumber::getMatchingAncestors(
  +		StylesheetExecutionContext&		executionContext,
  +		XalanNode* node, 
  +		bool stopAtFirstFound) const
   {
  -	XalanNode*			nodeCopy = node;
  -
  -	const unsigned int	nMatchingAncestors =
  -				countMatchingAncestors(executionContext,
  -									   countMatchPattern,
  -									   nodeCopy);
  +	MutableNodeRefList ancestors;
  +	const XPath* countMatchPattern = getCountMatchPattern(executionContext, node);
  +	while( 0 != node )
  +	{
  +		if((0 != m_fromMatchPattern) &&
  +				(m_fromMatchPattern->getMatchScore(node, *this, executionContext.getXPathExecutionContext()) !=
  +				 XPath::s_MatchScoreNone))
  +		{ 
  +			// The following if statement gives level="single" different 
  +			// behavior from level="multiple", which seems incorrect according 
  +			// to the XSLT spec.  For now we are leaving this in to replicate 
  +			// the same behavior in XT, but, for all intents and purposes we 
  +			// think this is a bug, or there is something about level="single" 
  +			// that we still don't understand.
  +			if(!stopAtFirstFound)
  +				break;
  +		}  
   
  -	IntArrayType	counts(nMatchingAncestors);
  +		if(0 == countMatchPattern)
  +			error(XalanDOMString("Programmers error! countMatchPattern should never be 0!"));
   
  -	if(nMatchingAncestors > 0)
  -	{
  -		int		countIndex = counts.size() - 1; // position to put count into
  -
  -		while(nodeCopy != 0)
  +		if(countMatchPattern->getMatchScore(node, *this, executionContext.getXPathExecutionContext()) !=
  +				XPath::s_MatchScoreNone)
   		{
  -			bool	countIt = false;
  -
  -			if(0 != countMatchPattern)
  -			{
  -				if(countMatchPattern->getMatchScore(nodeCopy,
  -													*this,
  -													executionContext.getXPathExecutionContext()) != XPath::s_MatchScoreNone)
  -				{
  -					countIt = true;
  -				} 
  -			}
  -			else
  -			{
  -				countIt = true;
  -			}
  -
  -			if(countIt == true)
  -			{
  -				XalanNode*	target =
  -						findAncestor(executionContext,
  -									 fromMatchPattern,
  -									 countMatchPattern,
  -									 nodeCopy,
  -									 this);
  -
  -				if(target == 0)
  -					target = nodeCopy;
  -
  -				counts[countIndex] = getSiblingNumber(executionContext, countMatchPattern, target);
  -				countIndex--;
  -			}
  -
  -			nodeCopy = executionContext.getParentOfNode(*nodeCopy);
  -		} // end while
  -	} // end if nMatchingAncestors > 0
  -
  -	return counts;
  -}
  -
  +			ancestors.addNode(node);
  +			if(stopAtFirstFound)
  +				break;
  +		}
  +		node = executionContext.getParentOfNode(*node);
  +	}
  +	return ancestors;
  +} // end getMatchingAncestors method
   
   
   #if ! defined(__GNUC__)
  @@ -679,31 +586,31 @@
       // Helper to format local specific numbers to strings.
   	std::auto_ptr<NumberFormat>		formatter(new NumberFormat);
   
  -	const XalanDOMString	digitGroupSepValue = (!isEmpty(m_groupingSeparator_avt))
  -                                  ?  executionContext.evaluateAttrVal(contextNode,
  -																	  *this,
  -																	  m_groupingSeparator_avt) :
  -									 XalanDOMString();
  -
  -    const XalanDOMString	nDigitsPerGroupValue = (!isEmpty(m_groupingSize_avt))
  -                                  ?  executionContext.evaluateAttrVal(contextNode,
  -																	  *this, 
  -																	  m_groupingSize_avt) :
  -									 XalanDOMString();
  +	XalanDOMString	digitGroupSepValue;
  +	if (0 != m_groupingSeparator_avt)
  +		 m_groupingSeparator_avt->evaluate(digitGroupSepValue, contextNode,
  +				 *this, executionContext.getXPathExecutionContext());
  +									 
  +	XalanDOMString	nDigitsPerGroupValue;
  +	if (0 != m_groupingSize_avt)
  +		m_groupingSize_avt->evaluate(nDigitsPerGroupValue, contextNode, *this,
  +				executionContext.getXPathExecutionContext());
   
       // TODO: Handle digit-group attributes
  -    if(!isEmpty(digitGroupSepValue) || !isEmpty(nDigitsPerGroupValue))
  -    {
  +	// 7.7.1 If one is empty, it is ignored	(numb81 conf test)
  +	if(!isEmpty(digitGroupSepValue) && !isEmpty(nDigitsPerGroupValue))
  +	{
   		formatter->setGroupingUsed(true);
  -		formatter->setGroupingSeparator(m_groupingSeparator_avt);
  -		formatter->setGroupingSize(m_groupingSize_avt);
  -    }
  -    
  -    return formatter.release();
  -}
  +		formatter->setGroupingSeparator(digitGroupSepValue);
  +		formatter->setGroupingSize(nDigitsPerGroupValue);
  +	}
   
  +	return formatter.release();
  +}
   
   
  +//@@ JMD: this is different from the java version, but seems to work, so I'll
  +//leave it alone
   XalanDOMString
   ElemNumber::formatNumberList(
   			StylesheetExecutionContext&		executionContext,
  @@ -723,16 +630,14 @@
   	if (nNumbers == 0) return formattedNumber;
   	if (contextNode == 0) return formattedNumber;
   
  -	XalanDOMString	formatValue = !isEmpty(m_format_avt)
  -		? executionContext.evaluateAttrVal(contextNode,
  -										   *this,
  -										   m_format_avt)
  -		: XalanDOMString();
  +	XalanDOMString	formatValue;
  +	if (m_format_avt != 0)
  +		 m_format_avt->evaluate(formatValue, contextNode, *this, executionContext.getXPathExecutionContext());
   
   	if(isEmpty(formatValue)) 
   		formatValue = XALAN_STATIC_UCODE_STRING("1");
   
  -	NumeratorFormatter::NumberFormatStringTokenizer		formatTokenizer(formatValue);
  +	NumberFormatStringTokenizer		formatTokenizer(formatValue);
   
   #if ! defined(__GNUC__)
   	std::locale		loc = getLocale(executionContext, contextNode);
  @@ -806,10 +711,14 @@
   			int								listElement) const
   {
   
  -	std::auto_ptr<NumberFormat> formatter(getNumberFormatter(executionContext, contextNode));
  +	std::auto_ptr<NumberFormat> formatter(
  +			getNumberFormatter(executionContext, contextNode));
   
   	XalanDOMString	padString = formatter->format(0);
  -	XalanDOMString	lookahead;
  +	XalanDOMString letterVal;
  +	if (m_lettervalue_avt != 0)
  +		m_lettervalue_avt->evaluate(letterVal, contextNode, *this,
  +				executionContext.getXPathExecutionContext());
   
   	XalanDOMString	formattedNumber;
   
  @@ -827,7 +736,18 @@
   		case 'i':
   			formattedNumber += toLowerCase(long2roman(listElement, true));
   			break;
  -
  +		case 0x3042:
  +		case 0x3044:
  +		case 0x30A2:
  +		case 0x30A4:
  +		case 0x4E00:
  +		case 0x58F9:
  +		case 0x0E51:
  +		case 0x05D0:
  +		case 0x10D0:
  +		case 0x03B1:
  +		case 0x0430:
  +			executionContext.error(LongToDOMString(numberType) + " format not supported yet!");
   		default: // "1"
   			{
   				const XalanDOMString		numString =
  @@ -848,19 +768,21 @@
   	return formattedNumber;  
   }
   
  +XalanDOMString ElemNumber::int2singlealphaCount(int val, 
  +		const XalanDOMString&	table)
  +{
  +	const int		radix = length(table);
   
  +	// TODO:  throw error on out of range input
  +	if (val > radix)
  +		return XalanDOMString(XALAN_STATIC_UCODE_STRING("#E(") +
  +				LongToDOMString(val) +
  +				XALAN_STATIC_UCODE_STRING(")"));
  +	else
  +		return XalanDOMString(charAt(table, val-1));
   
  -/**
  - * Convert a long integer into alphabetic counting, in other words 
  - * count using the sequence A B C ... Z AA AB AC.... etc.
  - * @param val Value to convert -- must be greater than zero.
  - * @param table a table containing one character for each digit in the radix
  - * @return String representing alpha count of number.
  - * @see XSLTEngineImpl#DecimalToRoman
  - * 
  - * Note that the radix of the conversion is inferred from the size
  - * of the table.
  - */
  +}
  +
   XalanDOMString
   ElemNumber::int2alphaCount(
   			int						val,
  @@ -939,6 +861,12 @@
   	return retStr;
   }
   
  +XalanDOMString ElemNumber::tradAlphaCount(int val)
  +{
  +//	@@ JMD: We don't do languages yet, so this is just a placeholder
  +	assert(0);
  +	return XalanDOMString();	// To keep compiler happy
  +}
   
   
   XalanDOMString
  @@ -990,4 +918,228 @@
   	}
   
   	return roman;
  +}
  +
  +
  +/*
  + *				NumberFormatStringTokenizer Class Implementation
  + */
  +
  +ElemNumber::NumberFormatStringTokenizer::NumberFormatStringTokenizer(
  +			const XalanDOMString&	theStr) :
  +	m_currentPosition(0),
  +	m_maxPosition(length(theStr)),
  +	m_str(theStr)
  +{
  +}
  +
  +
  +
  +/*
  +@@ Obsolete ??
  +void
  +ElemNumber::NumberFormatStringTokenizer::setString(const XalanDOMString&	theString)
  +{
  +	m_str = theString;
  +
  +	m_currentPosition = 0;
  +	m_maxPosition = length(theString);
  +}
  +
  +*/
  +
  +// @@ JMD: This seemed to be working OK in previous version and is
  +// functionally equivalent to java, so I left it alone.  Other java methods do
  +// not seem to be needed in this implementation
  +
  +XalanDOMString
  +ElemNumber::NumberFormatStringTokenizer::nextToken() 
  +{
  +	if (m_currentPosition >= m_maxPosition) 
  +	{
  +		// $$$ Todo: Implement!
  +//				throw new NoSuchElementException();
  +	}
  +
  +	const int	start = m_currentPosition;
  +
  +	if (isLetterOrDigit(charAt(m_str, m_currentPosition)))
  +	{
  +		while ((m_currentPosition < m_maxPosition) &&
  +				isLetterOrDigit(charAt(m_str, m_currentPosition))) 
  +			m_currentPosition++;
  +	}
  +	else
  +	{
  +		while ((m_currentPosition < m_maxPosition) &&
  +				!isLetterOrDigit(charAt(m_str, m_currentPosition))) 
  +			m_currentPosition++;
  +	}
  +
  +	// @@ This wasn't working right when start=current=0 with DOMStrings
  +	// need to check it with XalanDOMString's
  +	return substring(m_str, start, m_currentPosition);
  +}
  +
  +
  +
  +int
  +ElemNumber::NumberFormatStringTokenizer::countTokens() const
  +{
  +	int 	count = 0;
  +	int 	currpos = m_currentPosition;
  +
  +	// Tokens consist of sequences of alphabetic characters and sequences of
  +	// non-alphabetic characters
  +	while (currpos < m_maxPosition) 
  +	{
  +		if (isLetterOrDigit(charAt(m_str, currpos)))
  +		{
  +			while ((currpos < m_maxPosition) &&
  +					isLetterOrDigit(charAt(m_str, currpos))) 
  +				currpos++;
  +		}
  +		else
  +		{
  +			while ((currpos < m_maxPosition) &&
  +					!isLetterOrDigit(charAt(m_str, currpos))) 
  +				currpos++;
  +		}
  +		count++;
  +	}
  +	return count;
  +}
  +
  +/*
  + *					CountersTable Class Implementation
  + */
  +
  +ElemNumber::CounterVectorType& ElemNumber::CountersTable::getCounters(ElemNumber* const numberElem)
  +{
  +	Ptr2CounterVectorMapType::iterator it = m_hashTable.find(numberElem);
  +	return (m_hashTable.end() == it) ? putElemNumber(numberElem) : (*it).second;
  +}
  +
  +ElemNumber::CounterVectorType& ElemNumber::CountersTable::putElemNumber(ElemNumber* const numberElem)
  +{
  +#if !defined(XALAN_NO_NAMESPACES)
  +	using std::make_pair;
  +#endif
  +	m_hashTable.insert(make_pair(numberElem, CounterVectorType()));
  +	return (*m_hashTable.find(numberElem)).second;
  +}
  +
  +void ElemNumber::CountersTable::appendBtoFList(MutableNodeRefList& flist, MutableNodeRefList& blist)
  +{
  +	int n = blist.getLength();
  +	for(int i = (n-1); i >= 0; i--)
  +	{
  +		flist.addNode(blist.item(i));
  +	}
  +}
  +
  +/**
  + * Count forward until the given node is found, or until 
  + * we have looked to the given amount.
  + * @node The node to count.
  + * @return The node count, or 0 if not found.
  + */
  +int ElemNumber::CountersTable::countNode(
  +		StylesheetExecutionContext& support,
  +		ElemNumber* const numberElem,
  +		const XalanNode* const node)
  +{
  +	int count = 0;
  +	CounterVectorType& counters = getCounters(numberElem);
  +	int nCounters = counters.size();
  +
  +	XalanNode* target = numberElem->getTargetNode(support, node);
  +	if(0 != target)
  +	{
  +		for(int i = 0; i < nCounters; i++)
  +		{    
  +			Counter counter = counters[i];
  +
  +			count = counter.getPreviouslyCounted(support, target);
  +			if(count > 0)
  +				return count;
  +		}
  +
  +		// In the loop below, we collect the nodes in backwards doc order, so 
  +		// we don't have to do inserts, but then we store the nodes in forwards 
  +		// document order, so we don't have to insert nodes into that list, 
  +		// so that's what the appendBtoFList stuff is all about.  In cases 
  +		// of forward counting by one, this will mean a single node copy from 
  +		// the backwards list (m_newFound) to the forwards list
  +		// (counter.m_countNodes).
  +		count = 0;
  +		for(; 0 != target; target = numberElem->getPreviousNode(support, target))
  +		{   
  +			// First time in, we should not have to check for previous counts, 
  +			// since the original target node was already checked in the 
  +			// block above.
  +			if(0 != count)  
  +			{
  +				for(int i = 0; i < nCounters; i++)
  +				{    
  +					Counter counter = counters[i];
  +					int cacheLen = counter.m_countNodes.getLength();
  +					if((cacheLen > 0) &&
  +							(counter.m_countNodes.item(cacheLen-1) == target))
  +					{
  +						count += (cacheLen+counter.m_countNodesStartCount);
  +						if(cacheLen > 0)
  +							appendBtoFList(counter.m_countNodes, m_newFound);
  +						m_newFound.clear();
  +						return count;
  +					}
  +				}
  +			}
  +			m_newFound.addNode(target);
  +			count++;
  +		}
  +		// If we got to this point, then we didn't find a counter, so make 
  +		// one and add it to the list.
  +		ElemNumber::Counter counter(numberElem);
  +		m_countersMade++; // for diagnostics
  +		appendBtoFList(counter.m_countNodes, m_newFound);
  +		m_newFound.clear();
  +		counters.push_back(counter);
  +	}
  +
  +	return count;
  +}
  +
  +/*
  + *					Counters Class Implementation
  + */
  +    
  +int ElemNumber::Counter::getPreviouslyCounted(
  +		StylesheetExecutionContext& /*support */,
  +		const XalanNode* const node)
  +{
  +	int n = m_countNodes.getLength();
  +	m_countResult = 0;
  +	for(int i = n-1;i >= 0; i--)
  +	{
  +		const XalanNode* countedNode = m_countNodes.item(i);
  +		if(node == countedNode)
  +		{
  +			// Since the list is in backwards order, the count is 
  +			// how many are in the rest of the list.
  +			m_countResult = i+1+m_countNodesStartCount;
  +			break;
  +		}
  +		// Try to see if the given node falls after the counted node...
  +		// if it does, don't keep searching backwards.
  +		if(DOMServices::isNodeAfter(*countedNode, *node))
  +			break;
  +	}
  +	return m_countResult;
  +}
  +
  +XalanNode* ElemNumber::Counter::getLast()
  +{
  +	int size = m_countNodes.getLength();
  +	return (size > 0) ? m_countNodes.item(size-1) : 0;
   }
  
  
  
  1.9       +300 -94   xml-xalan/c/src/XSLT/ElemNumber.hpp
  
  Index: ElemNumber.hpp
  ===================================================================
  RCS file: /home/cvs/xml-xalan/c/src/XSLT/ElemNumber.hpp,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- ElemNumber.hpp	2000/04/11 15:09:25	1.8
  +++ ElemNumber.hpp	2000/04/19 15:59:25	1.9
  @@ -33,7 +33,7 @@
    *    nor may "Apache" appear in their name, without prior written
    *    permission of the Apache Software Foundation.
    *
  - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  +  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
  @@ -58,7 +58,7 @@
   #define XALAN_ELEMNUMBER_HEADER_GUARD 
   
   /**
  - * $Id: ElemNumber.hpp,v 1.8 2000/04/11 15:09:25 dbertoni Exp $
  + * $Id: ElemNumber.hpp,v 1.9 2000/04/19 15:59:25 jdonohue Exp $
    * 
    * $State: Exp $
    * 
  @@ -72,9 +72,12 @@
   
   // Base class header file.
   #include "ElemTemplateElement.hpp"
  +#include "AVT.hpp"
   
  +#include "XPath/MutableNodeRefList.hpp"
   
   
  +
   // Just locale.h in G++
   #if ! defined(__GNUC__)
   #include <locale>
  @@ -95,6 +98,10 @@
   
   class ElemNumber: public ElemTemplateElement
   {
  +private:
  +
  +struct Counter;
  +
   public:
   
   #if defined(XALAN_NO_NAMESPACES)
  @@ -103,8 +110,10 @@
   #     define XALAN_STD std::
   #endif
   	typedef XALAN_STD vector<int> IntArrayType;
  +	typedef XALAN_STD vector<Counter> CounterVectorType;
  +	typedef XALAN_STD map<ElemNumber*, CounterVectorType>Ptr2CounterVectorMapType;
   #	if ! defined(__GNUC__)
  -		typedef XALAN_STD locale LocaleType;
  +	typedef XALAN_STD locale LocaleType;
   #	endif
   #undef XALAN_STD	
   
  @@ -126,6 +135,9 @@
   			int								lineNumber,
   			int								columnNumber);
   
  +	virtual
  +	~ElemNumber();
  +
   	// These methods are inherited from ElemTemplateElement ...
   	
   	virtual void
  @@ -148,10 +160,10 @@
   	 */
   	XalanNode*
   	findAncestor(
  -			StylesheetExecutionContext&		executionContext,
  -			const XPath*					fromMatchPattern,
  -			const XPath*					countMatchPattern,
  -			XalanNode*						context,
  +			StylesheetExecutionContext&	executionContext,
  +			const XPath*						fromMatchPattern,
  +			const XPath*						countMatchPattern,
  +			const XalanNode* const			context,
   			const XalanElement*				namespaceContext) const;
   
   	  /**
  @@ -165,10 +177,10 @@
   	   */
   	XalanNode*
   	findPrecedingOrAncestorOrSelf(
  -			StylesheetExecutionContext&		executionContext,
  -			const XPath*					fromMatchPattern,
  -			const XPath*					countMatchPattern,
  -			XalanNode*						context,
  +			StylesheetExecutionContext&	executionContext,
  +			const XPath*						fromMatchPattern,
  +			const XPath*						countMatchPattern,
  +			const XalanNode* const 			context,
   			const XalanElement*				namespaceContext) const;
   
   	/**
  @@ -177,7 +189,7 @@
   	const XPath*
   	getCountMatchPattern(
   			StylesheetExecutionContext&		executionContext,
  -			XalanNode*						contextNode) const;
  +			const XalanNode* const				contextNode) const;
   
   	/**
   	 * Given an XML source node, get the count according to the 
  @@ -186,93 +198,35 @@
   	XalanDOMString
   	getCountString(
   			StylesheetExecutionContext&		executionContext,
  -			XalanNode*						sourceTree, 
  -			XalanNode*						sourceNode) const;
  +			XalanNode* const					sourceTree, 
  +			XalanNode* const					sourceNode) const;
   
   	/**
  -	 * from any position in the tree, return the 
  -	 * next node in the tree, assuming preorder 
  -	 * traversal preceded, or null if at the end.
  -	 */
  -	static XalanNode*
  -	getNextInTree(
  -			XalanNode*	pos,
  -			XalanNode*	from);
  -
  -	/**
  -	 * Get a number that represents a node based on the
  -	 * position of that node among within the document tree,  
  -	 * and taking into account the count and from patterns as 
  -	 * specified in the XSL specification.
  -	 * @param fromMatchPattern if non-null, where to 
  -	 * start counting from.
  -	 * @param countMatchPattern if non-null, count only nodes 
  -	 * that match this pattern.
  -	 * @param target count this node and preceding nodes.
  -	 * @return A number that counts target and preceding 
  -	 * nodes that qualify.
  -	 */
  -	unsigned int
  -	getNumberInTree(
  -			XPathExecutionContext&	executionContext,
  -			const XPath*			countMatchPattern,
  -			XalanNode*				pos,
  -			XalanNode*				from,
  -			XalanNode*				target,
  -			int						countFrom) const;
  -
  -	/**
  -	 * Get a number that represents a node based on the
  -	 * position of that node among it's siblings, and 
  -	 * taking into account the count and from patterns.
  -	 * @param fromMatchPattern if non-null, where to 
  -	 * start counting from.
  -	 * @param countMatchPattern if non-null, count only nodes 
  -	 * that match this pattern.
  -	 * @param target count this node and preceding siblings.
  -	 * @return A number that counts target and preceding 
  -	 * siblings that qualify.
  +	 * Get the previous node to be counted.
   	 */
  -	unsigned int
  -	getSiblingNumber(
  +	XalanNode* getPreviousNode(
   			StylesheetExecutionContext&		executionContext,
  -			const XPath*					countMatchPattern, 
  -			XalanNode*						target) const;
  +			XalanNode* pos);
   
   	/**
  -	 * Count the ancestors, up to the root, that match the 
  -	 * pattern.
  -	 * @param patterns if non-null, count only nodes 
  -	 * that match this pattern, if null count all ancestors.
  -	 * @param node Count this node and it's ancestors.
  -	 * @return The number of ancestors that match the pattern.
  +	 * Get the target node that will be counted..
   	 */
  -	unsigned int
  -	countMatchingAncestors(	
  -			StylesheetExecutionContext&		executionContext,
  -			const XPath*					patterns,
  -			XalanNode*						node) const;
  +	XalanNode* getTargetNode(
  +			StylesheetExecutionContext& executionContext,
  +			const XalanNode* const sourceNode);
   
   	/**
  -	 * Climb up the ancestor tree, collecting sibling position 
  -	 * numbers (as modified by the fromMatchPattern and 
  -	 * countMatchPattern patterns).
  -	 * @param fromMatchPattern if non-null, where to 
  -	 * start counting from in each sibling list.
  -	 * @param countMatchPattern if non-null, count only ancestors 
  -	 * and siblings that match this pattern.
  -	 * @param node count this node and ancestors that match the countMatchPattern.
  -	 * @return An array of ints of length that matches exactly the number 
  -	 * of ancestors that match countMatchPattern.
  -	 * @exception XSLProcessorException thrown if the active ProblemListener and XMLParserLiaison decide 
  -	 * the error condition is severe enough to halt processing.
  +	 * Get the ancestors, up to the root, that match the
  +	 * pattern.
  +	 * @param patterns if non-0, count only nodes
  +	 * that match this pattern, if 0 count all ancestors.
  +	 * @param node Count this node and it's ancestors.
  +	 * @return The number of ancestors that match the pattern.
   	 */
  -	IntArrayType
  -	getAncestorNumbers(
  +	MutableNodeRefList getMatchingAncestors(
   			StylesheetExecutionContext&		executionContext,
  -			const XPath*					fromMatchPattern,
  -			const XPath*					countMatchPattern, 
  -			XalanNode*						node) const;
  +			XalanNode* node, 
  +			bool stopAtFirstFound) const;
   
   #if ! defined(__GNUC__)
   	/**
  @@ -305,6 +259,20 @@
   			XalanNode*						contextNode) const;
   
   	/**
  +	 * Convert a long integer into alphabetic counting, in other words
  +	 * count using the sequence A B C ... Z.
  +	 * @param val Value to convert -- must be greater than zero.
  +	 * @param table a table containing one character for each digit in the radix
  +	 * @return String representing alpha count of number.
  +	 * @see XSLTEngineImpl#DecimalToRoman
  +	 *
  +	 * Note that the radix of the conversion is inferred from the size
  +	 * of the table.
  +	 */
  +	XalanDOMString int2singlealphaCount(int val, 
  +			const XalanDOMString&	table);
  +		
  +	/**
   	 * Convert a long integer into alphabetic counting, in other words 
   	 * count using the sequence A B C ... Z AA AB AC.... etc.
   	 * @param val Value to convert -- must be greater than zero.
  @@ -321,6 +289,20 @@
   			const XalanDOMString&	table);
   
   	/**
  +	 * Convert a long integer into traditional alphabetic counting, in other words
  +	 * count using the traditional numbering.
  +	 * @param val Value to convert -- must be greater than zero.
  +	 * @param table a table containing one character for each digit in the radix
  +	 * @return String representing alpha count of number.
  +	 * @see XSLProcessor#DecimalToRoman
  +	 *
  +	 * Note that the radix of the conversion is inferred from the size
  +	 * of the table.
  +	 */
  +	static XalanDOMString
  +	tradAlphaCount(int val);
  +
  +	/**
   	 * Convert a long integer into roman numerals.
   	 * @param val Value to convert.
   	 * @param prefixesAreOK true_ to enable prefix notation (e.g. 4 = "IV"),
  @@ -354,11 +336,11 @@
   
   	int				m_level; // = Constants.NUMBERLEVEL_SINGLE;
   	
  -	XalanDOMString	m_format_avt;
  -	XalanDOMString	m_lang_avt;
  -	XalanDOMString	m_lettervalue_avt;
  -	XalanDOMString	m_groupingSeparator_avt;
  -	XalanDOMString	m_groupingSize_avt;
  +	AVT*	m_format_avt;
  +	AVT*	m_lang_avt;
  +	AVT*	m_lettervalue_avt;
  +	AVT*	m_groupingSeparator_avt;
  +	AVT*	m_groupingSize_avt;
   
   	/**
   	* Chars for converting integers into alpha counts.
  @@ -372,8 +354,232 @@
   	 * @see XSLTEngineImpl#long2roman
   	 */
   	static const DecimalToRoman		s_romanConvertTable[];
  -};
   
   
  +
  +// Inner classes
  +
  +
  +	/**
  +	 * This class returns tokens using non-alphanumberic characters as
  +	 * delimiters. 
  +	 */
  +	class NumberFormatStringTokenizer
  +	{
  +		public:
  +
  +			/**
  +			 * Construct a NumberFormatStringTokenizer.
  +			 *
  +			 * @param theStr string to tokenize
  +			 */
  +			explicit
  +				NumberFormatStringTokenizer(const DOMString&	theStr = DOMString());
  +
  +			/**
  +			 * Sets the string to tokenize.
  +			 *
  +			 * @param theString  new string to tokenize
  +			 */
  +			void
  +				setString(const DOMString&	theString);
  +
  +			/**
  +			 * Reset tokenizer so that nextToken() starts from the beginning.
  +			 */
  +			void
  +				reset()
  +				{
  +					m_currentPosition = 0;
  +				}
  +
  +			/**
  +			 * Retrieve the next token to be parsed; behavior is undefined if there
  +			 * are no more tokens
  +			 * 
  +			 * @return next token string
  +			 */
  +			DOMString
  +				nextToken();
  +
  +			/**
  +			 * Determine if there are tokens remaining
  +			 * 
  +			 * @return true if there are more tokens
  +			 */
  +			bool
  +				hasMoreTokens() const
  +				{
  +					return (m_currentPosition >= m_maxPosition) ? false : true;
  +				}
  +
  +			/**
  +			 * Count the number of tokens yet to be parsed
  +			 * 
  +			 * @return number of remaining tokens
  +			 */
  +			int
  +				countTokens() const;
  +
  +		private:
  +
  +			int			m_currentPosition;
  +			int			m_maxPosition;
  +			DOMString	m_str;
  +	}; // end NumberFormatStringTokenizer
  +
  +	/**
  +	 * <meta name="usage" content="internal"/>
  +	 * This is a table of counters, keyed by ElemNumber objects, each 
  +	 * of which has a list of Counter objects.  This really isn't a true 
  +	 * table, it is more like a list of lists (there must be a technical 
  +	 * term for that...).
  +	 */
  +	class CountersTable
  +	{
  +		public:
  +
  +			/**
  +			 * Construct a CountersTable.
  +			 */
  +			CountersTable() : 
  +				m_countersMade(0)
  +				{
  +				};
  +
  +
  +			/**
  +			 * Count forward until the given node is found, or until 
  +			 * we have looked to the given amount.
  +			 * @node The node to count.
  +			 * @return The node count, or 0 if not found.
  +			 */
  +			int CountersTable::countNode(
  +					StylesheetExecutionContext& support,
  +					ElemNumber* const numberElem,
  +					const XalanNode* const node);
  +
  +		private:
  +
  +			/**
  +			 * Get the list of counters that corresponds to 
  +			 * the given ElemNumber object.
  +			 */
  +			CounterVectorType& getCounters(ElemNumber* const numberElem);
  +
  +
  +			/**
  +			 * Put a counter into the table and create an empty 
  +			 * vector as it's value.
  +			 */
  +			CounterVectorType& putElemNumber(ElemNumber* const numberElem);
  +
  +			/**
  +			 * Add a list of counted nodes that were built in backwards document 
  +			 * order, or a list of counted nodes that are in forwards document 
  +			 * order.
  +			 */
  +			void appendBtoFList(MutableNodeRefList& flist, MutableNodeRefList& blist);
  +
  +			/**
  +			 * Place to collect new counters.
  +			 */
  +			MutableNodeRefList m_newFound;
  +
  +			// For diagnostics
  +			int m_countersMade;
  +
  +			// Since we're not really a hash table like in java, we need this
  +			Ptr2CounterVectorMapType m_hashTable;
  +
  +	}; // end CountersTable
  +
  +	friend class CountersTable;
  +
  +	/**
  +	 * <meta name="usage" content="internal"/>
  +	 * A class that does incremental counting for support of xsl:number.
  +	 * This class stores a cache of counted nodes (m_countNodes). 
  +	 * It tries to cache the counted nodes in document order... 
  +	 * the node count is based on its position in the cache list 
  +	 */
  +	struct Counter
  +	{
  +		/**
  +		 * The start count from where m_countNodes counts 
  +		 * from.  In other words, the count of a given node 
  +		 * in the m_countNodes vector is node position + 
  +		 * m_countNodesStartCount.
  +		 */
  +		int m_countNodesStartCount;
  +
  +		/**
  +		 * A vector of all nodes counted so far.
  +		 */
  +		MutableNodeRefList m_countNodes;
  +
  +		/**
  +		 * The node from where the counting starts.  This is needed to 
  +		 * find a counter if the node being counted is not immediatly
  +		 * found in the m_countNodes vector.
  +		 */
  +		XalanNode* m_fromNode;
  +
  +		/**
  +		 * The owning xsl:number element.
  +		 */
  +		ElemNumber* m_numberElem;
  +
  +		/**
  +		 * Value to store result of last getCount call, for benifit
  +		 * of returning val from CountersTable.getCounterByCounted, 
  +		 * who calls getCount.
  +		 */
  +		int m_countResult;
  +
  +		/**
  +		 * Construct a counter object.
  +		 */
  +		Counter(ElemNumber* numberElem, MutableNodeRefList& countNodes) :
  +			m_countNodesStartCount(0),
  +		m_countNodes(countNodes),
  +		m_fromNode(0),
  +		m_numberElem(numberElem),
  +		m_countResult(0)
  +		{
  +		}
  +
  +		/**
  +		 * Construct a counter object.
  +		 */
  +		Counter(ElemNumber* numberElem) :
  +			m_countNodesStartCount(0),
  +		m_countNodes(),
  +		m_fromNode(0),
  +		m_numberElem(numberElem),
  +		m_countResult(0)
  +		{
  +		}
  +
  +		/**
  +		 * Try to find a node that was previously counted. If found, return a
  +		 * positive integer that corresponds to the count.
  +		 * @param node The node to be counted.
  +		 * @returns The count of the node, or -1 if not found.
  +		 */
  +		int getPreviouslyCounted(
  +				StylesheetExecutionContext& support,
  +				const XalanNode* const node);
  +
  +		/**
  +		 * Get the last node in the list.
  +		 */
  +		XalanNode* getLast();
  +
  +	}; // end Counter
  +
  +	friend struct Counter;
  +
  +}; // end ElemNumber
   
   #endif	// XALAN_ELEMNUMBER_HEADER_GUARD