KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > expr > NodeSetExtent


1 package com.icl.saxon.expr;
2 import com.icl.saxon.Context;
3 import com.icl.saxon.om.NodeInfo;
4 import com.icl.saxon.om.NodeEnumeration;
5 import com.icl.saxon.om.AxisEnumeration;
6 import com.icl.saxon.sort.QuickSort;
7 import com.icl.saxon.sort.Sortable;
8 import com.icl.saxon.sort.NodeOrderComparer;
9 import java.util.Vector;
10 import org.w3c.dom.NodeList;
11 import org.w3c.dom.Node;
12
13 /**
14 * A node-set value implemented extensionally. This class also implements the
15 * DOM NodeList interface - though this will only work if the nodes themselves
16 * implement the DOM Node interface (which is true of the two Saxon tree models,
17 * but not necessarily of all possible implementations).
18 */

19
20 public final class NodeSetExtent extends NodeSetValue
21                            implements Sortable, org.w3c.dom.NodeList {
22     private NodeInfo[] value;
23     private int length;
24     private boolean sorted; // true only if values are known to be in document order
25
private boolean reverseSorted; // true if known to be in reverse document order
26
private NodeOrderComparer comparer; // Comparer used for sorting nodes.
27

28     /**
29     * Construct an empty node set
30     */

31
32     public NodeSetExtent(NodeOrderComparer comparer) {
33         this.comparer = comparer;
34         this.value = new NodeInfo[0];
35         length = 0;
36         sorted = true;
37         reverseSorted = true;
38     }
39
40     /**
41     * Construct a node-set given the set of nodes as an array
42     * @param nodes An array whose elements must be NodeInfo objects
43     * @param comparer Comparer used for sorting into document order
44     */

45
46     public NodeSetExtent(NodeInfo[] nodes, NodeOrderComparer comparer) {
47         this.value = nodes;
48         this.length = nodes.length;
49         sorted = length<2;
50         reverseSorted = length<2;
51         this.comparer = comparer;
52     }
53
54
55     /**
56     * Construct a node-set given the set of nodes as a Vector
57     * @param nodes a Vector whose elements must be NodeInfo objects
58     * @param comparer Comparer used for sorting into document order
59     */

60
61     public NodeSetExtent(Vector nodes, NodeOrderComparer comparer) {
62         value = new NodeInfo[nodes.size()];
63         for (int i=0; i<nodes.size(); i++) {
64             value[i] = (NodeInfo)nodes.elementAt(i);
65         }
66         length = nodes.size();
67         sorted = length<2;
68         reverseSorted = length<2;
69         this.comparer = comparer;
70     }
71
72     /**
73     * Construct a node-set containing all the nodes in a NodeEnumeration.
74     * @param enum The supplied node enumeration. This must be positioned at the start,
75     * so that hasMoreElements() returns true if there are any nodes in the node-set,
76     * and nextElement() returns the first node.
77     * @param comparer Comparer used for sorting into document order
78     */

79
80     public NodeSetExtent(NodeEnumeration enum, NodeOrderComparer comparer) throws XPathException {
81         this.comparer = comparer;
82         int size = 20;
83         //if (enum instanceof LastPositionFinder) {
84
// size = ((LastPositionFinder)enum).getLastPosition();
85
//} else {
86
// size = 20;
87
//}
88
// above commented out. Although the enumeration may be able to
89
// say how many nodes it contains, it may be an expensive operation,
90
// so we behave as if we don't know.
91
value = new NodeInfo[size];
92         int i = 0;
93         while (enum.hasMoreElements()) {
94             if (i>=size) {
95                 size *= 2;
96                 NodeInfo newarray[] = new NodeInfo[size];
97                 System.arraycopy(value, 0, newarray, 0, i);
98                 value = newarray;
99             }
100             value[i++] = enum.nextElement();
101         }
102         sorted = enum.isSorted() || i<2;
103         reverseSorted = enum.isReverseSorted() || i<2;
104         length = i;
105     }
106
107     /**
108     * Append a node to the node-set. This is used only when building indexes.
109     * The node-set must be sorted; the new node must follow the others in document
110     * order. The new node is not added if it is the same as the last node currently
111     * in the node-set.
112     */

113
114     public void append(NodeInfo node) {
115         reverseSorted = false;
116         if (value.length < length + 1) {
117             NodeInfo[] newval = new NodeInfo[(length==0 ? 10 : length * 2)];
118             System.arraycopy(value, 0, newval, 0, length);
119             value = newval;
120         }
121         if (length>0 && value[length-1].isSameNode(node)) {
122             return;
123         } else {
124             value[length++] = node;
125         }
126     }
127     
128     /**
129     * Simplify the expression
130     */

131
132     public Expression simplify() {
133         if (length==0) {
134             return new EmptyNodeSet();
135         } else if (length==1) {
136             return new SingletonNodeSet(value[0]);
137         } else {
138             return this;
139         }
140     }
141
142
143     /**
144     * Set a flag to indicate whether the nodes are sorted. Used when the creator of the
145     * node-set knows that they are already in document order.
146     * @param isSorted true if the caller wishes to assert that the nodes are in document order
147     * and do not need to be further sorted
148     */

149
150     public void setSorted(boolean isSorted) {
151         sorted = isSorted;
152     }
153
154     /**
155     * Test whether the value is known to be sorted
156     * @return true if the value is known to be sorted in document order, false if it is not
157     * known whether it is sorted.
158     */

159
160     public boolean isSorted() {
161         return sorted;
162     }
163     
164     /**
165     * Convert to string value
166     * @return the value of the first node in the node-set if there
167     * is one, otherwise an empty string
168     */

169
170     public String asString() {
171         return (length>0 ? getFirst().getStringValue() : "");
172     }
173
174     /**
175     * Evaluate as a boolean.
176     * @return true if the node set is not empty
177     */

178
179     public boolean asBoolean() throws XPathException {
180         return (length>0);
181     }
182     
183     /**
184     * Count the nodes in the node-set. Note this will sort the node set if necessary, to
185     * make sure there are no duplicates.
186     */

187
188     public int getCount() {
189         sort();
190         return length;
191     }
192
193     /**
194     * Sort the nodes into document order.
195     * This does nothing if the nodes are already known to be sorted; to force a sort,
196     * call setSorted(false)
197     * @return the same NodeSetValue, after sorting. (The reason for returning this is that
198     * it makes life easier for the XSL compiler).
199     */

200
201     public NodeSetValue sort() {
202         if (length<2) sorted=true;
203         if (sorted) return this;
204
205         if (reverseSorted) {
206             
207             NodeInfo[] array = new NodeInfo[length];
208             for (int n=0; n<length; n++) {
209                 array[n] = value[length-n-1];
210             }
211             value = array;
212             sorted = true;
213             reverseSorted = false;
214             
215         } else {
216             // sort the array
217

218             QuickSort.sort(this, 0, length-1);
219
220             // need to eliminate duplicate nodes. Note that we cannot compare the node
221
// objects directly, because with attributes and namespaces there might be
222
// two objects representing the same node.
223

224             int j=1;
225             for(int i=1; i<length; i++) {
226                 if (!value[i].isSameNode(value[i-1])) {
227                     value[j++] = value[i];
228                 }
229             }
230             length = j;
231
232             sorted = true;
233             reverseSorted = false;
234         }
235         return this;
236     }
237
238     /**
239     * Get the first node in the nodeset (in document order)
240     * @return the first node, or null if the nodeset is empty
241     */

242
243     public NodeInfo getFirst() {
244         if (length==0) return null;
245         if (sorted) return value[0];
246         
247         // scan to find the first in document order
248
NodeInfo first = value[0];
249         for(int i=1; i<length; i++) {
250             if (comparer.compare(value[i], first) < 0) {
251                 first = value[i];
252             }
253         }
254         return first;
255     }
256
257     /**
258     * Return the first node in the nodeset (in document order)
259     * @param context The context for the evaluation: not used
260     * @return the NodeInfo of the first node in document order, or null if the node-set
261     * is empty.
262     */

263
264     public NodeInfo selectFirst(Context context) {
265         return getFirst();
266     }
267
268     /**
269     * Return an enumeration of this nodeset value.
270     */

271
272     public NodeEnumeration enumerate() {
273         return new NodeSetValueEnumeration();
274     }
275
276     // implement DOM NodeList
277

278     /**
279     * return the number of nodes in the list (DOM method)
280     */

281
282     public int getLength() {
283         return getCount();
284     }
285
286     /**
287     * Return the n'th item in the list (DOM method)
288     */

289
290     public Node item(int index) {
291         sort();
292         if (length>index && (value[index] instanceof Node)) {
293             return (Node)(value[index]);
294         } else {
295             return null;
296         }
297     }
298
299     /**
300     * Compare two nodes in document sequence
301     * (needed to implement the Sortable interface)
302     */

303     
304     public int compare(int a, int b) {
305         return comparer.compare(value[a], value[b]);
306     }
307
308     /**
309     * Swap two nodes (needed to implement the Sortable interface)
310     */

311     
312     public void swap(int a, int b) {
313         NodeInfo temp = value[a];
314         value[a] = value[b];
315         value[b] = temp;
316     }
317
318     /**
319     * Inner class NodeSetValueEnumeration
320     */

321
322     private class NodeSetValueEnumeration implements AxisEnumeration, LastPositionFinder {
323
324         int index=0;
325
326         public NodeSetValueEnumeration() {
327             index = 0;
328             //System.err.println("NSV enumeration: " + length);
329
}
330
331         public boolean hasMoreElements() {
332             //System.err.println("NSV hasMoreElements?: " + index + " of " + length);
333
return index<length;
334         }
335
336         public NodeInfo nextElement() {
337             //System.err.println("NSV enumeration: " + index + " of " + length);
338
return value[index++];
339         }
340
341         public boolean isSorted() {
342             return sorted;
343         }
344
345         public boolean isReverseSorted() {
346             return reverseSorted;
347         }
348
349         public boolean isPeer() {
350             return false;
351         }
352
353         public int getLastPosition() {
354             return length;
355         }
356     }
357
358 }
359
360 //
361
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
362
// you may not use this file except in compliance with the License. You may obtain a copy of the
363
// License at http://www.mozilla.org/MPL/
364
//
365
// Software distributed under the License is distributed on an "AS IS" basis,
366
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
367
// See the License for the specific language governing rights and limitations under the License.
368
//
369
// The Original Code is: all this file.
370
//
371
// The Initial Developer of the Original Code is
372
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
373
//
374
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
375
//
376
// Contributor(s): none.
377
//
378

379
Popular Tags