KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > pull > UnconstructedParent


1 package net.sf.saxon.pull;
2
3 import net.sf.saxon.Configuration;
4 import net.sf.saxon.value.Value;
5 import net.sf.saxon.event.PipelineConfiguration;
6 import net.sf.saxon.event.Receiver;
7 import net.sf.saxon.event.SequenceOutputter;
8 import net.sf.saxon.expr.StackFrame;
9 import net.sf.saxon.expr.StaticProperty;
10 import net.sf.saxon.expr.XPathContext;
11 import net.sf.saxon.expr.XPathContextMajor;
12 import net.sf.saxon.instruct.ParentNodeConstructor;
13 import net.sf.saxon.om.*;
14 import net.sf.saxon.pattern.NodeTest;
15 import net.sf.saxon.tinytree.TinyBuilder;
16 import net.sf.saxon.trace.Location;
17 import net.sf.saxon.trans.XPathException;
18 import net.sf.saxon.trans.UncheckedXPathException;
19
20 /**
21   * This class represents a virtual element node, the result of an element constructor that
22   * (in general) hasn't been fully evaluated. This is similar to a Closure, except that it is
23   * a NodeInfo rather than a Value. The object is capable of materializing the element if it
24   * is actually needed, but the aim is to avoid materializing the element wherever possible,
25   * at any rate not until its parent element is constructed so that this element can be built
26   * in-situ rather than being built as a standalone element and then later copied.
27  *
28  * This class is not currently used for elements that require schema validation.
29  */

30 public abstract class UnconstructedParent implements NodeInfo {
31
32     private ParentNodeConstructor instruction;
33     private XPathContextMajor savedXPathContext;
34     NodeInfo node = null;
35
36     public UnconstructedParent(ParentNodeConstructor instruction, XPathContext context) {
37         this.instruction = instruction;
38         savedXPathContext = context.newContext();
39         savedXPathContext.setOriginatingConstructType(Location.LAZY_EVALUATION);
40
41         // Make a copy of all local variables. If the value of any local variable is a closure
42
// whose depth exceeds a certain threshold, we evaluate the closure eagerly to avoid
43
// creating deeply nested lists of Closures, which consume memory unnecessarily
44

45         // We only copy the local variables if the expression has dependencies on local variables.
46
// It would be even smarter to copy only those variables that we need; but that gives
47
// diminishing returns.
48

49         if ((instruction.getDependencies() & StaticProperty.DEPENDS_ON_LOCAL_VARIABLES) != 0) {
50             StackFrame localStackFrame = context.getStackFrame();
51             ValueRepresentation[] local = localStackFrame.getStackFrameValues();
52             if (local != null) {
53                 ValueRepresentation[] savedStackFrame = new ValueRepresentation[local.length];
54                 System.arraycopy(local, 0, savedStackFrame, 0, local.length);
55                 savedXPathContext.setStackFrame(localStackFrame.getStackFrameMap(), savedStackFrame);
56             }
57         }
58
59         // Make a copy of the context item
60
SequenceIterator currentIterator = context.getCurrentIterator();
61         if (currentIterator != null) {
62             Item contextItem = currentIterator.current();
63             AxisIterator single = SingletonIterator.makeIterator(contextItem);
64             single.next();
65             savedXPathContext.setCurrentIterator(single);
66             // we don't save position() and last() because we have no way
67
// of restoring them. Instead, we prevent lazy construction if there is a dependency
68
// on position() or last()
69
}
70         savedXPathContext.setReceiver(new SequenceOutputter());
71     }
72
73     public XPathContext getXPathContext() {
74         return savedXPathContext;
75     }
76
77     public ParentNodeConstructor getInstruction() {
78         return instruction;
79     }
80
81     public PullProvider getPuller() {
82         if (node == null) {
83             VirtualTreeWalker walker = new VirtualTreeWalker(instruction, savedXPathContext);
84             walker.setPipelineConfiguration(savedXPathContext.getController().makePipelineConfiguration());
85             walker.setNameCode(getNameCode());
86             return walker;
87         } else {
88             return TreeWalker.makeTreeWalker(node);
89         }
90     }
91
92     /**
93      * Method to construct the node when this is required.
94      *
95      * @throws XPathException if any failure occurs
96      */

97     void construct() throws XPathException {
98         PipelineConfiguration pipe = savedXPathContext.getController().makePipelineConfiguration();
99         PullProvider puller = getPuller();
100         puller.setPipelineConfiguration(pipe);
101         TinyBuilder builder = new TinyBuilder();
102         builder.setPipelineConfiguration(pipe);
103
104
105         builder.open();
106         new PullPushCopier(puller, builder).copy();
107         builder.close();
108
109         node = builder.getCurrentRoot();
110     }
111
112     /**
113      * Method to construct the node when this is required.
114      * <p>
115      * Note that this may throw an UncheckedXPathException. This is because many of the methods on the
116      * NodeInfo class are exception-free; we can't throw an XPathException on these interfaces, but may need
117      * to in this case because lazy computation of expressions may throw errors.
118      *
119      * @throws UncheckedXPathException
120      */

121
122     void tryToConstruct() {
123         try {
124             construct();
125         } catch (XPathException err) {
126             throw new UncheckedXPathException(err);
127         }
128     }
129
130     /**
131      * Determine whether this is the same node as another node.
132      * Note: a.isSameNodeInfo(b) if and only if generateId(a)==generateId(b).
133      * This method has the same semantics as isSameNode() in DOM Level 3, but
134      * works on Saxon NodeInfo objects rather than DOM Node objects.
135      *
136      * @param other the node to be compared with this node
137      * @return true if this NodeInfo object and the supplied NodeInfo object represent
138      * the same node in the tree.
139      */

140
141     public boolean isSameNodeInfo(NodeInfo other) {
142         if (this == other) {
143             return true;
144         }
145         if (other instanceof UnconstructedParent) {
146             return false;
147         }
148         if (node != null) {
149             return node.isSameNodeInfo(other);
150         }
151         return false;
152     }
153
154     /**
155      * Get the System ID for the node.
156      *
157      * @return the System Identifier of the entity in the source document
158      * containing the node, or null if not known. Note this is not the
159      * same as the base URI: the base URI can be modified by xml:base, but
160      * the system ID cannot.
161      */

162
163     public String JavaDoc getSystemId() {
164         if (node == null) {
165             tryToConstruct();
166         }
167         return node.getSystemId();
168     }
169
170     /**
171      * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained
172      * in the node. This will be the same as the System ID unless xml:base has been used.
173      *
174      * @return the base URI of the node
175      */

176
177     public String JavaDoc getBaseURI() {
178         if (node == null) {
179             tryToConstruct();
180         }
181         return node.getBaseURI();
182     }
183
184     /**
185      * Get line number
186      *
187      * @return the line number of the node in its original source document; or
188      * -1 if not available
189      */

190
191     public int getLineNumber() {
192         return -1;
193     }
194
195     /**
196      * Determine the relative position of this node and another node, in document order.
197      * The other node will always be in the same document.
198      *
199      * @param other The other node, whose position is to be compared with this
200      * node
201      * @return -1 if this node precedes the other node, +1 if it follows the
202      * other node, or 0 if they are the same node. (In this case,
203      * isSameNode() will always return true, and the two nodes will
204      * produce the same result for generateId())
205      */

206
207     public int compareOrder(NodeInfo other) {
208         if (node == null) {
209             tryToConstruct();
210         }
211         return node.compareOrder(other);
212     }
213
214     /**
215      * Return the string value of the node. The interpretation of this depends on the type
216      * of node. For an element it is the accumulated character content of the element,
217      * including descendant elements.
218      *
219      * @return the string value of the node
220      */

221
222     public String JavaDoc getStringValue() {
223         return getStringValueCS().toString();
224     }
225
226     /**
227      * Get fingerprint. The fingerprint is a coded form of the expanded name
228      * of the node: two nodes
229      * with the same name code have the same namespace URI and the same local name.
230      * A fingerprint of -1 should be returned for a node with no name.
231      *
232      * @return an integer fingerprint; two nodes with the same fingerprint have
233      * the same expanded QName
234      */

235
236     public int getFingerprint() {
237         int nc = getNameCode();
238         if (nc == -1) {
239             return -1;
240         }
241         return nc & NamePool.FP_MASK;
242     }
243
244     /**
245      * Get the local part of the name of this node. This is the name after the ":" if any.
246      *
247      * @return the local part of the name. For an unnamed node, returns "". Unlike the DOM
248      * interface, this returns the full name in the case of a non-namespaced name.
249      */

250
251     public String JavaDoc getLocalPart() {
252         return getNamePool().getLocalName(getNameCode());
253     }
254
255     /**
256      * Get the URI part of the name of this node. This is the URI corresponding to the
257      * prefix, or the URI of the default namespace if appropriate.
258      *
259      * @return The URI of the namespace of this node. For an unnamed node,
260      * or for a node with an empty prefix, return an empty
261      * string.
262      */

263
264     public String JavaDoc getURI() {
265         return getNamePool().getURI(getNameCode());
266     }
267
268     /**
269      * Get the display name of this node. For elements and attributes this is [prefix:]localname.
270      * For unnamed nodes, it is an empty string.
271      *
272      * @return The display name of this node. For a node with no name, return
273      * an empty string.
274      */

275
276     public String JavaDoc getDisplayName() {
277         return getNamePool().getDisplayName(getNameCode());
278     }
279
280     /**
281      * Get the prefix of the name of the node. This is defined only for elements and attributes.
282      * If the node has no prefix, or for other kinds of node, return a zero-length string.
283      *
284      * @return The prefix of the name of the node.
285      */

286
287     public String JavaDoc getPrefix() {
288         return getNamePool().getPrefix(getNameCode());
289     }
290
291     /**
292      * Get the configuration
293      */

294
295     public Configuration getConfiguration() {
296         return savedXPathContext.getController().getConfiguration();
297     }
298
299     /**
300      * Get the NamePool that holds the namecode for this node
301      *
302      * @return the namepool
303      */

304
305     public NamePool getNamePool() {
306         return getConfiguration().getNamePool();
307     }
308
309     /**
310      * Get the type annotation of this node, if any.
311      * Returns -1 for kinds of nodes that have no annotation, and for elements annotated as
312      * untyped, and attributes annotated as untypedAtomic.
313      *
314      * @return the type annotation of the node.
315      * @see net.sf.saxon.type.Type
316      */

317
318     public int getTypeAnnotation() {
319         return -1;
320     }
321
322     /**
323      * Get the NodeInfo object representing the parent of this node
324      *
325      * @return the parent of this node; null if this node has no parent
326      */

327
328     public NodeInfo getParent() {
329         return null;
330     }
331
332     /**
333      * Return an iteration over all the nodes reached by the given axis from this node
334      *
335      * @param axisNumber an integer identifying the axis; one of the constants
336      * defined in class net.sf.saxon.om.Axis
337      * @return an AxisIterator that scans the nodes reached by the axis in
338      * turn.
339      * @throws UnsupportedOperationException if the namespace axis is
340      * requested and this axis is not supported for this implementation.
341      * @see net.sf.saxon.om.Axis
342      */

343
344     public AxisIterator iterateAxis(byte axisNumber) {
345         if (node == null) {
346             tryToConstruct();
347         }
348         return node.iterateAxis(axisNumber);
349     }
350
351     /**
352      * Return an iteration over all the nodes reached by the given axis from this node
353      * that match a given NodeTest
354      *
355      * @param axisNumber an integer identifying the axis; one of the constants
356      * defined in class net.sf.saxon.om.Axis
357      * @param nodeTest A pattern to be matched by the returned nodes; nodes
358      * that do not match this pattern are not included in the result
359      * @return a NodeEnumeration that scans the nodes reached by the axis in
360      * turn.
361      * @throws UnsupportedOperationException if the namespace axis is
362      * requested and this axis is not supported for this implementation.
363      * @see net.sf.saxon.om.Axis
364      */

365
366     public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
367         if (node == null) {
368             tryToConstruct();
369         }
370         return node.iterateAxis(axisNumber, nodeTest);
371     }
372
373     /**
374      * Get the value of a given attribute of this node
375      *
376      * @param fingerprint The fingerprint of the attribute name
377      * @return the attribute value if it exists or null if not
378      */

379
380     public String JavaDoc getAttributeValue(int fingerprint) {
381         if (node == null) {
382             tryToConstruct();
383         }
384         return node.getAttributeValue(fingerprint);
385     }
386
387     /**
388      * Get the root node of the tree containing this node
389      *
390      * @return the NodeInfo representing the top-level ancestor of this node.
391      * This will not necessarily be a document node
392      */

393
394     public NodeInfo getRoot() {
395         return this;
396     }
397
398     /**
399      * Get the root node, if it is a document node.
400      *
401      * @return the DocumentInfo representing the containing document. If this
402      * node is part of a tree that does not have a document node as its
403      * root, return null.
404      */

405
406     public DocumentInfo getDocumentRoot() {
407         return null;
408     }
409
410     /**
411      * Determine whether the node has any children. <br />
412      * Note: the result is equivalent to <br />
413      * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext()
414      *
415      * @return True if the node has one or more children
416      */

417
418     public boolean hasChildNodes() {
419         if (node == null) {
420             tryToConstruct();
421         }
422         return node.hasChildNodes();
423     }
424
425     /**
426      * Get a character string that uniquely identifies this node.
427      * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
428      *
429      * @return a string that uniquely identifies this node, across all
430      * documents. (Changed in Saxon 7.5. Previously this method returned
431      * an id that was unique within the current document, and the calling
432      * code prepended a document id).
433      */

434
435     public String JavaDoc generateId() {
436         if (node == null) {
437             tryToConstruct();
438         }
439         return node.generateId();
440     }
441
442     /**
443      * Get the document number of the document containing this node. For a free-standing
444      * orphan node, just return the hashcode.
445      */

446
447     public int getDocumentNumber() {
448         if (node == null) {
449             tryToConstruct();
450         }
451         return node.getDocumentNumber();
452     }
453
454     /**
455      * Copy this node to a given outputter
456      *
457      * @param out the Receiver to which the node should be copied
458      * @param whichNamespaces in the case of an element, controls
459      * which namespace nodes should be copied. Values are {@link #NO_NAMESPACES},
460      * {@link #LOCAL_NAMESPACES}, {@link #ALL_NAMESPACES}
461      * @param copyAnnotations indicates whether the type annotations
462      * of element and attribute nodes should be copied
463      * @param locationId If non-zero, identifies the location of the instruction
464      * that requested this copy. If zero, indicates that the location information
465      * for the original node is to be copied; in this case the Receiver must be
466      * a LocationCopier
467      * @throws net.sf.saxon.trans.XPathException
468      *
469      */

470
471     public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException {
472         if (node == null) {
473             if (whichNamespaces == NodeInfo.ALL_NAMESPACES && copyAnnotations) {
474                 PullProvider pull = new VirtualTreeWalker(instruction, savedXPathContext);
475                 PullPushCopier copier = new PullPushCopier(pull, out);
476                 copier.copy();
477                 return;
478             } else {
479                 construct();
480             }
481         }
482         node.copy(out, whichNamespaces, copyAnnotations, locationId);
483     }
484
485     /**
486      * Output all namespace declarations associated with this element. Does nothing if
487      * the node is not an element.
488      *
489      * @param out The relevant Receiver
490      * @param includeAncestors True if namespaces declared on ancestor
491      * elements must be output; false if it is known that these are
492      */

493
494     public void sendNamespaceDeclarations(Receiver out, boolean includeAncestors) throws XPathException {
495         if (node == null) {
496             try {
497                 construct();
498             } catch (UncheckedXPathException e) {
499                 throw e.getXPathException();
500             }
501         }
502         node.sendNamespaceDeclarations(out, includeAncestors);
503     }
504
505     /**
506      * Get all namespace undeclarations and undeclarations defined on this element.
507      *
508      * @param buffer If this is non-null, and the result array fits in this buffer, then the result
509      * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
510      * @return An array of integers representing the namespace declarations and undeclarations present on
511      * this element. For a node other than an element, return null. Otherwise, the returned array is a
512      * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
513      * top half word of each namespace code represents the prefix, the bottom half represents the URI.
514      * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
515      * The XML namespace is never included in the list. If the supplied array is larger than required,
516      * then the first unused entry will be set to -1.
517      * <p/>
518      * <p>For a node other than an element, the method returns null.</p>
519      */

520
521     public int[] getDeclaredNamespaces(int[] buffer) {
522         if (node == null) {
523             tryToConstruct();
524         }
525         return node.getDeclaredNamespaces(buffer);
526     }
527
528     /**
529      * Set the system identifier for this Source.
530      * <p/>
531      * <p>The system identifier is optional if the source does not
532      * get its data from a URL, but it may still be useful to provide one.
533      * The application can use a system identifier, for example, to resolve
534      * relative URIs and to include in error messages and warnings.</p>
535      *
536      * @param systemId The system identifier as a URL string.
537      */

538     public void setSystemId(String JavaDoc systemId) {
539         //
540
}
541
542     /**
543      * Get the value of the item as a CharSequence. This is in some cases more efficient than
544      * the version of the method that returns a String.
545      */

546
547     public CharSequence JavaDoc getStringValueCS() {
548         if (node == null) {
549             //construct();
550
try {
551                 PullProvider puller = getPuller();
552                 puller.next(); // assert: it's a START_DOCUMENT or START_ELEMENT
553
return puller.getStringValue();
554             } catch (XPathException e) {
555                 throw new UncheckedXPathException(e);
556             }
557         }
558         return node.getStringValueCS();
559     }
560
561     /**
562      * Get the typed value of the item
563      *
564      * @return the typed value of the item. In general this will be a sequence
565      * @throws net.sf.saxon.trans.XPathException
566      * where no typed value is available, e.g. for
567      * an element with complex content
568      */

569
570     public SequenceIterator getTypedValue() throws XPathException {
571         if (node == null) {
572             construct();
573         }
574         return node.getTypedValue();
575     }
576
577     /**
578      * Get the typed value. The result of this method will always be consistent with the method
579      * {@link net.sf.saxon.om.Item#getTypedValue()}. However, this method is often more convenient and may be
580      * more efficient, especially in the common case where the value is expected to be a singleton.
581      *
582      * @return the typed value. If requireSingleton is set to true, the result will always be an
583      * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic
584      * values.
585      * @since 8.5
586      */

587
588     public Value atomize() throws XPathException {
589         if (node == null) {
590             construct();
591         }
592         return node.atomize();
593     }
594
595
596 }
597
598
599 //
600
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
601
// you may not use this file except in compliance with the License. You may obtain a copy of the
602
// License at http://www.mozilla.org/MPL/
603
//
604
// Software distributed under the License is distributed on an "AS IS" basis,
605
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
606
// See the License for the specific language governing rights and limitations under the License.
607
//
608
// The Original Code is: all this file.
609
//
610
// The Initial Developer of the Original Code is Michael H. Kay.
611
//
612
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
613
//
614
// Contributor(s): none.
615
//
616
Popular Tags