[290286]: If template defined before functions, validation errors appear
https://bugs.eclipse.org/bugs/show_bug.cgi?id=290286
diff --git a/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/StylesheetParser.java b/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/StylesheetParser.java
index 1ec97c0..774121e 100644
--- a/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/StylesheetParser.java
+++ b/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/StylesheetParser.java
@@ -7,6 +7,7 @@
  *
  * Contributors:
  *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
+ *     David Carver (STAR) - bug 290286 - Model loading of parameters not respecting functions. 
  *******************************************************************************/
 
 package org.eclipse.wst.xsl.core.internal;
@@ -63,8 +64,7 @@
 				currentTemplate = new Template(sf);
 				sf.addTemplate(currentTemplate);
 				xslEl = currentTemplate;
-			} else if ("param".equals(elName) && elementStack.size() == 2 && currentTemplate != null) //$NON-NLS-1$
-			{
+			} else if ("param".equals(elName) && parentEl.getModelType() != XSLModelObject.Type.STYLESHEET) { //$NON-NLS-1$
 				Parameter param = new Parameter(sf);
 				// determine whether param has a value
 				NodeList childNodes = element.getChildNodes();
@@ -75,7 +75,14 @@
 						break;
 					}
 				}
-				currentTemplate.addParameter(param);
+				if (parentEl.getModelType() == XSLModelObject.Type.FUNCTION) {
+					Function function = (Function) parentEl;
+					function.addParameter(param);
+				} else if (parentEl.getModelType() == XSLModelObject.Type.TEMPLATE
+						&& elementStack.size() == 2 && currentTemplate != null) {
+					Template template = (Template) parentEl;
+					template.addParameter(param);
+				}
 				xslEl = param;
 			} else if ("call-template".equals(elName) && elementStack.size() >= 2) //$NON-NLS-1$
 			{
@@ -101,28 +108,26 @@
 				xslEl = param;
 			} else if ("variable".equals(elName) || "param".equals(elName)) //$NON-NLS-1$ //$NON-NLS-2$
 			{
-				if (elementStack.size() == 1)
-				{// global variable
+				if (elementStack.size() == 1) {// global variable
 					Variable var = new Variable(sf);
 					sf.addGlobalVariable(var);
 					xslEl = var;
-				}
-				else if (elementStack.size() > 1 && currentTemplate != null)
-				{// local variable
+				} else if (elementStack.size() > 1 && currentTemplate != null) {// local
+																				// variable
 					Variable var = new Variable(sf);
 					currentTemplate.addVariable(var);
 					xslEl = var;
 				}
 			} else if ("function".equals(elName)) { //$NON-NLS-1$
+				currentTemplate = null;
 				Function function = new Function(sf);
 				functions.push(function);
 				sf.addFunction(function);
 				xslEl = function;
-			}
-			else {
+			} else {
 				xslEl = new XSLElement(sf);
 			}
-			if (xslEl!=null)
+			if (xslEl != null)
 				configure((IDOMNode) element, xslEl);
 		}
 		elementStack.push(element);
@@ -133,6 +138,7 @@
 				recurse((Element) node);
 			}
 		}
+		
 		if (xslEl instanceof CallTemplate)
 			callTemplates.pop();
 		if (xslEl instanceof Function) {
@@ -157,15 +163,25 @@
 		}
 		if (parentEl != null)
 			parentEl.addChild(element);
-		parentEl = element;
+		if (node.hasChildNodes()) {
+			NodeList nodeList = node.getChildNodes();
+			for (int i = 0; i < nodeList.getLength(); i++) {
+				Node lnode = (Node) nodeList.item(i);
+				if (lnode.getNodeType() == Node.ELEMENT_NODE) {
+					parentEl = element; 
+					break;
+				}
+			}
+		}
+		//parentEl = element;
 	}
 
 	private static void setPositionInfo(IDOMNode node, XSLNode inc) {
 		try {
 			IStructuredDocument structuredDocument = node
 					.getStructuredDocument();
-			int line = structuredDocument.getLineOfOffset(node
-					.getStartOffset());
+			int line = structuredDocument
+					.getLineOfOffset(node.getStartOffset());
 			int lineOffset = structuredDocument.getLineOffset(line);
 			int col = node.getStartOffset() - lineOffset;
 			inc.setOffset(node.getStartOffset());
diff --git a/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/validation/XSLValidator.java b/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/validation/XSLValidator.java
index 9cb855a..c9cd010 100644
--- a/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/validation/XSLValidator.java
+++ b/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/internal/validation/XSLValidator.java
@@ -9,7 +9,8 @@
  *     Doug Satchwell (Chase Technology Ltd) - initial API and implementation
  *     David Carver (STAR) - bug 230072 - Project level specific validation
  *                         - bug 226245 - XPath 2.0 validation for XSLT
- *                         - bug 258937 - XML Catalog support for includes/imports 
+ *                         - bug 258937 - XML Catalog support for includes/imports
+ *                         - bug 290286 - Model loading of parameters not respecting functions. 
  *******************************************************************************/
 package org.eclipse.wst.xsl.core.internal.validation;
 
@@ -39,6 +40,7 @@
 import org.eclipse.wst.xsl.core.internal.util.Debug;
 import org.eclipse.wst.xsl.core.internal.util.XMLCatalog;
 import org.eclipse.wst.xsl.core.model.CallTemplate;
+import org.eclipse.wst.xsl.core.model.Function;
 import org.eclipse.wst.xsl.core.model.Include;
 import org.eclipse.wst.xsl.core.model.Parameter;
 import org.eclipse.wst.xsl.core.model.StylesheetModel;
@@ -47,33 +49,36 @@
 import org.eclipse.wst.xsl.core.model.XSLElement;
 import org.eclipse.wst.xsl.core.model.XSLNode;
 
-
 /**
  * The XSL validator for workspace XSL files.
  * 
  * @author Doug Satchwell
  */
-public class XSLValidator
-{
+public class XSLValidator {
 	private static final String XSLT2_Version = "2.0"; //$NON-NLS-1$
 	private static XSLValidator instance;
 	private IProject project;
 
-	private XSLValidator()
-	{
+	private XSLValidator() {
 	}
 
 	/**
-	 * Validate the given XSL file. Same as <code>validate(xslFile,report,forceBuild)</code> except a new report is created and returned.
+	 * Validate the given XSL file. Same as
+	 * <code>validate(xslFile,report,forceBuild)</code> except a new report is
+	 * created and returned.
 	 * 
-	 * @param xslFile the XSL file
-	 * @param forceBuild true if build should always be forced
+	 * @param xslFile
+	 *            the XSL file
+	 * @param forceBuild
+	 *            true if build should always be forced
 	 * @return the validation report
-	 * @throws CoreException if any exception occurs while validating
+	 * @throws CoreException
+	 *             if any exception occurs while validating
 	 */
-	public ValidationReport validate(IFile xslFile, boolean forceBuild) throws CoreException
-	{
-		XSLValidationReport report = new XSLValidationReport(xslFile.getLocationURI().toString());
+	public ValidationReport validate(IFile xslFile, boolean forceBuild)
+			throws CoreException {
+		XSLValidationReport report = new XSLValidationReport(xslFile
+				.getLocationURI().toString());
 		project = xslFile.getProject();
 		validate(xslFile, report, forceBuild);
 		return report;
@@ -82,96 +87,103 @@
 	/**
 	 * Validate the given XSL file using the specified report.
 	 * 
-	 * @param xslFile the XSL file
-	 * @param report the report to use for reporting validation errors
-	 * @param forceBuild true if build should always be forced
+	 * @param xslFile
+	 *            the XSL file
+	 * @param report
+	 *            the report to use for reporting validation errors
+	 * @param forceBuild
+	 *            true if build should always be forced
 	 * @return the validation report
-	 * @throws CoreException if any exception occurs while validating
+	 * @throws CoreException
+	 *             if any exception occurs while validating
 	 */
-	public void validate(IFile xslFile, XSLValidationReport report, boolean forceBuild) throws CoreException
-	{
+	public void validate(IFile xslFile, XSLValidationReport report,
+			boolean forceBuild) throws CoreException {
 		StylesheetModel stylesheet;
 		if (forceBuild)
 			stylesheet = XSLCore.getInstance().buildStylesheet(xslFile);
 		else
 			stylesheet = XSLCore.getInstance().getStylesheet(xslFile);
-		
+
 		project = xslFile.getProject();
 
 		long start;
 		if (Debug.debugXSLModel) {
 			start = System.currentTimeMillis();
 		}
-		if (stylesheet!=null)
-		{
-			try
-			{
+		if (stylesheet != null) {
+			try {
 				calculateProblems(stylesheet, report);
-			}
-			catch (MaxErrorsExceededException e)
-			{
+			} catch (MaxErrorsExceededException e) {
 				// do nothing
 			}
 		}
 		if (Debug.debugXSLModel) {
 			long end = System.currentTimeMillis();
-			System.out.println("VALIDATE "+xslFile+" in "+(end-start)+"ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+			System.out
+					.println("VALIDATE " + xslFile + " in " + (end - start) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
 		}
 	}
 
-	private void calculateProblems(StylesheetModel stylesheetComposed, XSLValidationReport report) throws MaxErrorsExceededException
-	{
+	private void calculateProblems(StylesheetModel stylesheetComposed,
+			XSLValidationReport report) throws MaxErrorsExceededException {
 		// circular reference check
 		checkCircularRef(stylesheetComposed, report);
 		// include checks
 		checkIncludes(stylesheetComposed, report);
 		// template checks
 		checkTemplates(stylesheetComposed, report);
+		
+		if (stylesheetComposed.getStylesheet().getVersion().equals("2.0")) {
+			checkFunctions(stylesheetComposed, report);
+		}
 		// call-template checks
 		checkCallTemplates(stylesheetComposed, report);
 		// call-template checks
 		if (getPreference(ValidationPreferences.XPATHS) > IMarker.SEVERITY_INFO)
 			checkXPaths(stylesheetComposed.getStylesheet(), report);
-		
-		// TODO a) check globals and b) apply-templates where mode does not exist
+
+		// TODO a) check globals and b) apply-templates where mode does not
+		// exist
 	}
-	
-	private int getPreference(String key)
-	{
+
+	private int getPreference(String key) {
 		if (project == null) {
-			return XSLCorePlugin.getDefault().getPluginPreferences().getInt(key);
+			return XSLCorePlugin.getDefault().getPluginPreferences()
+					.getInt(key);
 		}
-		
-		IEclipsePreferences prefs = new ProjectScope(project).getNode(XSLCorePlugin.getDefault().getBundle().getSymbolicName());
-		boolean useProject = prefs.getBoolean(XSLCorePlugin.USE_PROJECT_SETTINGS, false);
-		
+
+		IEclipsePreferences prefs = new ProjectScope(project)
+				.getNode(XSLCorePlugin.getDefault().getBundle()
+						.getSymbolicName());
+		boolean useProject = prefs.getBoolean(
+				XSLCorePlugin.USE_PROJECT_SETTINGS, false);
+
 		int valPref;
 		if (useProject) {
-			valPref = prefs.getInt(key, ValidationMessage.WARNING);	
+			valPref = prefs.getInt(key, ValidationMessage.WARNING);
 		} else {
-			valPref = XSLCorePlugin.getDefault().getPluginPreferences().getInt(key);
+			valPref = XSLCorePlugin.getDefault().getPluginPreferences().getInt(
+					key);
 		}
 		return valPref;
 	}
 
-	private void checkXPaths(XSLElement xslEl, XSLValidationReport report) throws MaxErrorsExceededException
-	{
+	private void checkXPaths(XSLElement xslEl, XSLValidationReport report)
+			throws MaxErrorsExceededException {
 		validateXPath(xslEl, report, "select"); //$NON-NLS-1$
 		validateXPath(xslEl, report, "test"); //$NON-NLS-1$
 		validateXPath(xslEl, report, "match"); //$NON-NLS-1$
-		for (XSLElement childEl : xslEl.getChildElements())
-		{
+		for (XSLElement childEl : xslEl.getChildElements()) {
 			checkXPaths(childEl, report);
 		}
 	}
 
-	private void validateXPath(XSLElement xslEl, XSLValidationReport report, String attName) throws MaxErrorsExceededException
-	{
+	private void validateXPath(XSLElement xslEl, XSLValidationReport report,
+			String attName) throws MaxErrorsExceededException {
 		XSLAttribute att = xslEl.getAttribute(attName);
-		if (att != null && att.getValue() != null)
-		{
-			try
-			{	
+		if (att != null && att.getValue() != null) {
+			try {
 				String xslVersion = xslEl.getStylesheet().getVersion();
 				String xpathExp = att.getValue();
 				if (xslVersion.equals(XSLT2_Version)) {
@@ -179,138 +191,175 @@
 				} else {
 					XSLTXPathHelper.compile(att.getValue());
 				}
-			}
-			catch (XPathExpressionException e)
-			{
-				createMarker(report, att, getPreference(ValidationPreferences.XPATHS), Messages.XSLValidator_1);
-			}
-			catch (NullPointerException e)
-			{
+			} catch (XPathExpressionException e) {
+				createMarker(report, att,
+						getPreference(ValidationPreferences.XPATHS),
+						Messages.XSLValidator_1);
+			} catch (NullPointerException e) {
 				// not sure why NPE is being thrown here
 			}
 		}
 	}
 
-	private void checkCircularRef(StylesheetModel stylesheetComposed, XSLValidationReport report) throws MaxErrorsExceededException
-	{
+	private void checkCircularRef(StylesheetModel stylesheetComposed,
+			XSLValidationReport report) throws MaxErrorsExceededException {
 		if (stylesheetComposed.hasCircularReference())
-			createMarker(report, stylesheetComposed.getStylesheet(), getPreference(ValidationPreferences.CIRCULAR_REF), Messages.XSLValidator_2);
+			createMarker(report, stylesheetComposed.getStylesheet(),
+					getPreference(ValidationPreferences.CIRCULAR_REF),
+					Messages.XSLValidator_2);
 	}
 
-	private void checkIncludes(StylesheetModel stylesheetComposed, XSLValidationReport report) throws MaxErrorsExceededException
-	{		
+	private void checkIncludes(StylesheetModel stylesheetComposed,
+			XSLValidationReport report) throws MaxErrorsExceededException {
 		// includes
-		for (Include include : stylesheetComposed.getStylesheet().getIncludes())
-		{
+		for (Include include : stylesheetComposed.getStylesheet().getIncludes()) {
 			IFile includedFile = include.getHrefAsFile();
-			if (includedFile == null || !includedFile.exists())
-			{ // included file does not exist
-				XSLAttribute att = include.getAttribute("href");  //$NON-NLS-1$
+			if (includedFile == null || !includedFile.exists()) { // included
+																	// file does
+																	// not exist
+				XSLAttribute att = include.getAttribute("href"); //$NON-NLS-1$
 				if (att != null) {
 					XMLCatalog catalog = new XMLCatalog();
 					if (!catalog.exists(att.getValue())) {
 						// Do we want to try and get the file?
 						// If we do then there might be performance issues
-						createMarker(report, att, getPreference(ValidationPreferences.MISSING_INCLUDE), Messages.XSLValidator_4 + include.getHref());
+						createMarker(
+								report,
+								att,
+								getPreference(ValidationPreferences.MISSING_INCLUDE),
+								Messages.XSLValidator_4 + include.getHref());
 					}
+				} else {
+					createMarker(
+							report,
+							include,
+							getPreference(ValidationPreferences.NAME_ATTRIBUTE_EMPTY),
+							Messages.XSLValidator_23);
 				}
-				else {
-					createMarker(report, include, getPreference(ValidationPreferences.NAME_ATTRIBUTE_EMPTY), Messages.XSLValidator_23 );
-				}
-			}
-			else if (includedFile.equals(include.getStylesheet().getFile()))
-			{ // stylesheet including itself!
-				createMarker(report, include.getAttribute("href"), getPreference(ValidationPreferences.CIRCULAR_REF), Messages.XSLValidator_6); //$NON-NLS-1$
+			} else if (includedFile.equals(include.getStylesheet().getFile())) { // stylesheet
+																					// including
+																					// itself!
+				createMarker(
+						report,
+						include.getAttribute("href"), getPreference(ValidationPreferences.CIRCULAR_REF), Messages.XSLValidator_6); //$NON-NLS-1$
 			}
 		}
-		//imports
-		for (Include include : stylesheetComposed.getStylesheet().getImports())
-		{
+		// imports
+		for (Include include : stylesheetComposed.getStylesheet().getImports()) {
 			IFile includedFile = include.getHrefAsFile();
-			if (includedFile == null || !includedFile.exists())
-			{ // included file does not exist
-				XSLAttribute att = include.getAttribute("href");  //$NON-NLS-1$
+			if (includedFile == null || !includedFile.exists()) { // included
+																	// file does
+																	// not exist
+				XSLAttribute att = include.getAttribute("href"); //$NON-NLS-1$
 				if (att != null) {
 					XMLCatalog catalog = new XMLCatalog();
 					if (!catalog.exists(att.getValue())) {
-						createMarker(report, att, getPreference(ValidationPreferences.MISSING_INCLUDE), Messages.XSLValidator_4 + include.getHref());
+						createMarker(
+								report,
+								att,
+								getPreference(ValidationPreferences.MISSING_INCLUDE),
+								Messages.XSLValidator_4 + include.getHref());
 					}
 				}
+			} else if (includedFile.equals(include.getStylesheet().getFile())) { // stylesheet
+																					// including
+																					// itself!
+				createMarker(
+						report,
+						include.getAttribute("href"), getPreference(ValidationPreferences.CIRCULAR_REF), Messages.XSLValidator_10); //$NON-NLS-1$
 			}
-			else if (includedFile.equals(include.getStylesheet().getFile()))
-			{ // stylesheet including itself!
-				createMarker(report, include.getAttribute("href"), getPreference(ValidationPreferences.CIRCULAR_REF), Messages.XSLValidator_10); //$NON-NLS-1$
+		}
+	}
+	
+	private void checkFunctions(StylesheetModel stylesheetComposed, XSLValidationReport report) throws MaxErrorsExceededException {
+		for (Function function : stylesheetComposed.getStylesheet().getFunctions()) {
+			if (function.getName() != null) {
+				checkParameters(report, function);
 			}
 		}
 	}
 
-	private void checkTemplates(StylesheetModel stylesheetComposed, XSLValidationReport report) throws MaxErrorsExceededException
-	{
-		for (Template template : stylesheetComposed.getStylesheet().getTemplates())
-		{
+	private void checkTemplates(StylesheetModel stylesheetComposed,
+			XSLValidationReport report) throws MaxErrorsExceededException {
+		for (Template template : stylesheetComposed.getStylesheet()
+				.getTemplates()) {
 			// check attributes are correct
-			if (template.getName() != null)
-			{// named template
-//				if (template.getMatch() != null)
-//					createMarker(report, template, IMarker.SEVERITY_ERROR, "Template cannot specify both name and match attributes");
-//				if (template.getMode() != null)
-//					createMarker(report, template, IMarker.SEVERITY_ERROR, "Named templates cannot specify a mode");
+			if (template.getName() != null) {
 				checkParameters(report, template);
-			} 
+			}
 
-			for (Template checkTemplate : stylesheetComposed.getTemplates())
-			{
-				if (checkTemplate != template && checkTemplate.equals(template))
-				{
-					if (template.getStylesheet() == stylesheetComposed.getStylesheet() && checkTemplate.getStylesheet() == stylesheetComposed.getStylesheet())
-					{// templates in this stylesheet conflict with each other
-						createMarker(report, template, getPreference(ValidationPreferences.TEMPLATE_CONFLICT), Messages.XSLValidator_11);
-					}
-					else if (template.getStylesheet() == stylesheetComposed.getStylesheet())
-					{// template in included stylesheet conflicts with this
-						createMarker(report, template, getPreference(ValidationPreferences.TEMPLATE_CONFLICT), Messages.XSLValidator_12);
-					}
-					else
-					{// templates in included stylesheets conflict with each other
-						createMarker(report, template.getStylesheet(), getPreference(ValidationPreferences.TEMPLATE_CONFLICT), Messages.XSLValidator_13);
+			for (Template checkTemplate : stylesheetComposed.getTemplates()) {
+				if (checkTemplate != template && checkTemplate.equals(template)) {
+					if (template.getStylesheet() == stylesheetComposed
+							.getStylesheet()
+							&& checkTemplate.getStylesheet() == stylesheetComposed
+									.getStylesheet()) {// templates in this
+														// stylesheet conflict
+														// with each other
+						createMarker(
+								report,
+								template,
+								getPreference(ValidationPreferences.TEMPLATE_CONFLICT),
+								Messages.XSLValidator_11);
+					} else if (template.getStylesheet() == stylesheetComposed
+							.getStylesheet()) {// template in included
+												// stylesheet conflicts with
+												// this
+						createMarker(
+								report,
+								template,
+								getPreference(ValidationPreferences.TEMPLATE_CONFLICT),
+								Messages.XSLValidator_12);
+					} else {// templates in included stylesheets conflict with
+							// each other
+						createMarker(
+								report,
+								template.getStylesheet(),
+								getPreference(ValidationPreferences.TEMPLATE_CONFLICT),
+								Messages.XSLValidator_13);
 					}
 				}
 			}
 		}
+
 	}
 
-	private void checkParameters(XSLValidationReport report, Template template) throws MaxErrorsExceededException
-	{
-		List<Parameter> parameters = new ArrayList<Parameter>(template.getParameters());
+	private void checkParameters(XSLValidationReport report, Template template)
+			throws MaxErrorsExceededException {
+		List<Parameter> parameters = new ArrayList<Parameter>(template
+				.getParameters());
 		// reverse the parameters order for checking - for duplicate parameters
 		// the first one is valid
 		Collections.reverse(parameters);
 		Set<Parameter> duplicateParameters = new HashSet<Parameter>();
 		// check parameters
-		for (Parameter param : parameters)
-		{
-			if (param.getName() == null)
-			{// name is required
-				createMarker(report, param, getPreference(ValidationPreferences.NAME_ATTRIBUTE_MISSING), Messages.XSLValidator_14);
-			}
-			else if (param.getName().trim().length() == 0)
-			{// name value is required
-				createMarker(report, param, getPreference(ValidationPreferences.NAME_ATTRIBUTE_EMPTY), Messages.XSLValidator_15);
-			}
-			else if (duplicateParameters.contains(param))
-			{// don't recheck the parameter
+		for (Parameter param : parameters) {
+			if (param.getName() == null) {// name is required
+				createMarker(
+						report,
+						param,
+						getPreference(ValidationPreferences.NAME_ATTRIBUTE_MISSING),
+						Messages.XSLValidator_14);
+			} else if (param.getName().trim().length() == 0) {// name value is
+																// required
+				createMarker(
+						report,
+						param,
+						getPreference(ValidationPreferences.NAME_ATTRIBUTE_EMPTY),
+						Messages.XSLValidator_15);
+			} else if (duplicateParameters.contains(param)) {// don't recheck
+																// the parameter
 				continue;
-			}
-			else
-			{// check a parameter with the same name does not exist
-				for (Parameter checkParam : parameters)
-				{
-					if (param != checkParam)
-					{
-						if (param.getName().equals(checkParam.getName()))
-						{
+			} else {// check a parameter with the same name does not exist
+				for (Parameter checkParam : parameters) {
+					if (param != checkParam) {
+						if (param.getName().equals(checkParam.getName())) {
 							duplicateParameters.add(checkParam);
-							createMarker(report, param, getPreference(ValidationPreferences.DUPLICATE_PARAMETER), Messages.XSLValidator_16);
+							createMarker(
+									report,
+									param,
+									getPreference(ValidationPreferences.DUPLICATE_PARAMETER),
+									Messages.XSLValidator_16);
 						}
 					}
 				}
@@ -318,85 +367,141 @@
 		}
 	}
 
-	private void checkCallTemplates(StylesheetModel stylesheetComposed, XSLValidationReport report) throws MaxErrorsExceededException
-	{
-		for (CallTemplate calledTemplate : stylesheetComposed.getStylesheet().getCalledTemplates())
-		{
-			if (calledTemplate.getName() != null)
-			{
+	private void checkParameters(XSLValidationReport report, Function function)
+			throws MaxErrorsExceededException {
+		List<Parameter> parameters = new ArrayList<Parameter>(function
+				.getParameters());
+		// reverse the parameters order for checking - for duplicate parameters
+		// the first one is valid
+		Collections.reverse(parameters);
+		Set<Parameter> duplicateParameters = new HashSet<Parameter>();
+		// check parameters
+		for (Parameter param : parameters) {
+			if (param.getName() == null) {// name is required
+				createMarker(
+						report,
+						param,
+						getPreference(ValidationPreferences.NAME_ATTRIBUTE_MISSING),
+						Messages.XSLValidator_14);
+			} else if (param.getName().trim().length() == 0) {// name value is
+																// required
+				createMarker(
+						report,
+						param,
+						getPreference(ValidationPreferences.NAME_ATTRIBUTE_EMPTY),
+						Messages.XSLValidator_15);
+			} else if (duplicateParameters.contains(param)) {// don't recheck
+																// the parameter
+				continue;
+			} else {// check a parameter with the same name does not exist
+				for (Parameter checkParam : parameters) {
+					if (param != checkParam) {
+						if (param.getName().equals(checkParam.getName())) {
+							duplicateParameters.add(checkParam);
+							createMarker(
+									report,
+									param,
+									getPreference(ValidationPreferences.DUPLICATE_PARAMETER),
+									Messages.XSLValidator_16);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	private void checkCallTemplates(StylesheetModel stylesheetComposed,
+			XSLValidationReport report) throws MaxErrorsExceededException {
+		for (CallTemplate calledTemplate : stylesheetComposed.getStylesheet()
+				.getCalledTemplates()) {
+			if (calledTemplate.getName() != null) {
 				// get the list of templates that might be being called by this
 				// template call
-				List<Template> templateList = stylesheetComposed.getTemplatesByName(calledTemplate.getName());
-				if (templateList.size() == 0)
-				{
+				List<Template> templateList = stylesheetComposed
+						.getTemplatesByName(calledTemplate.getName());
+				if (templateList.size() == 0) {
 					Object[] messageArgs = { calledTemplate.getName() };
-					createMarker(report, calledTemplate.getAttribute("name"), getPreference(ValidationPreferences.CALL_TEMPLATES), MessageFormat.format(Messages.XSLValidator_18, messageArgs)); //$NON-NLS-1$
-				}
-				else
-				{
+					createMarker(
+							report,
+							calledTemplate.getAttribute("name"), getPreference(ValidationPreferences.CALL_TEMPLATES), MessageFormat.format(Messages.XSLValidator_18, messageArgs)); //$NON-NLS-1$
+				} else {
 					Template namedTemplate = templateList.get(0);
-					for (Parameter calledTemplateParam : calledTemplate.getParameters())
-					{
+					for (Parameter calledTemplateParam : calledTemplate
+							.getParameters()) {
 						boolean found = false;
-						for (Parameter namedTemplateParam : namedTemplate.getParameters())
-						{
-							if (calledTemplateParam.getName().equals(namedTemplateParam.getName()))
-							{
+						for (Parameter namedTemplateParam : namedTemplate
+								.getParameters()) {
+							if (calledTemplateParam.getName().equals(
+									namedTemplateParam.getName())) {
 								found = true;
-								if (!namedTemplateParam.isValue() && !calledTemplateParam.isValue()) {
-								    Object[] messageArgs = { calledTemplateParam.getName() };	
-									createMarker(report, calledTemplateParam, getPreference(ValidationPreferences.EMPTY_PARAM), MessageFormat.format(Messages.XSLValidator_20, messageArgs));
+								if (!namedTemplateParam.isValue()
+										&& !calledTemplateParam.isValue()) {
+									Object[] messageArgs = { calledTemplateParam
+											.getName() };
+									createMarker(
+											report,
+											calledTemplateParam,
+											getPreference(ValidationPreferences.EMPTY_PARAM),
+											MessageFormat.format(
+													Messages.XSLValidator_20,
+													messageArgs));
 								}
 								break;
-								
+
 							}
 						}
 						if (!found) {
-							Object[] messageArgs = { calledTemplateParam.getName() };
-							createMarker(report, calledTemplateParam.getAttribute("name"), getPreference(ValidationPreferences.MISSING_PARAM), MessageFormat.format(Messages.XSLValidator_22, messageArgs)); //$NON-NLS-1$
+							Object[] messageArgs = { calledTemplateParam
+									.getName() };
+							createMarker(
+									report,
+									calledTemplateParam.getAttribute("name"), getPreference(ValidationPreferences.MISSING_PARAM), MessageFormat.format(Messages.XSLValidator_22, messageArgs)); //$NON-NLS-1$
 						}
 					}
-					if (getPreference(ValidationPreferences.MISSING_PARAM) > IMarker.SEVERITY_INFO)
-					{
-						for (Parameter namedTemplateParam : namedTemplate.getParameters())
-						{
-							if (!namedTemplateParam.isValue())
-							{
+					if (getPreference(ValidationPreferences.MISSING_PARAM) > IMarker.SEVERITY_INFO) {
+						for (Parameter namedTemplateParam : namedTemplate
+								.getParameters()) {
+							if (!namedTemplateParam.isValue()) {
 								boolean found = false;
-								for (Parameter calledTemplateParam : calledTemplate.getParameters())
-								{
-									if (calledTemplateParam.getName().equals(namedTemplateParam.getName()))
-									{
+								for (Parameter calledTemplateParam : calledTemplate
+										.getParameters()) {
+									if (calledTemplateParam.getName().equals(
+											namedTemplateParam.getName())) {
 										found = true;
 										break;
 									}
 								}
 								if (!found) {
-									Object[] messageArgs = { namedTemplateParam.getName() };
-									createMarker(report, calledTemplate, getPreference(ValidationPreferences.MISSING_PARAM), MessageFormat.format(Messages.XSLValidator_3, messageArgs));
+									Object[] messageArgs = { namedTemplateParam
+											.getName() };
+									createMarker(
+											report,
+											calledTemplate,
+											getPreference(ValidationPreferences.MISSING_PARAM),
+											MessageFormat.format(
+													Messages.XSLValidator_3,
+													messageArgs));
 								}
 							}
 						}
 					}
-				} 
+				}
 			}
 		}
 	}
 
-	private void createMarker(XSLValidationReport report, XSLNode xslNode, int severity, String message) throws MaxErrorsExceededException
-	{
-		if (severity > IMarker.SEVERITY_INFO)
-		{
+	private void createMarker(XSLValidationReport report, XSLNode xslNode,
+			int severity, String message) throws MaxErrorsExceededException {
+		if (severity > IMarker.SEVERITY_INFO) {
 			if (report.getErrors().size() + report.getWarnings().size() > getPreference(ValidationPreferences.MAX_ERRORS))
 				throw new MaxErrorsExceededException();
-			switch (severity)
-			{
-				case IMarker.SEVERITY_ERROR:
-					report.addError(xslNode, message);
-					break;
-				case IMarker.SEVERITY_WARNING:
-					report.addWarning(xslNode, message);
-					break;
+			switch (severity) {
+			case IMarker.SEVERITY_ERROR:
+				report.addError(xslNode, message);
+				break;
+			case IMarker.SEVERITY_WARNING:
+				report.addWarning(xslNode, message);
+				break;
 			}
 		}
 	}
@@ -406,8 +511,7 @@
 	 * 
 	 * @return the singleton XSLValidator instance
 	 */
-	public static XSLValidator getInstance()
-	{
+	public static XSLValidator getInstance() {
 		if (instance == null)
 			instance = new XSLValidator();
 		return instance;
diff --git a/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/model/Function.java b/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/model/Function.java
index 5438e37..ac12abd 100644
--- a/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/model/Function.java
+++ b/bundles/org.eclipse.wst.xsl.core/src/org/eclipse/wst/xsl/core/model/Function.java
@@ -21,6 +21,22 @@
 	final List<Variable> variables = new ArrayList<Variable>();
 	final List<Parameter> parameters = new ArrayList<Parameter>();
 
+	/**
+	 * Return the variables defined in this function.
+	 * @return
+	 */
+	public List<Variable> getVariables() {
+		return variables;
+	}
+
+	/**
+	 * Return the parameters defined in this function.
+	 * @return
+	 */
+	public List<Parameter> getParameters() {
+		return parameters;
+	}
+
 	public Function(Stylesheet stylesheet) {
 		super(stylesheet);
 	}