001: package net.sf.saxon.instruct;
002:
003: import net.sf.saxon.Controller;
004: import net.sf.saxon.value.Whitespace;
005: import net.sf.saxon.event.*;
006: import net.sf.saxon.expr.ExpressionTool;
007: import net.sf.saxon.expr.XPathContext;
008: import net.sf.saxon.om.Item;
009: import net.sf.saxon.om.NamePool;
010: import net.sf.saxon.om.NodeInfo;
011: import net.sf.saxon.style.StandardNames;
012: import net.sf.saxon.trans.DynamicError;
013: import net.sf.saxon.trans.XPathException;
014: import net.sf.saxon.type.*;
015:
016: import java.io.PrintStream;
017:
018: /**
019: * Handler for xsl:copy elements in stylesheet.
020: */
021:
022: public class Copy extends ElementCreator {
023:
024: private boolean copyNamespaces;
025: private ItemType contextItemType;
026:
027: public Copy(boolean copyNamespaces, boolean inheritNamespaces,
028: SchemaType schemaType, int validation) {
029: this .copyNamespaces = copyNamespaces;
030: this .inheritNamespaces = inheritNamespaces;
031: setSchemaType(schemaType);
032: this .validation = validation;
033: if (copyNamespaces) {
034: setLazyConstruction(false);
035: // can't do lazy construction at present in cases where namespaces need to be copied from the
036: // source document.
037: }
038: }
039:
040: /**
041: * Get the name of this instruction for diagnostic and tracing purposes
042: */
043:
044: public int getInstructionNameCode() {
045: return StandardNames.XSL_COPY;
046: }
047:
048: /**
049: * Get the item type of the result of this instruction.
050: * @return The context item type.
051: * @param th
052: */
053:
054: public ItemType getItemType(TypeHierarchy th) {
055: if (contextItemType == null) {
056: return AnyItemType.getInstance();
057: } else {
058: return contextItemType;
059: }
060: }
061:
062: /**
063: * Callback from ElementCreator when constructing an element
064: * @param context
065: * @return the namecode of the element to be constructed
066: * @throws XPathException
067: */
068:
069: public int getNameCode(XPathContext context) throws XPathException {
070: return ((NodeInfo) context.getContextItem()).getNameCode();
071: }
072:
073: /**
074: * Callback to output namespace nodes for the new element.
075: * @param context The execution context
076: * @param receiver the Receiver where the namespace nodes are to be written
077: * @throws XPathException
078: */
079:
080: protected void outputNamespaceNodes(XPathContext context,
081: Receiver receiver) throws XPathException {
082: if (copyNamespaces) {
083: NodeInfo element = (NodeInfo) context.getContextItem();
084: element.sendNamespaceDeclarations(receiver, true);
085: }
086: }
087:
088: /**
089: * Callback to get a list of the intrinsic namespaces that need to be generated for the element.
090: * The result is an array of namespace codes, the codes either occupy the whole array or are
091: * terminated by a -1 entry. A result of null is equivalent to a zero-length array.
092: */
093:
094: public int[] getActiveNamespaces() throws XPathException {
095: if (copyNamespaces) {
096: // we should have disabled lazy construction, so this shouldn't be called.
097: throw new UnsupportedOperationException();
098: } else {
099: return null;
100: }
101: }
102:
103: public TailCall processLeavingTail(XPathContext context)
104: throws XPathException {
105: Controller controller = context.getController();
106: XPathContext c2 = context.newMinorContext();
107: c2.setOrigin(this );
108: SequenceReceiver out = c2.getReceiver();
109: Item item = context.getContextItem();
110: if (!(item instanceof NodeInfo)) {
111: out.append(item, locationId, NodeInfo.ALL_NAMESPACES);
112: return null;
113: }
114: NodeInfo source = (NodeInfo) item;
115:
116: // Processing depends on the node kind.
117:
118: switch (source.getNodeKind()) {
119:
120: case Type.ELEMENT:
121: // use the generic code for creating new elements
122: return super .processLeavingTail(c2);
123:
124: case Type.ATTRIBUTE:
125: try {
126: CopyOf.copyAttribute(source, getSchemaType(),
127: validation, this , c2, false);
128: } catch (NoOpenStartTagException err) {
129: err.setXPathContext(context);
130: throw dynamicError(this , err, c2);
131: }
132: break;
133:
134: case Type.TEXT:
135: out.characters(source.getStringValueCS(), locationId, 0);
136: break;
137:
138: case Type.PROCESSING_INSTRUCTION:
139: out.processingInstruction(source.getDisplayName(), source
140: .getStringValueCS(), locationId, 0);
141: break;
142:
143: case Type.COMMENT:
144: out.comment(source.getStringValueCS(), locationId, 0);
145: break;
146:
147: case Type.NAMESPACE:
148: try {
149: source.copy(out, NodeInfo.NO_NAMESPACES, false,
150: locationId);
151: } catch (NoOpenStartTagException err) {
152: DynamicError e = new DynamicError(err.getMessage());
153: e.setXPathContext(context);
154: e.setErrorCode(err.getErrorCodeLocalPart());
155: throw dynamicError(this , e, context);
156: }
157: break;
158:
159: case Type.DOCUMENT:
160: Receiver val = controller.getConfiguration()
161: .getDocumentValidator(out, source.getBaseURI(),
162: controller.getNamePool(), validation,
163: Whitespace.NONE, getSchemaType());
164: if (val != out) {
165: SequenceReceiver sr = new TreeReceiver(val);
166: sr.setPipelineConfiguration(out
167: .getPipelineConfiguration());
168: c2.setReceiver(sr);
169: val = sr;
170: }
171: val.startDocument(0);
172: content.process(c2);
173: val.endDocument();
174: break;
175:
176: default:
177: throw new IllegalArgumentException("Unknown node kind "
178: + source.getNodeKind());
179:
180: }
181: return null;
182: }
183:
184: /**
185: * Evaluate as an expression. We rely on the fact that when these instructions
186: * are generated by XQuery, there will always be a valueExpression to evaluate
187: * the content
188: */
189:
190: public Item evaluateItem(XPathContext context)
191: throws XPathException {
192: Controller controller = context.getController();
193: XPathContext c2 = context.newMinorContext();
194: c2.setOrigin(this );
195: SequenceOutputter seq = new SequenceOutputter(1);
196: seq.setPipelineConfiguration(controller
197: .makePipelineConfiguration());
198: c2.setTemporaryReceiver(seq);
199: process(c2);
200: seq.close();
201: return seq.getFirstItem();
202: }
203:
204: /**
205: * Diagnostic print of expression structure. The expression is written to the System.err
206: * output stream
207: *
208: * @param level indentation level for this expression
209: * @param out
210: */
211:
212: public void display(int level, NamePool pool, PrintStream out) {
213: out.println(ExpressionTool.indent(level) + "copy");
214: }
215:
216: }
217:
218: //
219: // The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
220: // you may not use this file except in compliance with the License. You may obtain a copy of the
221: // License at http://www.mozilla.org/MPL/
222: //
223: // Software distributed under the License is distributed on an "AS IS" basis,
224: // WITHOUT WARRANTY OF ANY KIND, either express or implied.
225: // See the License for the specific language governing rights and limitations under the License.
226: //
227: // The Original Code is: all this file.
228: //
229: // The Initial Developer of the Original Code is Michael H. Kay.
230: //
231: // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
232: //
233: // Contributor(s): none.
234: //
|