KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > instruct > CopyOf


1 package net.sf.saxon.instruct;
2
3 import net.sf.saxon.Controller;
4 import net.sf.saxon.pattern.NodeKindTest;
5 import net.sf.saxon.pattern.ContentTypeTest;
6 import net.sf.saxon.event.*;
7 import net.sf.saxon.expr.*;
8 import net.sf.saxon.om.*;
9 import net.sf.saxon.style.StandardNames;
10 import net.sf.saxon.trans.DynamicError;
11 import net.sf.saxon.trans.XPathException;
12 import net.sf.saxon.type.*;
13 import net.sf.saxon.value.AtomicValue;
14 import net.sf.saxon.value.Value;
15
16 import java.io.PrintStream JavaDoc;
17 import java.util.Iterator JavaDoc;
18
19
20 /**
21  * An xsl:copy-of element in the stylesheet.
22  */

23
24 public class CopyOf extends Instruction implements MappingFunction {
25
26     private Expression select;
27     private boolean copyNamespaces;
28     private int validation;
29     private SchemaType schemaType;
30     private boolean requireDocumentOrElement = false;
31     private boolean rejectDuplicateAttributes;
32     private boolean readOnce = false;
33
34     public CopyOf(Expression select,
35                   boolean copyNamespaces,
36                   int validation,
37                   SchemaType schemaType, boolean rejectDuplicatAttributes) {
38         this.select = select;
39         this.copyNamespaces = copyNamespaces;
40         this.validation = validation;
41         this.schemaType = schemaType;
42         this.rejectDuplicateAttributes = rejectDuplicatAttributes;
43         adoptChildExpression(select);
44     }
45
46     public void setReadOnce(boolean b) {
47         readOnce = b;
48     }
49
50     /**
51      * Determine whether this instruction creates new nodes.
52      * This implementation returns true.
53      */

54
55     public final boolean createsNewNodes() {
56         return !Type.isSubType(select.getItemType(), Type.ANY_ATOMIC_TYPE);
57     }
58
59     /**
60      * Get the name of this instruction, for diagnostics and tracing
61      */

62
63     public int getInstructionNameCode() {
64         return StandardNames.XSL_COPY_OF;
65     }
66
67     /**
68      * For XQuery, the operand (select) must be a single element or document node.
69      * @param requireDocumentOrElement
70      */

71     public void setRequireDocumentOrElement(boolean requireDocumentOrElement) {
72         this.requireDocumentOrElement = requireDocumentOrElement;
73     }
74
75     /**
76      * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
77      * This method indicates which of these methods is provided. This implementation provides both iterate() and
78      * process() methods natively.
79      */

80
81     public int getImplementationMethod() {
82         return ITERATE_METHOD | PROCESS_METHOD;
83     }
84
85     /**
86      * Process this xsl:copy-of instruction
87      * @param context the dynamic context for the transformation
88      * @return null - this implementation of the method never returns a TailCall
89      */

90
91     public TailCall processLeavingTail(XPathContext context) throws XPathException {
92
93         Controller controller = context.getController();
94         SequenceReceiver out = context.getReceiver();
95
96         int whichNamespaces = (copyNamespaces ? NodeInfo.ALL_NAMESPACES : NodeInfo.NO_NAMESPACES);
97
98         SequenceIterator iter = select.iterate(context);
99         while (true) {
100
101
102             Item item = iter.next();
103             if (item == null) {
104                 break;
105             }
106             if (item instanceof NodeInfo) {
107                 NodeInfo source = (NodeInfo) item;
108                 int kind = source.getNodeKind();
109                 if (requireDocumentOrElement &&
110                         !(kind == Type.ELEMENT || kind == Type.DOCUMENT)) {
111                     DynamicError e = new DynamicError(
112                             "Operand of validate expression must be a document or element node"
113                     );
114                     e.setXPathContext(context);
115                     e.setErrorCode("XQTY0030");
116                     throw e;
117                 }
118                 switch (kind) {
119
120                     case Type.ELEMENT:
121
122                         Receiver eval = controller.getConfiguration().getElementValidator(
123                                 out, source.getNameCode(), locationId,
124                                 schemaType, validation,
125                                 controller.getNamePool()
126                         );
127                         source.copy(eval, whichNamespaces, true, locationId);
128                         break;
129
130                     case Type.ATTRIBUTE:
131                         try {
132                             copyAttribute(source, schemaType, validation, this, context, rejectDuplicateAttributes);
133                         } catch (NoOpenStartTagException err) {
134                             DynamicError e = new DynamicError(err.getMessage());
135                             e.setLocator(this);
136                             e.setXPathContext(context);
137                             e.setErrorCode(err.getErrorCodeLocalPart());
138                             throw dynamicError(this, e, context);
139                         }
140                         break;
141                     case Type.TEXT:
142                         out.characters(source.getStringValueCS(), locationId, 0);
143                         break;
144
145                     case Type.PROCESSING_INSTRUCTION:
146                         out.processingInstruction(source.getDisplayName(), source.getStringValueCS(), locationId, 0);
147                         break;
148
149                     case Type.COMMENT:
150                         out.comment(source.getStringValueCS(), locationId, 0);
151                         break;
152
153                     case Type.NAMESPACE:
154                         try {
155                             source.copy(out, NodeInfo.NO_NAMESPACES, false, locationId);
156                         } catch (NoOpenStartTagException err) {
157                             DynamicError e = new DynamicError(err.getMessage());
158                             e.setXPathContext(context);
159                             e.setErrorCode(err.getErrorCodeLocalPart());
160                             //context.getController().recoverableError(e);
161
throw dynamicError(this, e, context);
162                         }
163                         break;
164
165                     case Type.DOCUMENT:
166                         Receiver val = controller.getConfiguration().
167                                 getDocumentValidator(out,
168                                         source.getBaseURI(),
169                                         controller.getNamePool(),
170                                         validation, schemaType);
171                         val.setPipelineConfiguration(out.getPipelineConfiguration());
172                         //val.startDocument(0);
173
source.copy(val, whichNamespaces, true, locationId);
174                         //val.endDocument();
175
break;
176
177                     default:
178                         throw new IllegalArgumentException JavaDoc("Unknown node kind " + source.getNodeKind());
179                 }
180
181             } else {
182                 out.append(item, locationId, NodeInfo.ALL_NAMESPACES);
183             }
184         }
185         return null;
186     }
187
188     protected static void copyAttribute(NodeInfo source,
189                                         SchemaType schemaType,
190                                         int validation,
191                                         Instruction instruction,
192                                         XPathContext context,
193                                         boolean rejectDuplicates)
194             throws XPathException {
195         int nameCode = source.getNameCode();
196         int annotation = -1;
197         int opt = 0;
198         if (rejectDuplicates) {
199             opt |= ReceiverOptions.REJECT_DUPLICATES;
200         }
201         CharSequence JavaDoc value = source.getStringValueCS();
202         if (schemaType != null) {
203             if (schemaType.isSimpleType()) {
204                 if (((SimpleType)schemaType).isNamespaceSensitive()) {
205                     DynamicError err = new DynamicError("Cannot create a parentless attribute whose " +
206                             "type is namespace-sensitive (such as xs:QName)");
207                     err.setErrorCode( "XTTE1545");
208                     err.setXPathContext(context);
209                     err.setLocator(instruction);
210                     throw err;
211                 }
212                 try {
213                     XPathException err = ((SimpleType) schemaType).validateContent(
214                             value, DummyNamespaceResolver.getInstance(), context);
215                     if (err != null) {
216                         throw new ValidationException("Attribute being copied does not match the required type. " +
217                             err.getMessage());
218                     }
219                     annotation = schemaType.getFingerprint();
220                 } catch (UnresolvedReferenceException ure) {
221                     throw new ValidationException(ure);
222                 }
223             } else {
224                 DynamicError e = new DynamicError("Cannot validate an attribute against a complex type");
225                 e.setXPathContext(context);
226                 e.setErrorCode("XTSE1530");
227                 throw e;
228             }
229         } else if (validation == Validation.STRICT ||
230                 validation == Validation.LAX) {
231             try {
232                 annotation = context.getController().getConfiguration().validateAttribute(
233                         nameCode, value, validation);
234             } catch (ValidationException e) {
235                 DynamicError err = DynamicError.makeDynamicError(e);
236                 err.setErrorCode(e.getErrorCodeLocalPart());
237                 err.setXPathContext(context);
238                 err.setLocator(instruction);
239                 err.setIsTypeError(true);
240                 throw err;
241             }
242
243         } else if (validation == Validation.PRESERVE) {
244             annotation = source.getTypeAnnotation();
245         }
246
247         context.getReceiver().attribute(nameCode, annotation, value, instruction.getLocationId(), opt);
248     }
249
250     public Expression simplify(StaticContext env) throws XPathException {
251         select = select.simplify(env);
252         return this;
253     }
254
255     public ItemType getItemType() {
256         if (schemaType != null) {
257             ItemType in = select.getItemType();
258             int e = Type.relationship(in, NodeKindTest.ELEMENT);
259             if (e == Type.SAME_TYPE || e == Type.SUBSUMED_BY) {
260                 return new ContentTypeTest(Type.ELEMENT, schemaType, getExecutable().getConfiguration());
261             }
262             int a = Type.relationship(in, NodeKindTest.ATTRIBUTE);
263             if (a == Type.SAME_TYPE || a == Type.SUBSUMED_BY) {
264                 return new ContentTypeTest(Type.ATTRIBUTE, schemaType, getExecutable().getConfiguration());
265             }
266         }
267         return select.getItemType();
268     }
269
270     public int getCardinality() {
271         return select.getCardinality();
272     }
273
274     public int getDependencies() {
275         return select.getDependencies();
276     }
277
278     protected void promoteInst(PromotionOffer offer) throws XPathException {
279         select = doPromotion(select, offer);
280     }
281
282     public Expression typeCheck(StaticContext env, ItemType contextItemType) throws XPathException {
283         select = select.typeCheck(env, contextItemType);
284         adoptChildExpression(select);
285         return this;
286     }
287
288     public Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) throws XPathException {
289         select = select.optimize(opt, env, contextItemType);
290         adoptChildExpression(select);
291         if (readOnce) {
292             Expression optcopy = opt.optimizeCopy(select);
293             if (optcopy != null) {
294                 return optcopy;
295             }
296         }
297         return this;
298     }
299
300     /**
301      * Diagnostic print of expression structure. The expression is written to the System.err
302      * output stream
303      *
304      * @param level indentation level for this expression
305      * @param out
306      */

307
308     public void display(int level, NamePool pool, PrintStream JavaDoc out) {
309         out.println(ExpressionTool.indent(level) + "copyOf " +
310                 ("validation=" + Validation.toString(validation)));
311         select.display(level + 1, pool, out);
312     }
313
314     public Iterator JavaDoc iterateSubExpressions() {
315         return new MonoIterator(select);
316     }
317
318     /**
319      * Return the first item if there is one, or null if not
320      * @param context
321      * @return the result of evaluating the instruction
322      * @throws XPathException
323      */

324
325     public Item evaluateItem(XPathContext context) throws XPathException {
326         return super.evaluateItem(context);
327     }
328
329     public SequenceIterator iterate(XPathContext context) throws XPathException {
330         if (validation==Validation.PRESERVE && schemaType==null && copyNamespaces) {
331             // create a virtual copy of the underlying nodes
332
return new MappingIterator(select.iterate(context), this, context);
333         }
334         Controller controller = context.getController();
335         XPathContext c2 = context.newMinorContext();
336         c2.setOrigin(this);
337         SequenceOutputter out = new SequenceOutputter();
338         out.setPipelineConfiguration(controller.makePipelineConfiguration());
339         c2.setReceiver(out);
340         try {
341             process(c2);
342             return Value.getIterator(out.getSequence());
343         } catch (XPathException err) {
344             if (err instanceof ValidationException) {
345                 ((ValidationException) err).setSourceLocator(this);
346                 ((ValidationException) err).setSystemId(getSystemId());
347             }
348             if (err.getLocator() == null) {
349                 err.setLocator(this);
350             }
351             throw err;
352         }
353     }
354
355     /**
356      * Mapping function used to perform the copy when using the iterate() method
357      */

358
359     /**
360      * Map one item to a sequence.
361      *
362      * @param item The item to be mapped.
363      * If context is supplied, this must be the same as context.currentItem().
364      * @param context The processing context. This is supplied only for mapping constructs that
365      * set the context node, position, and size. Otherwise it is null.
366      * @return either (a) a SequenceIterator over the sequence of items that the supplied input
367      * item maps to, or (b) an Item if it maps to a single item, or (c) null if it maps to an empty
368      * sequence.
369      */

370
371     public Object JavaDoc map(Item item, XPathContext context) throws XPathException {
372         if (item instanceof AtomicValue) {
373             return item;
374         }
375         VirtualCopy vc = VirtualCopy.makeVirtualCopy((NodeInfo)item, (NodeInfo)item);
376         int documentNumber =
377                 context.getController().getConfiguration().getDocumentNumberAllocator().allocateDocumentNumber();
378         vc.setDocumentNumber(documentNumber);
379         return vc;
380     }
381
382 }
383
384 //
385
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
386
// you may not use this file except in compliance with the License. You may obtain a copy of the
387
// License at http://www.mozilla.org/MPL/
388
//
389
// Software distributed under the License is distributed on an "AS IS" basis,
390
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
391
// See the License for the specific language governing rights and limitations under the License.
392
//
393
// The Original Code is: all this file.
394
//
395
// The Initial Developer of the Original Code is Michael H. Kay.
396
//
397
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
398
//
399
// Contributor(s): none.
400
//
401
Popular Tags