package client.net.sf.saxon.ce.expr.instruct;
import client.net.sf.saxon.ce.expr.Expression;
import client.net.sf.saxon.ce.expr.XPathContext;
import client.net.sf.saxon.ce.expr.XPathContextMajor;
import client.net.sf.saxon.ce.om.StructuredQName;
import client.net.sf.saxon.ce.pattern.Pattern;
import client.net.sf.saxon.ce.trace.Location;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.value.SequenceType;
import java.util.Iterator;
/**
* The runtime object corresponding to an xsl:template element in the stylesheet.
*
* Note that the Template object no longer has precedence information associated with it; this is now
* only in the Rule object that references this Template. This allows two rules to share the same template,
* with different precedences. This occurs when a stylesheet module is imported more than once, from different
* places, with different import precedences.
*/
public class Template extends Procedure {
// TODO: change the calling mechanism for named templates to use positional parameters
// in the same way as functions. For templates that have both a match and a name attribute,
// create a match template as a wrapper around the named template, resulting in separate
// NamedTemplate and MatchTemplate classes. For named templates, perhaps compile into function
// calls directly, the only difference being that context is retained.
// The body of the template is represented by an expression,
// which is responsible for any type checking that's needed.
private Pattern matchPattern;
private StructuredQName templateName;
private boolean hasRequiredParams;
private boolean bodyIsTailCallReturner;
private SequenceType requiredType;
/**
* Create a template
*/
public Template () {
}
/**
* Initialize the template
* @param templateName the name of the template (if any)
* performed by apply-imports
*/
public void setTemplateName(StructuredQName templateName) {
this.templateName = templateName;
}
/**
* Set the match pattern used with this template
* @param pattern the match pattern (may be null for a named template)
*/
public void setMatchPattern(Pattern pattern) {
matchPattern = pattern;
}
/**
* Get the match pattern used with this template
* @return the match pattern, or null if this is a named template with no match pattern
*/
public Pattern getMatchPattern() {
return matchPattern;
}
/**
* Set the expression that forms the body of the template
* @param body the body of the template
*/
public void setBody(Expression body) {
super.setBody(body);
bodyIsTailCallReturner = (body instanceof TailCallReturner);
}
/**
* Get the name of the template (if it is named)
* @return the template name, or null if unnamed
*/
public StructuredQName getTemplateName() {
return templateName;
}
/**
* Get a name identifying the object of the expression, for example a function name, template name,
* variable name, key name, element name, etc. This is used only where the name is known statically.
*
*/
public StructuredQName getObjectName() {
return templateName;
}
/**
* Set whether this template has one or more required parameters
* @param has true if the template has at least one required parameter
*/
public void setHasRequiredParams(boolean has) {
hasRequiredParams = has;
}
/**
* Ask whether this template has one or more required parameters
* @return true if this template has at least one required parameter
*/
public boolean hasRequiredParams() {
return hasRequiredParams;
}
/**
* Set the required type to be returned by this template
* @param type the required type as defined in the "as" attribute on the xsl:template element
*/
public void setRequiredType(SequenceType type) {
requiredType = type;
}
/**
* Get the required type to be returned by this template
* @return the required type as defined in the "as" attribute on the xsl:template element
*/
public SequenceType getRequiredType() {
if (requiredType == null) {
return SequenceType.ANY_SEQUENCE;
} else {
return requiredType;
}
}
/**
* Get the local parameter with a given parameter id
* @param id the parameter id
* @return the local parameter with this id if found, otherwise null
*/
public LocalParam getLocalParam(int id) {
Iterator<Expression> iter = body.iterateSubExpressions();
while (iter.hasNext()) {
Expression child = iter.next();
if (child instanceof LocalParam && ((LocalParam)child).getParameterId() == id) {
return (LocalParam)child;
}
}
return null;
}
/**
* Process the template, without returning any tail calls. This path is used by
* xsl:apply-imports and xsl:next-match
* @param context The dynamic context, giving access to the current node,
*/
public void apply(XPathContextMajor context) throws XPathException {
TailCall tc = applyLeavingTail(context);
while (tc != null) {
tc = tc.processLeavingTail();
}
}
/**
* Process this template, with the possibility of returning a tail call package if the template
* contains any tail calls that are to be performed by the caller.
* @param context the XPath dynamic context
* @return null if the template exited normally; but if it was a tail call, details of the call
* that hasn't been made yet and needs to be made by the caller
*/
public TailCall applyLeavingTail(XPathContextMajor context) throws XPathException {
if (bodyIsTailCallReturner) {
return ((TailCallReturner)body).processLeavingTail(context);
} else {
body.process(context);
return null;
}
}
/**
* Expand the template. Called when the template is invoked using xsl:call-template.
* Invoking a template by this method does not change the current template.
* @param context the XPath dynamic context
* @return null if the template exited normally; but if it was a tail call, details of the call
* that hasn't been made yet and needs to be made by the caller
*/
public TailCall expand(XPathContext context) throws XPathException {
if (bodyIsTailCallReturner) {
return ((TailCallReturner)body).processLeavingTail(context);
} else if (body != null) {
body.process(context);
}
return null;
}
// // required for Trace
public int getConstructType() {
return Location.TEMPLATE;
}
}
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is “Incompatible With Secondary Licenses”, as defined by the Mozilla Public License, v. 2.0.