001: package net.sf.saxon.style;
002:
003: import net.sf.saxon.Err;
004: import net.sf.saxon.expr.*;
005: import net.sf.saxon.instruct.ApplyTemplates;
006: import net.sf.saxon.instruct.Executable;
007: import net.sf.saxon.om.*;
008: import net.sf.saxon.sort.SortExpression;
009: import net.sf.saxon.sort.SortKeyDefinition;
010: import net.sf.saxon.trans.Mode;
011: import net.sf.saxon.trans.XPathException;
012: import net.sf.saxon.type.Type;
013: import net.sf.saxon.value.SequenceType;
014: import net.sf.saxon.value.Whitespace;
015:
016: /**
017: * An xsl:apply-templates element in the stylesheet
018: */
019:
020: public class XSLApplyTemplates extends StyleElement {
021:
022: private Expression select;
023: private int modeNameCode = -1; // -1 if no mode specified
024: private boolean useCurrentMode = false;
025: private boolean useTailRecursion = false;
026: private Mode mode;
027: private String modeAttribute;
028:
029: /**
030: * Determine whether this node is an instruction.
031: * @return true - it is an instruction
032: */
033:
034: public boolean isInstruction() {
035: return true;
036: }
037:
038: public void prepareAttributes() throws XPathException {
039:
040: AttributeCollection atts = getAttributeList();
041:
042: String selectAtt = null;
043:
044: for (int a = 0; a < atts.getLength(); a++) {
045: int nc = atts.getNameCode(a);
046: String f = getNamePool().getClarkName(nc);
047: if (f == StandardNames.MODE) {
048: modeAttribute = atts.getValue(a).trim();
049: } else if (f == StandardNames.SELECT) {
050: selectAtt = atts.getValue(a);
051: } else {
052: checkUnknownAttribute(nc);
053: }
054: }
055:
056: if (modeAttribute != null) {
057: if (modeAttribute.equals("#current")) {
058: useCurrentMode = true;
059: } else if (modeAttribute.equals("#default")) {
060: // do nothing;
061: } else {
062: try {
063: modeNameCode = makeNameCode(modeAttribute.trim());
064: } catch (NamespaceException err) {
065: compileError(err.getMessage(), "XTSE0280");
066: modeNameCode = -1;
067: } catch (XPathException err) {
068: compileError("Mode name " + Err.wrap(modeAttribute)
069: + " is not a valid QName", "XTSE0280");
070: modeNameCode = -1;
071: }
072: }
073: }
074:
075: if (selectAtt != null) {
076: select = makeExpression(selectAtt);
077: }
078: }
079:
080: public void validate() throws XPathException {
081:
082: checkWithinTemplate();
083:
084: // get the Mode object
085: if (!useCurrentMode) {
086: mode = getPrincipalStylesheet().getRuleManager().getMode(
087: modeNameCode);
088: }
089:
090: // handle sorting if requested
091:
092: AxisIterator kids = iterateAxis(Axis.CHILD);
093: while (true) {
094: NodeInfo child = (NodeInfo) kids.next();
095: if (child == null) {
096: break;
097: }
098: if (child instanceof XSLSort) {
099: // no-op
100: } else if (child instanceof XSLWithParam) {
101: // usesParams = true;
102: } else if (child.getNodeKind() == Type.TEXT) {
103: // with xml:space=preserve, white space nodes may still be there
104: if (!Whitespace.isWhite(child.getStringValueCS())) {
105: compileError(
106: "No character data is allowed within xsl:apply-templates",
107: "XTSE0010");
108: }
109: } else {
110: compileError(
111: "Invalid element within xsl:apply-templates",
112: "XTSE0010");
113: }
114: }
115:
116: if (select == null) {
117: select = new AxisExpression(Axis.CHILD, null);
118: }
119:
120: select = typeCheck("select", select);
121: try {
122: RoleLocator role = new RoleLocator(RoleLocator.INSTRUCTION,
123: "xsl:apply-templates/select", 0, null);
124: role.setSourceLocator(new ExpressionLocation(this ));
125: role.setErrorCode("XTTE0520");
126: select = TypeChecker.staticTypeCheck(select,
127: SequenceType.NODE_SEQUENCE, false, role,
128: getStaticContext());
129: } catch (XPathException err) {
130: compileError(err);
131: }
132:
133: }
134:
135: /**
136: * Mark tail-recursive calls on templates and functions.
137: * For most instructions, this does nothing.
138: */
139:
140: public void markTailCalls() {
141: useTailRecursion = true;
142: }
143:
144: public Expression compile(Executable exec) throws XPathException {
145: SortKeyDefinition[] sortKeys = makeSortKeys();
146: if (sortKeys != null) {
147: useTailRecursion = false;
148: }
149: Expression sortedSequence = select;
150: if (sortKeys != null) {
151: sortedSequence = new SortExpression(select, sortKeys);
152: ExpressionTool.makeParentReferences(sortedSequence);
153: }
154: compileSequenceConstructor(exec, iterateAxis(Axis.CHILD), true);
155: ApplyTemplates app = new ApplyTemplates(sortedSequence,
156: useCurrentMode, useTailRecursion, mode,
157: backwardsCompatibleModeIsEnabled());
158: app.setActualParameters(getWithParamInstructions(exec, false,
159: app), getWithParamInstructions(exec, true, app));
160: ExpressionTool.makeParentReferences(app);
161: return app;
162: }
163:
164: }
165:
166: //
167: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
168: // you may not use this file except in compliance with the License. You may obtain a copy of the
169: // License at http://www.mozilla.org/MPL/
170: //
171: // Software distributed under the License is distributed on an "AS IS" basis,
172: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
173: // See the License for the specific language governing rights and limitations under the License.
174: //
175: // The Original Code is: all this file.
176: //
177: // The Initial Developer of the Original Code is Michael H. Kay.
178: //
179: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
180: //
181: // Contributor(s): none.
182: //
|