Index: xml-xalan/c/src/xalanc/XalanEXSLT/XalanEXSLTDynamicImpl.hpp
===================================================================
--- xml-xalan.orig/c/src/xalanc/XalanEXSLT/XalanEXSLTDynamicImpl.hpp
+++ xml-xalan/c/src/xalanc/XalanEXSLT/XalanEXSLTDynamicImpl.hpp
@@ -38,6 +38,59 @@ XALAN_CPP_NAMESPACE_BEGIN
 
 
 
+class XALAN_EXSLT_EXPORT XalanEXSLTFunctionClosure : public Function
+{
+public:
+
+    XalanEXSLTFunctionClosure()
+    {
+    }
+
+    virtual
+    ~XalanEXSLTFunctionClosure()
+    {
+    }
+
+    virtual XObjectPtr
+    execute(
+            XPathExecutionContext&          executionContext,
+            XalanNode*                      context,
+            const XObjectArgVectorType&     args,
+            const LocatorType*              locator) const;
+
+#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
+    virtual Function*
+#else
+    virtual XalanEXSLTFunctionClosure*
+#endif
+    clone(MemoryManagerType&    theManager) const
+    {
+        return XalanCopyConstruct(theManager, *this);
+    }
+
+protected:
+
+    virtual const XalanDOMString&
+    getError(XalanDOMString&    theResult) const
+    {
+        return XalanMessageLoader::getMessage(
+                    theResult,
+                    XalanMessages::EXSLTFunctionAcceptsTwoArguments_1Param,
+                    "closure");
+    }
+
+private:
+
+    // Not implemented...
+    XalanEXSLTFunctionClosure&
+    operator=(const XalanEXSLTFunctionClosure&);
+
+    bool
+    operator==(const XalanEXSLTFunctionClosure&) const;
+};
+
+
+
 class XALAN_EXSLT_EXPORT XalanEXSLTFunctionEvaluate : public FunctionEvaluate
 {
 public:
@@ -98,6 +151,249 @@ private:
 
 
 
+class XALAN_EXSLT_EXPORT XalanEXSLTFunctionDynMap : public Function
+{
+public:
+
+    XalanEXSLTFunctionDynMap()
+    {
+    }
+
+    virtual
+    ~XalanEXSLTFunctionDynMap()
+    {
+    }
+
+    virtual XObjectPtr
+    execute(
+            XPathExecutionContext&          executionContext,
+            XalanNode*                      context,
+            const XObjectArgVectorType&     args,
+            const LocatorType*              locator) const;
+
+#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
+    virtual Function*
+#else
+    virtual XalanEXSLTFunctionDynMap*
+#endif
+    clone(MemoryManagerType&    theManager) const
+    {
+        return XalanCopyConstruct(theManager, *this);
+    }
+
+protected:
+
+    virtual const XalanDOMString&
+    getError(XalanDOMString&    theResult) const
+    {
+        return XalanMessageLoader::getMessage(
+                    theResult,
+                    XalanMessages::EXSLTFunctionAcceptsTwoArguments_1Param,
+                    "map");
+    }
+
+private:
+
+    // Not implemented...
+    XalanEXSLTFunctionDynMap&
+    operator=(const XalanEXSLTFunctionDynMap&);
+
+    bool
+    operator==(const XalanEXSLTFunctionDynMap&) const;
+};
+
+
+
+/**
+ * Base class for min, max & sum -- these are all aggregate functions
+ * over the input nodeset
+ */
+class XALAN_EXSLT_EXPORT XalanEXSLTFunctionDynAggregate : public Function
+{
+public:
+
+    XalanEXSLTFunctionDynAggregate()
+    {
+    }
+
+    virtual
+	~XalanEXSLTFunctionDynAggregate() = 0
+	{
+	}
+
+    virtual XObjectPtr
+    execute(
+            XPathExecutionContext&          executionContext,
+            XalanNode*                      context,
+            const XObjectArgVectorType&     args,
+            const LocatorType*              locator) const;
+
+	virtual void aggregate(
+			double nodeValue, 
+			double &aggregateValue) const = 0;
+
+private:
+
+    // Not implemented...
+    XalanEXSLTFunctionDynAggregate&
+    operator=(const XalanEXSLTFunctionDynAggregate&);
+
+    bool
+    operator==(const XalanEXSLTFunctionDynAggregate&) const;
+};
+
+
+
+class XALAN_EXSLT_EXPORT XalanEXSLTFunctionDynMax : public XalanEXSLTFunctionDynAggregate
+{
+public:
+
+    XalanEXSLTFunctionDynMax()
+    {
+    }
+
+    virtual
+    ~XalanEXSLTFunctionDynMax()
+    {
+    }
+
+#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
+    virtual Function*
+#else
+    virtual XalanEXSLTFunctionDynMax*
+#endif
+    clone(MemoryManagerType&    theManager) const
+    {
+        return XalanCopyConstruct(theManager, *this);
+    }
+
+	virtual void aggregate(
+			double	nodeValue, 
+			double&	aggregateValue) const;
+
+protected:
+
+    virtual const XalanDOMString&
+    getError(XalanDOMString&    theResult) const
+    {
+        return XalanMessageLoader::getMessage(
+                    theResult,
+                    XalanMessages::EXSLTFunctionAcceptsTwoArguments_1Param,
+                    "max");
+    }
+
+private:
+
+    // Not implemented...
+    XalanEXSLTFunctionDynMax&
+    operator=(const XalanEXSLTFunctionDynMax&);
+
+    bool
+    operator==(const XalanEXSLTFunctionDynMax&) const;
+};
+
+
+
+class XALAN_EXSLT_EXPORT XalanEXSLTFunctionDynMin : public XalanEXSLTFunctionDynAggregate
+{
+public:
+
+    XalanEXSLTFunctionDynMin()
+    {
+    }
+
+    virtual
+    ~XalanEXSLTFunctionDynMin()
+    {
+    }
+
+#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
+    virtual Function*
+#else
+    virtual XalanEXSLTFunctionDynMin*
+#endif
+    clone(MemoryManagerType&    theManager) const
+    {
+        return XalanCopyConstruct(theManager, *this);
+    }
+
+	virtual void aggregate(
+			double	nodeValue, 
+			double&	aggregateValue) const;
+
+protected:
+
+    virtual const XalanDOMString&
+    getError(XalanDOMString&    theResult) const
+    {
+        return XalanMessageLoader::getMessage(
+                    theResult,
+                    XalanMessages::EXSLTFunctionAcceptsTwoArguments_1Param,
+                    "min");
+    }
+
+private:
+
+    // Not implemented...
+    XalanEXSLTFunctionDynMin&
+    operator=(const XalanEXSLTFunctionDynMin&);
+
+    bool
+    operator==(const XalanEXSLTFunctionDynMin&) const;
+};
+
+
+
+class XALAN_EXSLT_EXPORT XalanEXSLTFunctionDynSum : public XalanEXSLTFunctionDynAggregate
+{
+public:
+
+    XalanEXSLTFunctionDynSum()
+    {
+    }
+
+    virtual
+    ~XalanEXSLTFunctionDynSum()
+    {
+    }
+
+#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
+    virtual Function*
+#else
+    virtual XalanEXSLTFunctionDynSum*
+#endif
+    clone(MemoryManagerType&    theManager) const
+    {
+        return XalanCopyConstruct(theManager, *this);
+    }
+
+	virtual void aggregate(
+			double	nodeValue, 
+			double&	aggregateValue) const;
+
+protected:
+
+    virtual const XalanDOMString&
+    getError(XalanDOMString&    theResult) const
+    {
+        return XalanMessageLoader::getMessage(
+                    theResult,
+                    XalanMessages::EXSLTFunctionAcceptsTwoArguments_1Param,
+                    "sum");
+    }
+
+private:
+
+    // Not implemented...
+    XalanEXSLTFunctionDynSum&
+    operator=(const XalanEXSLTFunctionDynSum&);
+
+    bool
+    operator==(const XalanEXSLTFunctionDynSum&) const;
+};
+
+
+
 XALAN_CPP_NAMESPACE_END
 
 
Index: xml-xalan/c/src/xalanc/XalanEXSLT/XalanEXSLTDynamic.cpp
===================================================================
--- xml-xalan.orig/c/src/xalanc/XalanEXSLT/XalanEXSLTDynamic.cpp
+++ xml-xalan/c/src/xalanc/XalanEXSLT/XalanEXSLTDynamic.cpp
@@ -18,12 +18,42 @@
 
 
 
+#include <xalanc/PlatformSupport/AttributesImpl.hpp>
+#include <xalanc/PlatformSupport/DoubleSupport.hpp>
 #include <xalanc/PlatformSupport/XalanUnicode.hpp>
 
 
 
+#include <xalanc/Include/XalanAutoPtr.hpp>
+
+
+
+#include <xalanc/XPath/ElementPrefixResolverProxy.hpp>
 #include <xalanc/XPath/XObjectFactory.hpp>
 #include <xalanc/XPath/XPathEnvSupportDefault.hpp>
+#include <xalanc/XPath/XPath.hpp>
+#include <xalanc/XPath/XPathConstructionContextDefault.hpp>
+#include <xalanc/XPath/XPathProcessorImpl.hpp>
+
+
+
+#include <xalanc/XSLT/Constants.hpp>
+
+
+
+#include <xalanc/XalanTransformer/XalanDocumentBuilder.hpp>
+
+
+
+#include <xercesc/sax2/ContentHandler.hpp>
+
+
+
+#if !defined(XALAN_NO_STD_NUMERIC_LIMITS)
+#include <limits>
+#else
+#include <limits.h>
+#endif
 
 
 
@@ -31,6 +61,291 @@ XALAN_CPP_NAMESPACE_BEGIN
 
 
 
+XALAN_USING_XERCES(ContentHandler)
+
+
+
+#if !defined(XALAN_NO_STD_NUMERIC_LIMITS)
+static const double s_maxDouble = 
+	XALAN_STD_QUALIFIER numeric_limits<double>::max();
+#else
+static const double s_maxDouble =
+	DBL_MAX;
+#endif
+
+
+
+// Namespace for extension elements
+static const XalanDOMChar	s_commonNamespace[] =
+{
+	XalanUnicode::charLetter_h,
+	XalanUnicode::charLetter_t,
+	XalanUnicode::charLetter_t,
+	XalanUnicode::charLetter_p,
+	XalanUnicode::charColon,
+	XalanUnicode::charSolidus,
+	XalanUnicode::charSolidus,
+	XalanUnicode::charLetter_e,
+	XalanUnicode::charLetter_x,
+	XalanUnicode::charLetter_s,
+	XalanUnicode::charLetter_l,
+	XalanUnicode::charLetter_t,
+	XalanUnicode::charFullStop,
+	XalanUnicode::charLetter_o,
+	XalanUnicode::charLetter_r,
+	XalanUnicode::charLetter_g,
+	XalanUnicode::charSolidus,
+	XalanUnicode::charLetter_c,
+	XalanUnicode::charLetter_o,
+	XalanUnicode::charLetter_m,
+	XalanUnicode::charLetter_m,
+	XalanUnicode::charLetter_o,
+	XalanUnicode::charLetter_n,
+	0
+};
+
+
+
+static const XalanDOMChar	s_rootNodeName[] =
+{
+    XalanUnicode::charLetter_r,
+    XalanUnicode::charLetter_o,
+    XalanUnicode::charLetter_o,
+    XalanUnicode::charLetter_t,
+    0
+};
+
+
+
+static const XalanDOMChar	s_exslStringName[] =
+{
+	XalanUnicode::charLetter_e,
+	XalanUnicode::charLetter_x,
+	XalanUnicode::charLetter_s,
+	XalanUnicode::charLetter_l,
+	XalanUnicode::charColon,
+	XalanUnicode::charLetter_s,
+	XalanUnicode::charLetter_t,
+	XalanUnicode::charLetter_r,
+	XalanUnicode::charLetter_i,
+	XalanUnicode::charLetter_n,
+	XalanUnicode::charLetter_g,
+	0
+};
+
+
+
+static const XalanDOMChar	s_exslNumberName[] =
+{
+	XalanUnicode::charLetter_e,
+	XalanUnicode::charLetter_x,
+	XalanUnicode::charLetter_s,
+	XalanUnicode::charLetter_l,
+	XalanUnicode::charColon,
+	XalanUnicode::charLetter_n,
+	XalanUnicode::charLetter_u,
+	XalanUnicode::charLetter_m,
+	XalanUnicode::charLetter_b,
+	XalanUnicode::charLetter_e,
+	XalanUnicode::charLetter_r,
+	0
+};
+
+
+
+static const XalanDOMChar	s_exslBooleanName[] =
+{
+	XalanUnicode::charLetter_e,
+	XalanUnicode::charLetter_x,
+	XalanUnicode::charLetter_s,
+	XalanUnicode::charLetter_l,
+	XalanUnicode::charColon,
+	XalanUnicode::charLetter_b,
+	XalanUnicode::charLetter_o,
+	XalanUnicode::charLetter_o,
+	XalanUnicode::charLetter_l,
+	XalanUnicode::charLetter_e,
+	XalanUnicode::charLetter_a,
+	XalanUnicode::charLetter_n,
+	0
+};
+
+
+
+static const XalanDOMChar	s_trueName[] =
+{
+	XalanUnicode::charLetter_t,
+	XalanUnicode::charLetter_r,
+	XalanUnicode::charLetter_u,
+	XalanUnicode::charLetter_e,
+	0
+};
+
+static const XalanDOMChar	s_emptyCharArray[] =
+{
+	0
+};
+
+
+
+static const AttributesImpl s_emptyAttributes(XalanMemMgrs::getDummyMemMgr());
+
+
+
+// Empty class used to abort a run & return an empty nodeset
+class ExecutionError {};
+
+
+static const PrefixResolver* getPrefixResolver(
+			XalanAutoPtr<ElementPrefixResolverProxy>&	theResolverProxy,
+			XPathExecutionContext&						executionContext,
+			XalanNode*									context,
+			const LocatorType*							locator)
+{
+	const PrefixResolver* theResolver =
+			executionContext.getPrefixResolver();
+	if (theResolver == 0)
+	{
+		const XalanNode*    resolverNode = context;
+
+		if (resolverNode->getNodeType() != XalanNode::ELEMENT_NODE)
+		{
+			resolverNode = DOMServices::getParentOfNode(*resolverNode);
+
+			if (context->getNodeType() != XalanNode::ELEMENT_NODE)
+			{
+				const XPathExecutionContext::GetCachedString    theString(executionContext);
+
+				executionContext.warn(
+					XalanMessageLoader::getMessage(
+						theString.get(),
+						XalanMessages::NoPrefixResolverAvailable),
+					context,
+					locator);
+
+				resolverNode = 0;
+			}
+		}
+
+		// Make an ElementPrefixResolverProxy in convoluted fashion
+		const XalanElement *resolverElement = 
+#if defined(XALAN_OLD_STYLE_CASTS)
+			(const XalanElement*)resolverNode;
+#else
+			static_cast<const XalanElement *>(resolverNode);
+#endif
+
+		XalanAllocationGuard    theGuard(
+									executionContext.getMemoryManager(),
+									sizeof(ElementPrefixResolverProxy));
+		theResolverProxy.reset(
+			new (theGuard.get()) ElementPrefixResolverProxy(
+									resolverElement, executionContext.getMemoryManager()));
+		theGuard.release();
+
+		theResolver = theResolverProxy.get();
+	}
+
+	return theResolver;
+}
+
+
+
+XObjectPtr
+XalanEXSLTFunctionClosure::execute(
+			XPathExecutionContext&			executionContext,
+			XalanNode*						context,
+			const XObjectArgVectorType&		args,
+			const LocatorType*				locator) const
+{
+	try
+	{
+		if (args.size() != 2)
+		{
+			XPathExecutionContext::GetAndReleaseCachedString theString(executionContext);
+
+			executionContext.error(getError(theString.get()), context, locator);
+		}
+
+		const XalanDOMString&   theExpression = args[1]->str();
+		if (args[0]->getType() != XObject::eTypeNodeSet)
+			throw ExecutionError();
+
+		// Mess about to get a prefix resolver of some description
+		XalanAutoPtr<ElementPrefixResolverProxy> theResolverProxy;
+		const PrefixResolver *theResolver = 
+			getPrefixResolver(theResolverProxy, executionContext, context, locator);
+
+		// Construct the xpath expression
+		XPathProcessorImpl                  theProcessor(executionContext.getMemoryManager());
+		XPathConstructionContextDefault     theConstructionContext(executionContext.getMemoryManager());
+		XPath                               theXPath(executionContext.getMemoryManager(), locator);
+		theProcessor.initXPath(
+				theXPath,
+				theConstructionContext,
+				theExpression,
+				*theResolver,
+				locator);
+
+		// Create an output nodeset, which will be the union of the output nodesets
+		XPathExecutionContext::BorrowReturnMutableNodeRefList outputSet(executionContext);
+
+		// Create an initial working set, which contains the input nodeset
+		XPathExecutionContext::BorrowReturnMutableNodeRefList nextWorkingSet(executionContext);
+		nextWorkingSet->addNodesInDocOrder(args[0]->nodeset(), executionContext);
+
+		// Run until the next working set is empty
+		while (!nextWorkingSet->empty())
+		{
+			// Create a new next working set as the output from this iteration 
+			XPathExecutionContext::BorrowReturnMutableNodeRefList workingSet(executionContext);
+			XALAN_STD_QUALIFIER swap(workingSet, nextWorkingSet);
+
+			// Push the nodeset as context
+			XPathExecutionContext::ContextNodeListPushAndPop 
+				pushAndPopNodeset(executionContext, *workingSet.get());
+
+			// Run the expression on each of the input nodes, pushing the output
+			// nodesets on the stack if they aren't empty
+			for (unsigned int i = 0; i < workingSet->getLength(); ++i)
+			{
+				XalanNode *contextNode = workingSet->item(i);
+				if (contextNode)
+				{
+					XObjectPtr theResult = theXPath.execute(contextNode, *theResolver, executionContext);
+					
+					// We are supposed to return an empty nodeset if the expression returns
+					// something other than a nodeset.
+					if (theResult->getType() != XObject::eTypeNodeSet)
+						throw ExecutionError();
+
+					// Union the nodeset with the output & next working set
+					const NodeRefListBase &theResultNL = theResult->nodeset();
+					outputSet->addNodesInDocOrder(theResultNL, executionContext);
+					nextWorkingSet->addNodesInDocOrder(theResultNL, executionContext);
+				}
+			}
+		}
+
+		// Return the output nodeset
+		assert(outputSet->checkForDuplicates(executionContext.getMemoryManager()) == false);
+		outputSet->setDocumentOrder();
+		return executionContext.getXObjectFactory().createNodeSet(outputSet);
+	}
+	catch(const XSLException&)
+	{
+	}
+	catch(const ExecutionError&)
+	{
+	}
+
+	// Return an empty nodeset on error
+	XPathExecutionContext::BorrowReturnMutableNodeRefList	theGuard(executionContext);
+	return executionContext.getXObjectFactory().createNodeSet(theGuard);
+}
+
+
+
 XObjectPtr
 XalanEXSLTFunctionEvaluate::execute(
 			XPathExecutionContext&			executionContext,
@@ -53,6 +368,298 @@ XalanEXSLTFunctionEvaluate::execute(
 
 
 
+XObjectPtr
+XalanEXSLTFunctionDynMap::execute(
+			XPathExecutionContext&			executionContext,
+			XalanNode*						context,
+			const XObjectArgVectorType&		args,
+			const LocatorType*				locator) const
+{
+	try
+	{
+		if (args.size() != 2)
+		{
+			XPathExecutionContext::GetAndReleaseCachedString theString(executionContext);
+
+			executionContext.error(getError(theString.get()), context, locator);
+		}
+
+		const XalanDOMString&   theExpression = args[1]->str();
+		if (args[0]->getType() != XObject::eTypeNodeSet)
+			throw ExecutionError();
+
+		// Mess about to get a prefix resolver of some description
+		XalanAutoPtr<ElementPrefixResolverProxy> theResolverProxy;
+		const PrefixResolver *theResolver = 
+			getPrefixResolver(theResolverProxy, executionContext, context, locator);
+
+		// Construct the xpath expression
+		XPathProcessorImpl                  theProcessor(executionContext.getMemoryManager());
+		XPathConstructionContextDefault     theConstructionContext(executionContext.getMemoryManager());
+		XPath                               theXPath(executionContext.getMemoryManager(), locator);
+		theProcessor.initXPath(
+				theXPath,
+				theConstructionContext,
+				theExpression,
+				*theResolver,
+				locator);
+
+		// Create an output nodeset, which will be the union of the output nodesets,
+		// or contain individual exsl:{number,boolean,string} nodes
+		XPathExecutionContext::BorrowReturnMutableNodeRefList outputSet(executionContext);
+
+		// Builder object used for manufacturing exsl: nodes, created the first
+		// time it is needed (as it's not required for an XPath expression that
+		// outputs a nodeset)
+		XalanDocumentBuilder	*theBuilder = 0;
+		ContentHandler			*theContentHandler = 0;
+		XalanNode				*theLastNode = 0;
+		AttributesImpl			theAttributes;
+
+		// Push the nodeset as context
+		const NodeRefListBase &theNodeSet = args[0]->nodeset();
+		XPathExecutionContext::ContextNodeListPushAndPop 
+			pushAndPopNodeset(executionContext, theNodeSet);
+
+		// Run for each node in the input set
+		for (unsigned int i = 0; i < theNodeSet.getLength(); ++i)
+		{
+			XalanNode *node = theNodeSet.item(i);
+			if (!node)
+				continue;
+
+			XObjectPtr theResult = theXPath.execute(node, *theResolver, executionContext);
+			if (theResult->getType() == XObject::eTypeNodeSet)
+			{
+				// Union the nodeset with the output
+				const NodeRefListBase &theResultNL = theResult->nodeset();
+				outputSet->addNodesInDocOrder(theResultNL, executionContext);
+			}
+			else
+			{
+				// We need a builder, so create it if not done already
+				if (!theBuilder)
+				{
+					theBuilder = executionContext.createDocumentBuilder();
+					theContentHandler = theBuilder->getContentHandler();
+
+					theContentHandler->startDocument();
+					theContentHandler->startElement(s_emptyCharArray, s_emptyCharArray, s_rootNodeName, s_emptyAttributes);
+
+					theAttributes.addAttribute(L"xmlns:exsl", Constants::ATTRTYPE_CDATA.c_str(), s_commonNamespace);
+				}
+
+				// Handle number results
+				if (theResult->getType() == XObject::eTypeNumber)
+				{
+					double numResult = theResult->num();
+
+					// Handle specified weirdness with +/-INF -- convert
+					// to +/-DBL_MAX
+					if (DoubleSupport::isPositiveInfinity(numResult))
+					{
+						numResult = s_maxDouble;
+					}
+					else if (DoubleSupport::isNegativeInfinity(numResult))
+					{
+						numResult = -s_maxDouble;
+					}
+
+					// Format the number as a string
+					XPathExecutionContext::GetAndReleaseCachedString theFormattedNumberData(executionContext);
+					XalanDOMString& theFormattedNumber = theFormattedNumberData.get();
+					XObject::string(numResult, theFormattedNumber);
+
+					// add an exsl:number node
+					theContentHandler->startElement(s_commonNamespace, s_emptyCharArray, s_exslNumberName, theAttributes);
+					theContentHandler->characters(theFormattedNumber.data(), theFormattedNumber.size());
+					theContentHandler->endElement(s_commonNamespace, s_emptyCharArray, s_exslNumberName);
+				}
+				// Handle boolean results
+				else if (theResult->getType() == XObject::eTypeBoolean)
+				{
+					// add an exsl:boolean node
+					theContentHandler->startElement(s_commonNamespace, s_emptyCharArray, s_exslBooleanName, theAttributes);
+					if (theResult->boolean())
+					{
+						theContentHandler->characters(s_trueName, sizeof(s_trueName)/sizeof(s_trueName[0]) - 1);
+					}
+					else
+					{
+						theContentHandler->characters(s_emptyCharArray, 0);
+					}
+					theContentHandler->endElement(s_commonNamespace, s_emptyCharArray, s_exslBooleanName);
+				}
+				// Coerce everything else to a string
+				else
+				{
+					// add an exsl:string node
+					const XalanDOMString &stringResult = theResult->str();
+					theContentHandler->startElement(s_commonNamespace, s_emptyCharArray, s_exslStringName, theAttributes);
+					theContentHandler->characters(stringResult.data(), stringResult.size());
+					theContentHandler->endElement(s_commonNamespace, s_emptyCharArray, s_exslStringName);
+				}
+
+				// Put the last added node in the output nodeset
+				if (theLastNode)
+				{
+					theLastNode = theLastNode->getNextSibling();
+				}
+				else
+				{
+					theLastNode = theBuilder->getDocument()->getFirstChild()->getFirstChild();
+				}
+				assert(theLastNode);
+				outputSet->addNodeInDocOrder(theLastNode, executionContext);
+			}
+		}
+
+		// Finish off the document if one was being built
+		if (theBuilder)
+		{
+			theContentHandler->endElement(s_emptyCharArray, s_emptyCharArray, s_rootNodeName);
+			theContentHandler->endDocument();
+		}
+
+		// Return the output nodeset
+		assert(outputSet->checkForDuplicates(executionContext.getMemoryManager()) == false);
+		outputSet->setDocumentOrder();
+		return executionContext.getXObjectFactory().createNodeSet(outputSet);
+	}
+	catch(const XSLException&)
+	{
+	}
+	catch(const ExecutionError&)
+	{
+	}
+
+	// Return an empty nodeset on error
+	XPathExecutionContext::BorrowReturnMutableNodeRefList	theGuard(executionContext);
+	return executionContext.getXObjectFactory().createNodeSet(theGuard);
+}
+
+
+
+XObjectPtr
+XalanEXSLTFunctionDynAggregate::execute(
+			XPathExecutionContext&			executionContext,
+			XalanNode*						context,
+			const XObjectArgVectorType&		args,
+			const LocatorType*				locator) const
+{
+	try
+	{
+		if (args.size() != 2)
+		{
+			XPathExecutionContext::GetAndReleaseCachedString theString(executionContext);
+
+			executionContext.error(getError(theString.get()), context, locator);
+		}
+
+		const XalanDOMString&   theExpression = args[1]->str();
+		if (args[0]->getType() != XObject::eTypeNodeSet)
+			throw ExecutionError();
+
+		// Mess about to get a prefix resolver of some description
+		XalanAutoPtr<ElementPrefixResolverProxy> theResolverProxy;
+		const PrefixResolver *theResolver = 
+			getPrefixResolver(theResolverProxy, executionContext, context, locator);
+
+		// Construct the xpath expression
+		XPathProcessorImpl                  theProcessor(executionContext.getMemoryManager());
+		XPathConstructionContextDefault     theConstructionContext(executionContext.getMemoryManager());
+		XPath                               theXPath(executionContext.getMemoryManager(), locator);
+		theProcessor.initXPath(
+				theXPath,
+				theConstructionContext,
+				theExpression,
+				*theResolver,
+				locator);
+
+		// Push the nodeset as context
+		const NodeRefListBase &theNodeSet = args[0]->nodeset();
+		XPathExecutionContext::ContextNodeListPushAndPop 
+			pushAndPopNodeset(executionContext, theNodeSet);
+
+		double aggregateValue = DoubleSupport::getNaN();
+
+		// Run for each node in the input set
+		for (unsigned int i = 0; i < theNodeSet.getLength(); ++i)
+		{
+			XalanNode *node = theNodeSet.item(i);
+			if (!node)
+				continue;
+
+			// XXX: need to check result type?
+			XObjectPtr theResult = theXPath.execute(node, *theResolver, executionContext);
+			double nodeValue = theResult->num();
+
+			// Return a NaN if anything is a NaN (as math:max)
+			if (DoubleSupport::isNaN(nodeValue))
+				return executionContext.getXObjectFactory().createNumber(DoubleSupport::getNaN());
+
+			// Let the derived class compute the aggregate
+			aggregate(nodeValue, aggregateValue);
+		}
+
+		// Return the result
+		return executionContext.getXObjectFactory().createNumber(aggregateValue);
+	}
+	catch(const XSLException&)
+	{
+	}
+	catch(const ExecutionError&)
+	{
+	}
+
+	// Return NaN on error
+	return executionContext.getXObjectFactory().createNumber(DoubleSupport::getNaN());
+}
+
+
+
+void
+XalanEXSLTFunctionDynMax::aggregate(
+			double	nodeValue,
+			double&	aggregateValue
+) const
+{
+	if (DoubleSupport::isNaN(aggregateValue))
+		aggregateValue = nodeValue;
+	else if (DoubleSupport::greaterThan(nodeValue, aggregateValue))
+		aggregateValue = nodeValue;
+}
+
+			
+			
+void
+XalanEXSLTFunctionDynMin::aggregate(
+			double	nodeValue,
+			double&	aggregateValue
+) const
+{
+	if (DoubleSupport::isNaN(aggregateValue))
+		aggregateValue = nodeValue;
+	else if (DoubleSupport::lessThan(nodeValue, aggregateValue))
+		aggregateValue = nodeValue;
+}
+
+
+
+void
+XalanEXSLTFunctionDynSum::aggregate(
+			double	nodeValue,
+			double&	aggregateValue
+) const
+{
+	if (DoubleSupport::isNaN(aggregateValue))
+		aggregateValue = nodeValue;
+	else
+		aggregateValue += nodeValue;
+}
+
+
+
 static const XalanDOMChar	s_dynamicNamespace[] =
 {
 	XalanUnicode::charLetter_h,
@@ -84,6 +691,20 @@ static const XalanDOMChar	s_dynamicNames
 
 
 
+static const XalanDOMChar	s_closureFunctionName[] =
+{
+	XalanUnicode::charLetter_c,
+	XalanUnicode::charLetter_l,
+	XalanUnicode::charLetter_o,
+	XalanUnicode::charLetter_s,
+	XalanUnicode::charLetter_u,
+	XalanUnicode::charLetter_r,
+	XalanUnicode::charLetter_e,
+	0
+};
+
+
+
 static const XalanDOMChar	s_evaluateFunctionName[] =
 {
 	XalanUnicode::charLetter_e,
@@ -99,13 +720,63 @@ static const XalanDOMChar	s_evaluateFunc
 
 
 
+static const XalanDOMChar	s_mapFunctionName[] =
+{
+	XalanUnicode::charLetter_m,
+	XalanUnicode::charLetter_a,
+	XalanUnicode::charLetter_p,
+	0
+};
+
+
+
+static const XalanDOMChar	s_maxFunctionName[] =
+{
+	XalanUnicode::charLetter_m,
+	XalanUnicode::charLetter_a,
+	XalanUnicode::charLetter_x,
+	0
+};
+
+
+
+static const XalanDOMChar	s_minFunctionName[] =
+{
+	XalanUnicode::charLetter_m,
+	XalanUnicode::charLetter_i,
+	XalanUnicode::charLetter_n,
+	0
+};
+
+
+
+static const XalanDOMChar	s_sumFunctionName[] =
+{
+	XalanUnicode::charLetter_s,
+	XalanUnicode::charLetter_u,
+	XalanUnicode::charLetter_m,
+	0
+};
+
+
+
+static const XalanEXSLTFunctionClosure		s_closureFunction;
 static const XalanEXSLTFunctionEvaluate		s_evaluateFunction;
+static const XalanEXSLTFunctionDynMap		s_mapFunction;
+static const XalanEXSLTFunctionDynMax		s_maxFunction;
+static const XalanEXSLTFunctionDynMin		s_minFunction;
+static const XalanEXSLTFunctionDynSum		s_sumFunction;
 
 
 
 static const XalanEXSLTDynamicFunctionsInstaller::FunctionTableEntry	theFunctionTable[] =
 {
+	{ s_closureFunctionName, &s_closureFunction},
 	{ s_evaluateFunctionName, &s_evaluateFunction},
+	{ s_mapFunctionName, &s_mapFunction},
+	{ s_maxFunctionName, &s_maxFunction},
+	{ s_minFunctionName, &s_minFunction},
+	{ s_sumFunctionName, &s_sumFunction},
 	{ 0, 0 }
 };
 

