KickJava   Java API By Example, From Geeks To Geeks.

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


1 package net.sf.saxon.instruct;
2 import net.sf.saxon.Controller;
3 import net.sf.saxon.style.StandardNames;
4 import net.sf.saxon.event.*;
5 import net.sf.saxon.expr.Expression;
6 import net.sf.saxon.expr.StaticProperty;
7 import net.sf.saxon.expr.XPathContext;
8 import net.sf.saxon.om.Item;
9 import net.sf.saxon.om.NodeInfo;
10 import net.sf.saxon.om.Validation;
11 import net.sf.saxon.pattern.NodeKindTest;
12 import net.sf.saxon.pull.UnconstructedElement;
13 import net.sf.saxon.trans.DynamicError;
14 import net.sf.saxon.trans.XPathException;
15 import net.sf.saxon.type.ItemType;
16 import net.sf.saxon.type.ValidationException;
17
18
19 /**
20  * An instruction that creates an element node. There are two subtypes, FixedElement
21  * for use where the name is known statically, and Element where it is computed
22  * dynamically. To allow use in both XSLT and XQuery, the class acts both as an
23  * Instruction and as an Expression.
24 */

25
26 public abstract class ElementCreator extends ParentNodeConstructor {
27
28     /**
29      * The inheritNamespaces flag indicates that the namespace nodes on the element created by this instruction
30      * are to be inherited (copied) on the children of this element. That is, if this flag is false, the child
31      * elements must carry a namespace undeclaration for all the namespaces on the parent, unless they are
32      * redeclared in some way.
33      */

34
35     protected boolean inheritNamespaces = true;
36
37     public ElementCreator() { }
38
39     /**
40      * Get the item type of the value returned by this instruction
41      * @return the item type
42      */

43
44     public ItemType getItemType() {
45         return NodeKindTest.ELEMENT;
46     }
47
48     /**
49      * Get the static properties of this expression (other than its type). The result is
50      * bit-signficant. These properties are used for optimizations. In general, if
51      * property bit is set, it is true, but if it is unset, the value is unknown.
52      *
53      * @return a set of flags indicating static properties of this expression
54      */

55
56     public int computeSpecialProperties() {
57         return super.computeSpecialProperties() |
58                 StaticProperty.SINGLE_DOCUMENT_NODESET;
59     }
60
61     /**
62      * Set the validation mode for the new element
63      */

64
65     public void setValidationMode(int mode) {
66         validation = mode;
67     }
68
69     /**
70      * Get the validation mode for the constructed element
71      */

72
73     public int getValidationMode() {
74         return validation;
75     }
76
77     public abstract int getNameCode(XPathContext context)
78     throws XPathException;
79
80     /**
81      * Callback to output namespace nodes for the new element.
82      * @param context The execution context
83      * @param receiver the Receiver where the namespace nodes are to be written
84      * @throws net.sf.saxon.trans.XPathException
85      */

86
87     protected abstract void outputNamespaceNodes(XPathContext context, Receiver receiver)
88     throws XPathException;
89
90     /**
91      * Callback to get a list of the intrinsic namespaces that need to be generated for the element.
92      * The result is an array of namespace codes, the codes either occupy the whole array or are
93      * terminated by a -1 entry. A result of null is equivalent to a zero-length array.
94      */

95
96     public int[] getActiveNamespaces() throws XPathException {
97         return null;
98     }
99
100     /**
101      * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
102      * This method indicates which of these methods is prefered. For instructions this is the process() method.
103      */

104
105     public int getImplementationMethod() {
106         return Expression.PROCESS_METHOD | Expression.EVALUATE_METHOD;
107     }
108
109     /**
110      * Evaluate the instruction to produce a new element node. This method is typically used when there is
111      * a parent element or document in a result tree, to which the new element is added.
112      * @param context
113      * @return null (this instruction never returns a tail call)
114      * @throws XPathException
115      */

116     public TailCall processLeavingTail(XPathContext context)
117     throws XPathException {
118
119         try {
120
121             int nameCode = getNameCode(context);
122             int typeCode = (validation == Validation.PRESERVE ? StandardNames.XS_ANY_TYPE : StandardNames.XDT_UNTYPED);
123
124             Controller controller = context.getController();
125             XPathContext c2 = context;
126             SequenceReceiver out = context.getReceiver();
127
128             Receiver validator = controller.getConfiguration().getElementValidator(
129                     out, nameCode, locationId,
130                     getSchemaType(), validation,
131                     controller.getNamePool()
132             );
133
134             if (validator != out) {
135                 c2 = context.newMinorContext();
136                 c2.setOrigin(this);
137                 out = new TreeReceiver(validator);
138                 out.setPipelineConfiguration(controller.makePipelineConfiguration());
139                 c2.setReceiver(out);
140             }
141             int properties = (inheritNamespaces ? 0 : ReceiverOptions.DISINHERIT_NAMESPACES);
142             out.startElement(nameCode, typeCode, locationId, properties);
143
144             // output the required namespace nodes via a callback
145

146             outputNamespaceNodes(c2, out);
147
148             // process subordinate instructions to generate attributes and content
149
content.process(c2);
150
151             // output the element end tag (which will fail if validation fails)
152
out.endElement();
153             return null;
154
155         } catch (DynamicError e) {
156             if (e.getXPathContext() == null) {
157                 e.setXPathContext(context);
158             }
159             if (e.getLocator()==null) {
160                 e.setLocator(this);
161             }
162             throw e;
163         }
164     }
165
166    /**
167      * Evaluate the constructor, returning the constructed element node. If lazy construction
168      * mode is in effect, then an UnconstructedParent object is returned instead.
169      */

170
171     public Item evaluateItem(XPathContext context) throws XPathException {
172        //
173
if (isLazyConstruction()) {
174            UnconstructedElement e = new UnconstructedElement(this, context);
175            // The name code is evaluated eagerly. It's usually already known, and it's usually needed.
176
// Evaluating it now removes problems with error handling.
177
e.setNameCode(getNameCode(context));
178            return e;
179        } else {
180            return constructElement(context);
181        }
182     }
183
184     /**
185      * Construct the element node as a free-standing (parentless) node in a tiny tree
186      * @param context
187      * @return the constructed element node
188      * @throws XPathException
189      */

190     private NodeInfo constructElement(XPathContext context) throws XPathException {
191         try {
192             Controller controller = context.getController();
193             XPathContext c2 = context.newMinorContext();
194             c2.setOrigin(this);
195             SequenceReceiver old = c2.getReceiver();
196             SequenceOutputter seq;
197             if (old instanceof SequenceWriter && !((SequenceWriter)old).hasOpenNodes()) {
198                 // Reuse the current SequenceOutputter if possible. This enables the construction of
199
// a single TinyTree to hold a sequence of parentless elements (a forest).
200
seq = (SequenceOutputter)old;
201             } else {
202                 seq = new SequenceOutputter(1);
203             }
204             seq.setPipelineConfiguration(controller.makePipelineConfiguration());
205
206             int nameCode = getNameCode(c2);
207             int typeCode = (validation == Validation.PRESERVE ? StandardNames.XS_ANY_TYPE : StandardNames.XDT_UNTYPED);
208
209             Receiver validator = controller.getConfiguration().getElementValidator(
210                     seq, nameCode, locationId,
211                     getSchemaType(), validation,
212                     controller.getNamePool()
213             );
214
215             SequenceReceiver ini = seq;
216             if (validator == seq) {
217                 c2.setTemporaryReceiver(seq);
218             } else {
219                 TreeReceiver tr = new TreeReceiver(validator);
220                 tr.setPipelineConfiguration(seq.getPipelineConfiguration());
221                 c2.setReceiver(tr);
222                 ini = tr;
223             }
224
225
226             ini.open();
227             int properties = (inheritNamespaces ? 0 : ReceiverOptions.DISINHERIT_NAMESPACES);
228             ini.startElement(nameCode, typeCode, locationId, properties);
229
230             // output the namespace nodes for the new element
231
outputNamespaceNodes(c2, ini);
232
233             content.process(c2);
234
235             ini.endElement();
236             ini.close();
237
238             // the constructed element is the first and only item in the sequence
239
return (NodeInfo)seq.popLastItem();
240
241         } catch (XPathException err) {
242             if (err instanceof ValidationException) {
243                 ((ValidationException)err).setSourceLocator(this);
244                 ((ValidationException)err).setSystemId(getSystemId());
245             }
246             if (err.getLocator() == null) {
247                 err.setLocator(this);
248             }
249             if (err instanceof DynamicError && ((DynamicError)err).getXPathContext() == null) {
250                 ((DynamicError)err).setXPathContext(context);
251             }
252             throw err;
253         }
254     }
255 }
256
257 //
258
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
259
// you may not use this file except in compliance with the License. You may obtain a copy of the
260
// License at http://www.mozilla.org/MPL/
261
//
262
// Software distributed under the License is distributed on an "AS IS" basis,
263
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
264
// See the License for the specific language governing rights and limitations under the License.
265
//
266
// The Original Code is: all this file.
267
//
268
// The Initial Developer of the Original Code is Michael H. Kay.
269
//
270
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
271
//
272
// Contributor(s): none.
273
//
274
Popular Tags