KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > om > VirtualCopy


1 package net.sf.saxon.om;
2
3 import net.sf.saxon.Configuration;
4 import net.sf.saxon.value.Value;
5 import net.sf.saxon.event.Receiver;
6 import net.sf.saxon.pattern.AnyNodeTest;
7 import net.sf.saxon.pattern.NodeTest;
8 import net.sf.saxon.trans.XPathException;
9
10 /**
11  * This class represents a node that is a virtual copy of another node: that is, it behaves as a node that's the
12  * same as another node, but has different identity. It is implemented by means of a reference to the node of which
13  * it is a copy, but methods that are sensitive to node identity return a different result.
14  */

15
16 public class VirtualCopy implements NodeInfo {
17
18     protected String JavaDoc baseURI;
19     protected int documentNumber;
20     protected NodeInfo original;
21     protected VirtualCopy parent;
22     protected NodeInfo root; // the node forming the root of the subtree that was copied
23

24     protected VirtualCopy(NodeInfo base) {
25         this.original = base;
26     }
27
28     public static VirtualCopy makeVirtualCopy(NodeInfo original, NodeInfo root) {
29
30         VirtualCopy vc;
31         // Don't allow copies of copies of copies: define the new copy in terms of the original
32
while (original instanceof VirtualCopy) {
33             original = ((VirtualCopy)original).original;
34         }
35         while (root instanceof VirtualCopy) {
36             root = ((VirtualCopy)root).original;
37         }
38         if (original instanceof DocumentInfo) {
39             vc = new VirtualDocumentCopy((DocumentInfo)original);
40         } else {
41             vc = new VirtualCopy(original);
42         }
43         vc.root = root;
44         return vc;
45     }
46
47     public void setDocumentNumber(int documentNumber) {
48         this.documentNumber = documentNumber;
49     }
50
51     /**
52      * Get the kind of node. This will be a value such as Type.ELEMENT or Type.ATTRIBUTE
53      *
54      * @return an integer identifying the kind of node. These integer values are the
55      * same as those used in the DOM
56      * @see net.sf.saxon.type.Type
57      */

58
59     public int getNodeKind() {
60         return original.getNodeKind();
61     }
62
63     /**
64      * Determine whether this is the same node as another node.
65      * Note: a.isSameNodeInfo(b) if and only if generateId(a)==generateId(b).
66      * This method has the same semantics as isSameNode() in DOM Level 3, but
67      * works on Saxon NodeInfo objects rather than DOM Node objects.
68      *
69      * @param other the node to be compared with this node
70      * @return true if this NodeInfo object and the supplied NodeInfo object represent
71      * the same node in the tree.
72      */

73
74     public boolean isSameNodeInfo(NodeInfo other) {
75         return other instanceof VirtualCopy &&
76                 documentNumber == other.getDocumentNumber() &&
77                 original.isSameNodeInfo(((VirtualCopy)other).original);
78
79
80     }
81
82     /**
83      * Get the System ID for the node.
84      *
85      * @return the System Identifier of the entity in the source document
86      * containing the node, or null if not known. Note this is not the
87      * same as the base URI: the base URI can be modified by xml:base, but
88      * the system ID cannot.
89      */

90
91     public String JavaDoc getSystemId() {
92         return baseURI;
93     }
94
95     /**
96      * Get the Base URI for the node, that is, the URI used for resolving a relative URI contained
97      * in the node. This will be the same as the System ID unless xml:base has been used.
98      *
99      * @return the base URI of the node
100      */

101
102     public String JavaDoc getBaseURI() {
103         return baseURI;
104     }
105
106     /**
107      * Get line number
108      *
109      * @return the line number of the node in its original source document; or
110      * -1 if not available
111      */

112
113     public int getLineNumber() {
114         return original.getLineNumber();
115     }
116
117     /**
118      * Determine the relative position of this node and another node, in document order.
119      * The other node will always be in the same document.
120      *
121      * @param other The other node, whose position is to be compared with this
122      * node
123      * @return -1 if this node precedes the other node, +1 if it follows the
124      * other node, or 0 if they are the same node. (In this case,
125      * isSameNode() will always return true, and the two nodes will
126      * produce the same result for generateId())
127      */

128
129     public int compareOrder(NodeInfo other) {
130         return original.compareOrder(((VirtualCopy)other).original);
131     }
132
133     /**
134      * Return the string value of the node. The interpretation of this depends on the type
135      * of node. For an element it is the accumulated character content of the element,
136      * including descendant elements.
137      *
138      * @return the string value of the node
139      */

140
141     public String JavaDoc getStringValue() {
142         return original.getStringValue();
143     }
144
145     /**
146      * Get the value of the item as a CharSequence. This is in some cases more efficient than
147      * the version of the method that returns a String.
148      */

149
150     public CharSequence JavaDoc getStringValueCS() {
151         return original.getStringValueCS();
152     }
153
154     /**
155      * Get name code. The name code is a coded form of the node name: two nodes
156      * with the same name code have the same namespace URI, the same local name,
157      * and the same prefix. By masking the name code with &0xfffff, you get a
158      * fingerprint: two nodes with the same fingerprint have the same local name
159      * and namespace URI.
160      *
161      * @return an integer name code, which may be used to obtain the actual node
162      * name from the name pool
163      * @see NamePool#allocate allocate
164      * @see NamePool#getFingerprint getFingerprint
165      */

166
167     public int getNameCode() {
168         return original.getNameCode();
169     }
170
171     /**
172      * Get fingerprint. The fingerprint is a coded form of the expanded name
173      * of the node: two nodes
174      * with the same name code have the same namespace URI and the same local name.
175      * A fingerprint of -1 should be returned for a node with no name.
176      *
177      * @return an integer fingerprint; two nodes with the same fingerprint have
178      * the same expanded QName
179      */

180
181     public int getFingerprint() {
182         return original.getFingerprint();
183     }
184
185     /**
186      * Get the local part of the name of this node. This is the name after the ":" if any.
187      *
188      * @return the local part of the name. For an unnamed node, returns "". Unlike the DOM
189      * interface, this returns the full name in the case of a non-namespaced name.
190      */

191
192     public String JavaDoc getLocalPart() {
193         return original.getLocalPart();
194     }
195
196     /**
197      * Get the URI part of the name of this node. This is the URI corresponding to the
198      * prefix, or the URI of the default namespace if appropriate.
199      *
200      * @return The URI of the namespace of this node. For an unnamed node,
201      * or for a node with an empty prefix, return an empty
202      * string.
203      */

204
205     public String JavaDoc getURI() {
206         return original.getURI();
207     }
208
209     /**
210      * Get the prefix of the name of the node. This is defined only for elements and attributes.
211      * If the node has no prefix, or for other kinds of node, return a zero-length string.
212      *
213      * @return The prefix of the name of the node.
214      */

215
216     public String JavaDoc getPrefix() {
217         return original.getPrefix();
218     }
219
220     /**
221      * Get the display name of this node. For elements and attributes this is [prefix:]localname.
222      * For unnamed nodes, it is an empty string.
223      *
224      * @return The display name of this node. For a node with no name, return
225      * an empty string.
226      */

227
228     public String JavaDoc getDisplayName() {
229         return original.getDisplayName();
230     }
231
232     /**
233      * Get the configuration
234      */

235
236     public Configuration getConfiguration() {
237         return original.getConfiguration();
238     }
239
240     /**
241      * Get the NamePool that holds the namecode for this node
242      *
243      * @return the namepool
244      */

245
246     public NamePool getNamePool() {
247         return original.getNamePool();
248     }
249
250     /**
251      * Get the type annotation of this node, if any.
252      * Returns -1 for kinds of nodes that have no annotation, and for elements annotated as
253      * untyped, and attributes annotated as untypedAtomic.
254      *
255      * @return the type annotation of the node.
256      * @see net.sf.saxon.type.Type
257      */

258
259     public int getTypeAnnotation() {
260         return original.getTypeAnnotation();
261     }
262
263     /**
264      * Get the NodeInfo object representing the parent of this node
265      *
266      * @return the parent of this node; null if this node has no parent
267      */

268
269     public NodeInfo getParent() {
270         if (original.isSameNodeInfo(root)) {
271             return null;
272         }
273         if (parent == null) {
274             NodeInfo basep = original.getParent();
275             if (basep == null) {
276                 return null;
277             }
278             parent = new VirtualCopy(basep);
279             parent.setDocumentNumber(documentNumber);
280         }
281         return parent;
282     }
283
284     /**
285      * Return an iteration over all the nodes reached by the given axis from this node
286      *
287      * @param axisNumber an integer identifying the axis; one of the constants
288      * defined in class net.sf.saxon.om.Axis
289      * @return an AxisIterator that scans the nodes reached by the axis in
290      * turn.
291      * @throws UnsupportedOperationException if the namespace axis is
292      * requested and this axis is not supported for this implementation.
293      * @see Axis
294      */

295
296     public AxisIterator iterateAxis(byte axisNumber) {
297         return iterateAxis(axisNumber, AnyNodeTest.getInstance());
298     }
299
300     /**
301      * Return an iteration over all the nodes reached by the given axis from this node
302      * that match a given NodeTest
303      *
304      * @param axisNumber an integer identifying the axis; one of the constants
305      * defined in class net.sf.saxon.om.Axis
306      * @param nodeTest A pattern to be matched by the returned nodes; nodes
307      * that do not match this pattern are not included in the result
308      * @return a NodeEnumeration that scans the nodes reached by the axis in
309      * turn.
310      * @throws UnsupportedOperationException if the namespace axis is
311      * requested and this axis is not supported for this implementation.
312      * @see Axis
313      */

314
315     public AxisIterator iterateAxis(byte axisNumber, NodeTest nodeTest) {
316         VirtualCopy newParent = null;
317         if (axisNumber == Axis.CHILD || axisNumber == Axis.ATTRIBUTE || axisNumber == Axis.NAMESPACE) {
318             newParent = this;
319         } else if (axisNumber == Axis.SELF || axisNumber == Axis.PRECEDING_SIBLING || axisNumber == Axis.FOLLOWING_SIBLING) {
320             newParent = parent;
321         }
322         NodeInfo root;
323         if (Axis.isSubtreeAxis[axisNumber]) {
324             root = null;
325         } else {
326             root = this.root;
327         }
328         return new VirtualCopier(original.iterateAxis(axisNumber, nodeTest), newParent, root);
329     }
330
331     /**
332      * Get the value of a given attribute of this node
333      *
334      * @param fingerprint The fingerprint of the attribute name
335      * @return the attribute value if it exists or null if not
336      */

337
338     public String JavaDoc getAttributeValue(int fingerprint) {
339         return original.getAttributeValue(fingerprint);
340     }
341
342     /**
343      * Get the root node of the tree containing this node
344      *
345      * @return the NodeInfo representing the top-level ancestor of this node.
346      * This will not necessarily be a document node
347      */

348
349     public NodeInfo getRoot() {
350         NodeInfo n = this;
351         while (true) {
352             NodeInfo p = n.getParent();
353             if (p == null) {
354                 return n;
355             }
356             n = p;
357         }
358     }
359
360     /**
361      * Get the root node, if it is a document node.
362      *
363      * @return the DocumentInfo representing the containing document. If this
364      * node is part of a tree that does not have a document node as its
365      * root, return null.
366      */

367
368     public DocumentInfo getDocumentRoot() {
369         NodeInfo root = getRoot();
370         if (root instanceof DocumentInfo) {
371             return (DocumentInfo)root;
372         }
373         return null;
374     }
375
376     /**
377      * Determine whether the node has any children. <br />
378      * Note: the result is equivalent to <br />
379      * getEnumeration(Axis.CHILD, AnyNodeTest.getInstance()).hasNext()
380      *
381      * @return True if the node has one or more children
382      */

383
384     public boolean hasChildNodes() {
385         return original.hasChildNodes();
386     }
387
388     /**
389      * Get a character string that uniquely identifies this node.
390      * Note: a.isSameNode(b) if and only if generateId(a)==generateId(b)
391      *
392      * @return a string that uniquely identifies this node, across all
393      * documents. (Changed in Saxon 7.5. Previously this method returned
394      * an id that was unique within the current document, and the calling
395      * code prepended a document id).
396      */

397
398     public String JavaDoc generateId() {
399         return "d" + documentNumber + original.generateId();
400     }
401
402     /**
403      * Get the document number of the document containing this node. For a free-standing
404      * orphan node, just return the hashcode.
405      */

406
407     public int getDocumentNumber() {
408         return documentNumber;
409     }
410
411     /**
412      * Copy this node to a given outputter
413      *
414      * @param out the Receiver to which the node should be copied
415      * @param whichNamespaces in the case of an element, controls
416      * which namespace nodes should be copied. Values are NO_NAMESPACES,
417      * LOCAL_NAMESPACES, ALL_NAMESPACES
418      * @param copyAnnotations indicates whether the type annotations
419      * of element and attribute nodes should be copied
420      * @param locationId Identifies the location of the instruction
421      * that requested this copy. Pass zero if no other information is available
422      * @throws net.sf.saxon.trans.XPathException
423      *
424      */

425
426     public void copy(Receiver out, int whichNamespaces, boolean copyAnnotations, int locationId) throws XPathException {
427         original.copy(out, whichNamespaces, copyAnnotations, locationId);
428     }
429
430     /**
431      * Output all namespace nodes associated with this element. Does nothing if
432      * the node is not an element.
433      *
434      * @param out The relevant outputter
435      * @param includeAncestors True if namespaces declared on ancestor
436      */

437
438     public void sendNamespaceDeclarations(Receiver out, boolean includeAncestors) throws XPathException {
439         original.sendNamespaceDeclarations(out, includeAncestors);
440     }
441
442     /**
443      * Get all namespace undeclarations and undeclarations defined on this element.
444      *
445      * @param buffer If this is non-null, and the result array fits in this buffer, then the result
446      * may overwrite the contents of this array, to avoid the cost of allocating a new array on the heap.
447      * @return An array of integers representing the namespace declarations and undeclarations present on
448      * this element. For a node other than an element, return null. Otherwise, the returned array is a
449      * sequence of namespace codes, whose meaning may be interpreted by reference to the name pool. The
450      * top half word of each namespace code represents the prefix, the bottom half represents the URI.
451      * If the bottom half is zero, then this is a namespace undeclaration rather than a declaration.
452      * The XML namespace is never included in the list. If the supplied array is larger than required,
453      * then the first unused entry will be set to -1.
454      * <p/>
455      * <p>For a node other than an element, the method returns null.</p>
456      */

457
458     public int[] getDeclaredNamespaces(int[] buffer) {
459         return original.getDeclaredNamespaces(buffer);
460     }
461
462     /**
463      * Set the system identifier for this Source.
464      * <p/>
465      * <p>The system identifier is optional if the source does not
466      * get its data from a URL, but it may still be useful to provide one.
467      * The application can use a system identifier, for example, to resolve
468      * relative URIs and to include in error messages and warnings.</p>
469      *
470      * @param systemId The system identifier as a URL string.
471      */

472     public void setSystemId(String JavaDoc systemId) {
473         baseURI = systemId;
474     }
475
476     /**
477      * Get the typed value of the item
478      *
479      * @return the typed value of the item. In general this will be a sequence
480      * @throws net.sf.saxon.trans.XPathException
481      * where no typed value is available, e.g. for
482      * an element with complex content
483      */

484
485     public SequenceIterator getTypedValue() throws XPathException {
486         return original.getTypedValue();
487     }
488
489     /**
490      * Get the typed value. The result of this method will always be consistent with the method
491      * {@link Item#getTypedValue()}. However, this method is often more convenient and may be
492      * more efficient, especially in the common case where the value is expected to be a singleton.
493      *
494      * @return the typed value. If requireSingleton is set to true, the result will always be an
495      * AtomicValue. In other cases it may be a Value representing a sequence whose items are atomic
496      * values.
497      * @since 8.5
498      */

499
500     public Value atomize() throws XPathException {
501         return original.atomize();
502     }
503
504     /**
505      * VirtualCopier implements the XPath axes as applied to a VirtualCopy node. It works by
506      * applying the requested axis to the node of which this is a copy. There are two
507      * complications: firstly, all nodes encountered must themselves be (virtually) copied
508      * to give them a new identity. Secondly, axes that stray outside the subtree rooted at
509      * the original copied node must be truncated.
510      */

511
512     private class VirtualCopier implements AxisIterator, AtomizableIterator {
513
514         private AxisIterator base;
515         private VirtualCopy parent;
516         private NodeInfo subtreeRoot;
517         private Item current;
518
519         public VirtualCopier(AxisIterator base, VirtualCopy parent, NodeInfo subtreeRoot) {
520             this.base = base;
521             this.parent = parent;
522             this.subtreeRoot = subtreeRoot;
523         }
524
525         /**
526          * Indicate that any nodes returned in the sequence will be atomized. This
527          * means that if it wishes to do so, the implementation can return the typed
528          * values of the nodes rather than the nodes themselves. The implementation
529          * is free to ignore this hint.
530          *
531          * @param atomizing true if the caller of this iterator will atomize any
532          * nodes that are returned, and is therefore willing to accept the typed
533          * value of the nodes instead of the nodes themselves.
534          */

535
536         public void setIsAtomizing(boolean atomizing) {
537             if (base instanceof AtomizableIterator) {
538                 ((AtomizableIterator)base).setIsAtomizing(atomizing);
539             }
540         }
541
542         /**
543          * Get the next item in the sequence. <BR>
544          *
545          * @return the next Item. If there are no more nodes, return null.
546          */

547
548         public Item next() {
549             Item next = base.next();
550
551             if (next instanceof NodeInfo) {
552                 if (subtreeRoot != null) {
553                     // we're only interested in nodes within the subtree that was copied.
554
// Assert: once we find a node outside this subtree, all further nodes will also be outside
555
// the subtree.
556
if (!isAncestorOrSelf(subtreeRoot, ((NodeInfo)next))) {
557                         return null;
558                     }
559                 }
560                 VirtualCopy vc = VirtualCopy.makeVirtualCopy(((NodeInfo)next), root);
561                 vc.parent = parent;
562                 vc.baseURI = baseURI;
563                 vc.documentNumber = documentNumber;
564                 next = vc;
565             }
566             current = next;
567             return next;
568         }
569
570         /**
571          * Get the current item in the sequence.
572          *
573          * @return the current item, that is, the item most recently returned by
574          * next()
575          */

576
577         public Item current() {
578             return current;
579         }
580
581         /**
582          * Get the current position
583          *
584          * @return the position of the current item (the item most recently
585          * returned by next()), starting at 1 for the first node
586          */

587
588         public int position() {
589             return base.position();
590         }
591
592         /**
593          * Get another iterator over the same sequence of items, positioned at the
594          * start of the sequence
595          *
596          * @return a new iterator over the same sequence
597          */

598
599         public SequenceIterator getAnother() {
600             return new VirtualCopier((AxisIterator)base.getAnother(), parent, subtreeRoot);
601         }
602
603         /**
604          * Get properties of this iterator, as a bit-significant integer.
605          *
606          * @return the properties of this iterator. This will be some combination of
607          * properties such as {@link GROUNDED}, {@link LAST_POSITION_FINDER},
608          * and {@link LOOKAHEAD}. It is always
609          * acceptable to return the value zero, indicating that there are no known special properties.
610          * It is acceptable for the properties of the iterator to change depending on its state.
611          */

612
613         public int getProperties() {
614             return 0;
615         }
616
617         /**
618          * Test whether a node is an ancestor-or-self of another
619          */

620
621         private boolean isAncestorOrSelf(NodeInfo a, NodeInfo d) {
622             while (true) {
623                 if (a.isSameNodeInfo(d)) {
624                     return true;
625                 }
626                 d = d.getParent();
627                 if (d == null) {
628                     return false;
629                 }
630             }
631         }
632
633     }
634
635 }
636
637
638 //
639
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
640
// you may not use this file except in compliance with the License. You may obtain a copy of the
641
// License at http://www.mozilla.org/MPL/
642
//
643
// Software distributed under the License is distributed on an "AS IS" basis,
644
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
645
// See the License for the specific language governing rights and limitations under the License.
646
//
647
// The Original Code is: all this file.
648
//
649
// The Initial Developer of the Original Code is Michael H. Kay.
650
//
651
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
652
//
653
// Contributor(s): none.
654
//
655
Popular Tags