001: package net.sf.saxon.expr;
002:
003: import net.sf.saxon.Configuration;
004: import net.sf.saxon.Controller;
005: import net.sf.saxon.instruct.*;
006: import net.sf.saxon.om.AxisIterator;
007: import net.sf.saxon.om.Item;
008: import net.sf.saxon.om.SingletonIterator;
009: import net.sf.saxon.om.ValueRepresentation;
010: import net.sf.saxon.sort.GroupIterator;
011: import net.sf.saxon.trace.InstructionInfoProvider;
012: import net.sf.saxon.trans.Mode;
013: import net.sf.saxon.trans.XPathException;
014:
015: /**
016: * This class represents a "major context" in which an XPath expression is evaluated:
017: * a "major context" object allows all aspects of the dynamic context to change, whereas
018: * a "minor context" only allows changes to the focus and the destination for push output.
019: */
020:
021: public class XPathContextMajor extends XPathContextMinor {
022:
023: private StackFrame stackFrame = null;
024: private ParameterSet localParameters = null;
025: private XSLTContext xsltContext = null;
026:
027: /**
028: * Constructor should only be called by the Controller,
029: * which acts as a XPathContext factory.
030: */
031:
032: public XPathContextMajor(Controller c) {
033: controller = c;
034: stackFrame = StackFrame.EMPTY;
035: origin = controller;
036: }
037:
038: /**
039: * Private Constructor
040: */
041:
042: private XPathContextMajor() {
043: }
044:
045: /**
046: * Constructor for use in free-standing Java applications.
047: */
048:
049: public XPathContextMajor(Item item, Configuration config) {
050: Executable exec = new Executable();
051: exec.setHostLanguage(Configuration.JAVA_APPLICATION);
052: controller = new Controller(config, exec);
053: AxisIterator iter = SingletonIterator.makeIterator(item);
054: iter.next();
055: currentIterator = iter;
056: origin = controller;
057: }
058:
059: /**
060: * Construct a new context as a copy of another. The new context is effectively added
061: * to the top of a stack, and contains a pointer to the previous context
062: */
063:
064: public XPathContextMajor newContext() {
065: XPathContextMajor c = new XPathContextMajor();
066: c.controller = controller;
067: c.currentIterator = currentIterator;
068: c.stackFrame = stackFrame;
069: c.localParameters = localParameters;
070: c.last = last;
071: c.currentReceiver = currentReceiver;
072: c.isTemporaryDestination = isTemporaryDestination;
073: c.xsltContext = xsltContext;
074: c.caller = this ;
075: return c;
076: }
077:
078: public static XPathContextMajor newContext(XPathContextMinor p) {
079: XPathContextMajor c = new XPathContextMajor();
080: c.controller = p.getController();
081: c.currentIterator = p.getCurrentIterator();
082: c.stackFrame = p.getStackFrame();
083: c.localParameters = p.getLocalParameters();
084:
085: c.last = p.last;
086: c.currentReceiver = p.currentReceiver;
087: c.isTemporaryDestination = p.isTemporaryDestination;
088: c.xsltContext = p.getXSLTContext();
089: c.caller = p;
090: return c;
091: }
092:
093: /**
094: * Get the XSLT-specific part of the context
095: */
096:
097: public XSLTContext getXSLTContext() {
098: return xsltContext;
099: }
100:
101: /**
102: * Get the local parameters for the current template call.
103: * @return the supplied parameters
104: */
105:
106: public ParameterSet getLocalParameters() {
107: return localParameters;
108: }
109:
110: /**
111: * Set the local parameters for the current template call.
112: * @param localParameters the supplied parameters
113: */
114:
115: public void setLocalParameters(ParameterSet localParameters) {
116: this .localParameters = localParameters;
117: }
118:
119: /**
120: * Get the tunnel parameters for the current template call.
121: * @return the supplied tunnel parameters
122: */
123:
124: public ParameterSet getTunnelParameters() {
125: if (xsltContext != null) {
126: return xsltContext.tunnelParameters;
127: } else {
128: return null;
129: }
130: }
131:
132: /**
133: * Set the tunnel parameters for the current template call.
134: * @param tunnelParameters the supplied tunnel parameters
135: */
136:
137: public void setTunnelParameters(ParameterSet tunnelParameters) {
138: xsltContext = new XSLTContext(xsltContext);
139: xsltContext.tunnelParameters = tunnelParameters;
140: }
141:
142: /**
143: * Set the creating expression (for use in diagnostics). The origin is generally set to "this" by the
144: * object that creates the new context. It's up to the debugger to determine whether this information
145: * is useful. The object will either be an {@link InstructionInfoProvider}, allowing information
146: * about the calling instruction to be obtained, or null.
147: */
148:
149: public void setOrigin(InstructionInfoProvider expr) {
150: origin = expr;
151: }
152:
153: /**
154: * Get a reference to the local stack frame for variables. Note that it's
155: * the caller's job to make a local copy of this. This is used for creating
156: * a Closure containing a retained copy of the variables for delayed evaluation.
157: * @return array of variables.
158: */
159:
160: public StackFrame getStackFrame() {
161: return stackFrame;
162: }
163:
164: /**
165: * Set the local stack frame. This method is used when creating a Closure to support
166: * delayed evaluation of expressions. The "stack frame" is actually on the Java heap, which
167: * means it can survive function returns and the like.
168: */
169:
170: public void setStackFrame(SlotManager map,
171: ValueRepresentation[] variables) {
172: stackFrame = new StackFrame(map, variables);
173: if (map != null
174: && variables.length != map.getNumberOfVariables()) {
175: stackFrame.slots = new ValueRepresentation[map
176: .getNumberOfVariables()];
177: System.arraycopy(variables, 0, stackFrame.slots, 0,
178: variables.length);
179: }
180: }
181:
182: /**
183: * Create a new stack frame for local variables, using the supplied SlotManager to
184: * define the allocation of slots to individual variables
185: * @param map the SlotManager for the new stack frame
186: */
187: public void openStackFrame(SlotManager map) {
188: int slots = map.getNumberOfVariables();
189: if (slots == 0) {
190: stackFrame = StackFrame.EMPTY;
191: } else {
192: stackFrame = new StackFrame(map,
193: new ValueRepresentation[slots]);
194: }
195: }
196:
197: /**
198: * Create a new stack frame large enough to hold a given number of local variables,
199: * for which no stack frame map is available. This is used in particular when evaluating
200: * match patterns of template rules.
201: * @param numberOfVariables The number of local variables to be accommodated.
202: */
203:
204: public void openStackFrame(int numberOfVariables) {
205: stackFrame = new StackFrame(null,
206: new ValueRepresentation[numberOfVariables]);
207: }
208:
209: /**
210: * Get the value of a local variable, identified by its slot number
211: */
212:
213: public ValueRepresentation evaluateLocalVariable(int slotnumber) {
214: return stackFrame.slots[slotnumber];
215: }
216:
217: /**
218: * Set the value of a local variable, identified by its slot number
219: */
220:
221: public void setLocalVariable(int slotnumber,
222: ValueRepresentation value) {
223: stackFrame.slots[slotnumber] = value;
224: }
225:
226: /**
227: * Set the current mode.
228: * @param mode the new current mode
229: */
230:
231: public void setCurrentMode(Mode mode) {
232: if ((mode != null && !mode.isDefaultMode())
233: || (getCurrentMode() != null)) {
234: xsltContext = new XSLTContext(xsltContext);
235: xsltContext.currentMode = mode;
236: }
237: }
238:
239: /**
240: * Get the current mode.
241: * @return the current mode. May return null if the current mode is the default mode.
242: */
243:
244: public Mode getCurrentMode() {
245: if (xsltContext != null) {
246: return xsltContext.currentMode;
247: } else {
248: return null;
249: }
250: }
251:
252: /**
253: * Set the current template. This is used to support xsl:apply-imports. The caller
254: * is responsible for remembering the previous current template and resetting it
255: * after use.
256: *
257: * @param template the current template
258: */
259:
260: public void setCurrentTemplate(Template template) {
261: xsltContext = new XSLTContext(xsltContext);
262: xsltContext.currentTemplate = template;
263: }
264:
265: /**
266: * Get the current template. This is used to support xsl:apply-imports
267: *
268: * @return the current template
269: */
270:
271: public Template getCurrentTemplate() {
272: if (xsltContext != null) {
273: return xsltContext.currentTemplate;
274: } else {
275: return null;
276: }
277: }
278:
279: /**
280: * Set the current grouping iterator. This supports the current-group() and
281: * current-grouping-key() functions in XSLT 2.0
282: * @param collection the new current GroupIterator
283: */
284:
285: public void setCurrentGroupIterator(GroupIterator collection) {
286: xsltContext = new XSLTContext(xsltContext);
287: xsltContext.currentGroupIterator = collection;
288: }
289:
290: /**
291: * Get the current group iterator. This supports the current-group() and
292: * current-grouping-key() functions in XSLT 2.0
293: * @return the current grouped collection
294: */
295:
296: public GroupIterator getCurrentGroupIterator() {
297: if (xsltContext != null) {
298: return xsltContext.currentGroupIterator;
299: } else {
300: return null;
301: }
302: }
303:
304: /**
305: * Set the current regex iterator. This supports the functionality of the regex-group()
306: * function in XSLT 2.0.
307: * @param currentRegexIterator the current regex iterator
308: */
309:
310: public void setCurrentRegexIterator(
311: RegexIterator currentRegexIterator) {
312: xsltContext = new XSLTContext(xsltContext);
313: xsltContext.currentRegexIterator = currentRegexIterator;
314: }
315:
316: /**
317: * Get the current regex iterator. This supports the functionality of the regex-group()
318: * function in XSLT 2.0.
319: * @return the current regular expressions iterator
320: */
321:
322: public RegexIterator getCurrentRegexIterator() {
323: if (xsltContext != null) {
324: return xsltContext.currentRegexIterator;
325: } else {
326: return null;
327: }
328: }
329:
330: /**
331: * Use local parameter. This is called when a local xsl:param element is processed.
332: * If a parameter of the relevant name was supplied, it is bound to the xsl:param element.
333: * Otherwise the method returns false, so the xsl:param default will be evaluated
334: * @param fingerprint The fingerprint of the parameter name
335: * @param binding The XSLParam element to bind its value to
336: * @param isTunnel True if a tunnel parameter is required, else false
337: * @return true if a parameter of this name was supplied, false if not
338: */
339:
340: public boolean useLocalParameter(int fingerprint,
341: LocalParam binding, boolean isTunnel) throws XPathException {
342:
343: ParameterSet params = (isTunnel ? getTunnelParameters()
344: : localParameters);
345: if (params == null)
346: return false;
347: ValueRepresentation val = params.get(fingerprint);
348: stackFrame.slots[binding.getSlotNumber()] = val;
349: return (val != null);
350: }
351:
352: /**
353: * An XSLTContext object holds all the additional dynamic context items used in XSLT.
354: * These are held in a separate object for two reasons: firstly, they don't change often,
355: * so it's costly to copy them every time a new context object is created, and secondly,
356: * they aren't used at all in XQuery, they just add overhead.
357: */
358:
359: protected static class XSLTContext {
360: public ParameterSet tunnelParameters = null;
361: public Mode currentMode = null;
362: public Template currentTemplate = null;
363: public GroupIterator currentGroupIterator = null;
364: public RegexIterator currentRegexIterator = null;
365:
366: /**
367: * Create a new XSLTContext optionally by copying an existing XSLTContext
368: * @param original the existing XSLTContext. May be null, in which case a new XSLTContext is
369: * created from scratch.
370: */
371:
372: public XSLTContext(XSLTContext original) {
373: if (original != null) {
374: this .tunnelParameters = original.tunnelParameters;
375: this .currentMode = original.currentMode;
376: this .currentTemplate = original.currentTemplate;
377: this .currentGroupIterator = original.currentGroupIterator;
378: this .currentRegexIterator = original.currentRegexIterator;
379: }
380: }
381: }
382:
383: }
384:
385: //
386: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
387: // you may not use this file except in compliance with the License. You may obtain a copy of the
388: // License at http://www.mozilla.org/MPL/
389: //
390: // Software distributed under the License is distributed on an "AS IS" basis,
391: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
392: // See the License for the specific language governing rights and limitations under the License.
393: //
394: // The Original Code is: all this file.
395: //
396: // The Initial Developer of the Original Code is Michael H. Kay.
397: //
398: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
399: //
400: // Contributor(s): none.
401: //
|