001: package net.sf.saxon.style;
002:
003: import net.sf.saxon.Err;
004: import net.sf.saxon.expr.Expression;
005: import net.sf.saxon.expr.ExpressionTool;
006: import net.sf.saxon.instruct.CallTemplate;
007: import net.sf.saxon.instruct.Executable;
008: import net.sf.saxon.instruct.Template;
009: import net.sf.saxon.om.*;
010: import net.sf.saxon.trans.XPathException;
011: import net.sf.saxon.type.AnyItemType;
012: import net.sf.saxon.type.ItemType;
013: import net.sf.saxon.type.Type;
014: import net.sf.saxon.value.SequenceType;
015: import net.sf.saxon.value.Whitespace;
016:
017: import java.util.List;
018:
019: /**
020: * An xsl:call-template element in the stylesheet
021: */
022:
023: public class XSLCallTemplate extends StyleElement {
024:
025: private int calledTemplateFingerprint = -1; // the fingerprint of the called template
026: private XSLTemplate template = null;
027: private boolean useTailRecursion = false;
028: private String calledTemplateName = null; // used only for diagnostics
029: private Expression calledTemplateExpression; // allows name to be an AVT
030:
031: /**
032: * Determine whether the called template can be specified as an AVT
033: */
034:
035: protected boolean allowAVT() {
036: return false;
037: }
038:
039: /**
040: * Determine whether this node is an instruction.
041: * @return true - it is an instruction
042: */
043:
044: public boolean isInstruction() {
045: return true;
046: }
047:
048: /**
049: * Determine the type of item returned by this instruction (only relevant if
050: * it is an instruction).
051: * @return the item type returned
052: */
053:
054: protected ItemType getReturnedItemType() {
055: if (template == null) {
056: return AnyItemType.getInstance();
057: } else {
058: return template.getReturnedItemType();
059: }
060: }
061:
062: public void prepareAttributes() throws XPathException {
063:
064: AttributeCollection atts = getAttributeList();
065:
066: String nameAttribute = null;
067:
068: for (int a = 0; a < atts.getLength(); a++) {
069: int nc = atts.getNameCode(a);
070: String f = getNamePool().getClarkName(nc);
071: if (f == StandardNames.NAME) {
072: nameAttribute = atts.getValue(a).trim();
073: } else {
074: checkUnknownAttribute(nc);
075: }
076: }
077:
078: if (nameAttribute == null) {
079: reportAbsence("name");
080: return;
081: }
082:
083: if (allowAVT() && nameAttribute.indexOf('{') >= 0) {
084: calledTemplateExpression = makeAttributeValueTemplate(nameAttribute);
085: } else {
086: calledTemplateName = nameAttribute;
087: try {
088: calledTemplateFingerprint = makeNameCode(nameAttribute
089: .trim()) & 0xfffff;
090: } catch (NamespaceException err) {
091: compileError(err.getMessage(), "XTSE0280");
092: } catch (XPathException err) {
093: compileError(err.getMessage(), "XTSE0280");
094: }
095: }
096: }
097:
098: public void validate() throws XPathException {
099: checkWithinTemplate();
100:
101: AxisIterator kids = iterateAxis(Axis.CHILD);
102: while (true) {
103: NodeInfo child = (NodeInfo) kids.next();
104: if (child == null) {
105: break;
106: }
107: if (child instanceof XSLWithParam) {
108: // OK;
109: } else if (child instanceof XSLFallback
110: && mayContainFallback()) {
111: // xsl:fallback is not allowed on xsl:call-template, but is allowed on saxon:call-template (cheat!)
112: } else if (child.getNodeKind() == Type.TEXT) {
113: // with xml:space=preserve, white space nodes may still be there
114: if (!Whitespace.isWhite(child.getStringValueCS())) {
115: compileError(
116: "No character data is allowed within xsl:call-template",
117: "XTSE0010");
118: }
119: } else {
120: compileError("Child element "
121: + Err.wrap(child.getDisplayName(), Err.ELEMENT)
122: + " is not allowed within xsl:call-template",
123: "XTSE0010");
124: }
125: }
126: if (calledTemplateExpression == null) {
127: template = findTemplate(calledTemplateFingerprint);
128: if (template == null) {
129: return;
130: }
131: }
132: calledTemplateExpression = typeCheck("name",
133: calledTemplateExpression);
134: }
135:
136: public void postValidate() throws XPathException {
137: // check that a parameter is supplied for each required parameter
138: // of the called template
139:
140: if (template != null) {
141: AxisIterator declaredParams = template
142: .iterateAxis(Axis.CHILD);
143: while (true) {
144: NodeInfo param = (NodeInfo) declaredParams.next();
145: if (param == null) {
146: break;
147: }
148: if (param instanceof XSLParam
149: && ((XSLParam) param).isRequiredParam()
150: && !((XSLParam) param).isTunnelParam()) {
151: AxisIterator actualParams = iterateAxis(Axis.CHILD);
152: boolean ok = false;
153: while (true) {
154: NodeInfo withParam = (NodeInfo) actualParams
155: .next();
156: if (withParam == null) {
157: break;
158: }
159: if (withParam instanceof XSLWithParam
160: && ((XSLWithParam) withParam)
161: .getVariableFingerprint() == ((XSLParam) param)
162: .getVariableFingerprint()) {
163: ok = true;
164: break;
165: }
166: }
167: if (!ok) {
168: compileError(
169: "No value supplied for required parameter "
170: + Err.wrap(((XSLParam) param)
171: .getVariableName(),
172: Err.VARIABLE),
173: "XTSE0690");
174: }
175: }
176: }
177:
178: // check that every supplied parameter is declared in the called
179: // template
180:
181: AxisIterator actualParams = iterateAxis(Axis.CHILD);
182: while (true) {
183: NodeInfo w = (NodeInfo) actualParams.next();
184: if (w == null) {
185: break;
186: }
187: if (w instanceof XSLWithParam
188: && !((XSLWithParam) w).isTunnelParam()) {
189: XSLWithParam withParam = (XSLWithParam) w;
190: AxisIterator formalParams = template
191: .iterateAxis(Axis.CHILD);
192: boolean ok = false;
193: while (true) {
194: NodeInfo param = (NodeInfo) formalParams.next();
195: if (param == null) {
196: break;
197: }
198: if (param instanceof XSLParam
199: && ((XSLParam) param)
200: .getVariableFingerprint() == withParam
201: .getVariableFingerprint()) {
202: ok = true;
203: SequenceType required = ((XSLParam) param)
204: .getRequiredType();
205: withParam
206: .checkAgainstRequiredType(required);
207: break;
208: }
209: }
210: if (!ok) {
211: if (!backwardsCompatibleModeIsEnabled()) {
212: compileError(
213: "Parameter "
214: + withParam
215: .getVariableName()
216: + " is not declared in the called template",
217: "XTSE0680");
218: }
219: }
220: }
221: }
222: }
223: }
224:
225: private XSLTemplate findTemplate(int fingerprint)
226: throws XPathException {
227:
228: XSLStylesheet stylesheet = getPrincipalStylesheet();
229: List toplevel = stylesheet.getTopLevel();
230:
231: // search for a matching template name, starting at the end in case of duplicates.
232: // this also ensures we get the one with highest import precedence.
233:
234: for (int i = toplevel.size() - 1; i >= 0; i--) {
235: if (toplevel.get(i) instanceof XSLTemplate) {
236: XSLTemplate t = (XSLTemplate) toplevel.get(i);
237: if (t.getTemplateFingerprint() == fingerprint) {
238: return t;
239: }
240: }
241: }
242: compileError("No template exists named " + calledTemplateName,
243: "XTSE0650");
244: return null;
245: }
246:
247: /**
248: * Mark tail-recursive calls on templates and functions.
249: * For most instructions, this does nothing.
250: */
251:
252: public void markTailCalls() {
253: useTailRecursion = true;
254: }
255:
256: public Expression compile(Executable exec) throws XPathException {
257: Template target = null;
258: NamespaceResolver nsContext = null;
259:
260: if (calledTemplateExpression == null) {
261: if (template == null) {
262: return null; // error already reported
263: }
264: target = template.getCompiledTemplate();
265: } else {
266: //getPrincipalStyleSheet().setRequireRuntimeTemplateMap(true);
267: nsContext = makeNamespaceContext();
268: }
269:
270: CallTemplate call = new CallTemplate(target, useTailRecursion,
271: calledTemplateExpression, nsContext);
272: call.setActualParameters(getWithParamInstructions(exec, false,
273: call), getWithParamInstructions(exec, true, call));
274: ExpressionTool.makeParentReferences(call);
275: return call;
276: }
277:
278: }
279:
280: //
281: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
282: // you may not use this file except in compliance with the License. You may obtain a copy of the
283: // License at http://www.mozilla.org/MPL/
284: //
285: // Software distributed under the License is distributed on an "AS IS" basis,
286: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
287: // See the License for the specific language governing rights and limitations under the License.
288: //
289: // The Original Code is: all this file.
290: //
291: // The Initial Developer of the Original Code is Michael H. Kay.
292: //
293: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
294: //
295: // Contributor(s): none.
296: //
|