KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > value > Value


1 package net.sf.saxon.value;
2 import net.sf.saxon.Configuration;
3 import net.sf.saxon.Controller;
4 import net.sf.saxon.event.Builder;
5 import net.sf.saxon.event.PipelineConfiguration;
6 import net.sf.saxon.event.Sender;
7 import net.sf.saxon.event.SequenceReceiver;
8 import net.sf.saxon.expr.*;
9 import net.sf.saxon.functions.Aggregate;
10 import net.sf.saxon.om.*;
11 import net.sf.saxon.style.StandardNames;
12 import net.sf.saxon.tinytree.TinyBuilder;
13 import net.sf.saxon.trans.DynamicError;
14 import net.sf.saxon.trans.XPathException;
15 import net.sf.saxon.type.*;
16
17 import javax.xml.transform.Source JavaDoc;
18 import javax.xml.transform.dom.DOMSource JavaDoc;
19 import java.io.PrintStream JavaDoc;
20 import java.io.Serializable JavaDoc;
21 import java.lang.reflect.Array JavaDoc;
22 import java.lang.reflect.InvocationTargetException JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24 import java.math.BigDecimal JavaDoc;
25 import java.math.BigInteger JavaDoc;
26 import java.net.URI JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.util.*;
29
30 /**
31 * A value is the result of an expression but it is also an expression in its own right.
32 * Note that every value can be regarded as a sequence - in many cases, a sequence of
33 * length one.
34 */

35
36 public abstract class Value implements Expression, Serializable JavaDoc, ValueRepresentation {
37
38     /**
39      * Static method to make a Value from a given Item (which may be either an AtomicValue
40      * or a NodeInfo
41      * @param val The supplied value, or null, indicating the empty sequence.
42      * @return The supplied value, if it is a value, or a SingletonNode that
43      * wraps the item, if it is a node. If the supplied value was null,
44      * return an EmptySequence
45      */

46
47     public static Value asValue(ValueRepresentation val) {
48         if (val instanceof Value) {
49             return (Value)val;
50         } else if (val == null) {
51             return EmptySequence.getInstance();
52         } else {
53             return new SingletonNode((NodeInfo)val);
54         }
55     }
56
57     /**
58      * Static method to make an Item from a Value
59      * @param value the value to be converted
60      * @param context the context. It is probably safe to set this to null.
61      * @return null if the value is an empty sequence; or the only item in the value
62      * if it is a singleton sequence
63      * @throws XPathException if the Value contains multiple items
64      */

65
66     public static Item asItem(ValueRepresentation value, XPathContext context) throws XPathException {
67         if (value instanceof Item) {
68             return (Item)value;
69         } else if (value instanceof EmptySequence) {
70             return null;
71         } else if (value instanceof SingletonNode) {
72             return ((SingletonNode)value).getNode();
73         } else if (value instanceof AtomicValue) {
74             return (AtomicValue)value;
75         } else if (value instanceof Closure) {
76             return ((Closure)value).evaluateItem(context);
77         } else {
78             SequenceIterator iter = Value.getIterator(value);
79             Item item = iter.next();
80             if (item == null) {
81                 return null;
82             } else if (iter.next() != null) {
83                 throw new AssertionError JavaDoc("Attempting to access a sequence as an item");
84             } else {
85                 return item;
86             }
87         }
88     }
89
90     /**
91      * Static method to get an Iterator over any ValueRepresentation (which may be either a Value
92      * or a NodeInfo
93      * @param val The supplied value, or null, indicating the empty sequence.
94      * @param context The evaluation context. This may be null. It should always be possible to
95      * iterate over a value without supplying a context, but sometimes the context
96      * can provide access to better error information
97      * @return The supplied value, if it is a value, or a SingletonNode that
98      * wraps the item, if it is a node. If the supplied value was null,
99      * return an EmptySequence
100      */

101
102     public static SequenceIterator asIterator(ValueRepresentation val, XPathContext context) throws XPathException {
103         if (val instanceof Value) {
104             return ((Value)val).iterate(context);
105         } else if (val == null) {
106             return EmptyIterator.getInstance();
107         } else {
108             return SingletonIterator.makeIterator((NodeInfo)val);
109         }
110     }
111
112
113     /**
114     * Static method to convert strings to numbers. Might as well go here as anywhere else.
115     * @param s the String to be converted
116     * @return a double representing the value of the String
117      * @throws NumberFormatException if the value cannot be converted
118     */

119
120     public static double stringToNumber(CharSequence JavaDoc s) throws NumberFormatException JavaDoc {
121         String JavaDoc n = trimWhitespace(s).toString();
122         if ("INF".equals(n)) {
123             return Double.POSITIVE_INFINITY;
124         } else if ("-INF".equals(n)) {
125             return Double.NEGATIVE_INFINITY;
126         } else if ("NaN".equals(n)) {
127             return Double.NaN;
128         } else {
129             return Double.parseDouble(n);
130         }
131     }
132
133
134     /**
135     * Normalize whitespace as defined in XML Schema
136     */

137
138     public static CharSequence JavaDoc normalizeWhitespace(CharSequence JavaDoc in) {
139         FastStringBuffer sb = new FastStringBuffer(in.length());
140         for (int i=0; i<in.length(); i++) {
141             char c = in.charAt(i);
142             switch (c) {
143                 case '\n':
144                 case '\r':
145                 case '\t':
146                     sb.append(' ');
147                     break;
148                 default:
149                     sb.append(c);
150                     break;
151             }
152         }
153         return sb;
154     }
155
156     /**
157     * Collapse whitespace as defined in XML Schema
158     */

159
160     public static CharSequence JavaDoc collapseWhitespace(CharSequence JavaDoc in) {
161         if (in.length()==0) {
162             return in;
163         }
164
165         FastStringBuffer sb = new FastStringBuffer(in.length());
166         boolean inWhitespace = true;
167         int i = 0;
168         for (; i<in.length(); i++) {
169             char c = in.charAt(i);
170             switch (c) {
171                 case '\n':
172                 case '\r':
173                 case '\t':
174                 case ' ':
175                     if (inWhitespace) {
176                         // remove the whitespace
177
} else {
178                         sb.append(' ');
179                         inWhitespace = true;
180                     }
181                     break;
182                 default:
183                     sb.append(c);
184                     inWhitespace = false;
185                     break;
186             }
187         }
188         if (sb.charAt(sb.length()-1)==' ') {
189             sb.setLength(sb.length()-1);
190         }
191         return sb;
192     }
193
194     /**
195      * Remove leading and trailing whitespace. This has the same effect as collapseWhitespace,
196      * but is cheaper, for use by data types that do not allow internal whitespace.
197      * @param in the input string whose whitespace is to be removed
198      * @return the result of removing excess whitespace
199      */

200     public static CharSequence JavaDoc trimWhitespace(CharSequence JavaDoc in) {
201         if (in.length()==0) {
202             return in;
203         }
204         int first = 0;
205         int last = in.length()-1;
206         while (in.charAt(first) <= 0x20) {
207             if (first++ >= last) {
208                 return "";
209             }
210         }
211         while (in.charAt(last) <= 0x20) {
212             last--;
213         }
214         return in.subSequence(first, last+1);
215     }
216
217     /**
218      * Get a SequenceIterator over a ValueRepresentation
219      */

220
221     public static SequenceIterator getIterator(ValueRepresentation val) throws XPathException {
222         if (val instanceof Value) {
223             return ((Value)val).iterate(null);
224         } else if (val instanceof NodeInfo) {
225             return SingletonIterator.makeIterator((NodeInfo)val);
226         } else if (val == null) {
227             throw new AssertionError JavaDoc("Value of variable is undefined (null)");
228         } else {
229             throw new AssertionError JavaDoc("Unknown value representation " + val.getClass());
230         }
231     }
232
233     /**
234     * Simplify an expression
235     * @return for a Value, this always returns the value unchanged
236     */

237
238     public final Expression simplify(StaticContext env) {
239         return this;
240     }
241
242     /**
243     * TypeCheck an expression
244     * @return for a Value, this always returns the value unchanged
245     */

246
247     public final Expression typeCheck(StaticContext env, ItemType contextItemType) {
248         return this;
249     }
250
251     /**
252     * Optimize an expression
253     * @return for a Value, this always returns the value unchanged
254     */

255
256     public final Expression optimize(Optimizer opt, StaticContext env, ItemType contextItemType) {
257         return this;
258     }
259
260
261     /**
262      * Determine the data type of the items in the expression, if possible
263      * @return AnyItemType (not known)
264      */

265
266     public ItemType getItemType() {
267         return AnyItemType.getInstance();
268     }
269
270     /**
271      * Determine the cardinality
272      */

273
274     public int getCardinality() {
275         try {
276             SequenceIterator iter = iterate(null);
277             Item next = iter.next();
278             if (next == null) {
279                 return StaticProperty.EMPTY;
280             } else {
281                 if (iter.next() != null) {
282                     return StaticProperty.ALLOWS_ONE_OR_MORE;
283                 } else {
284                     return StaticProperty.EXACTLY_ONE;
285                 }
286             }
287         } catch (XPathException err) {
288             // can't actually happen
289
return StaticProperty.ALLOWS_ZERO_OR_MORE;
290         }
291     }
292
293     /**
294      * Get the sub-expressions of this expression.
295      * @return for a Value, this always returns an empty array
296      */

297
298     public final Iterator iterateSubExpressions() {
299         return Collections.EMPTY_LIST.iterator();
300     }
301
302     /**
303      * Get the expression that immediately contains this expression. This method
304      * returns null for an outermost expression; it also return null in the case
305      * of literal values. For an XPath expression occurring within an XSLT stylesheet,
306      * this method returns the XSLT instruction containing the XPath expression.
307      * @return the expression that contains this expression, if known; return null
308      * if there is no containing expression or if the containing expression is unknown.
309      */

310
311     public final Container getParentExpression() {
312         return null;
313     }
314
315     /**
316      * Get the static properties of this expression (other than its type). For a
317      * Value, the only special property is {@link StaticProperty#NON_CREATIVE}.
318      * @return {@link StaticProperty#NON_CREATIVE}
319      */

320
321
322     public int getSpecialProperties() {
323         return StaticProperty.NON_CREATIVE;
324     }
325
326     /**
327      * Offer promotion for this subexpression. Values (constant expressions)
328      * are never promoted
329      * @param offer details of the offer, for example the offer to move
330      * expressions that don't depend on the context to an outer level in
331      * the containing expression
332      * @return For a Value, this always returns the value unchanged
333      */

334
335      public final Expression promote(PromotionOffer offer) {
336         return this;
337     }
338
339     /**
340     * Determine which aspects of the context the expression depends on. The result is
341     * a bitwise-or'ed value composed from constants such as StaticProperty.VARIABLES and
342     * StaticProperty.CURRENT_NODE
343      * @return for a Value, this always returns zero.
344     */

345
346     public final int getDependencies() {
347         return 0;
348     }
349
350     /**
351      * Get the n'th item in the sequence (starting from 0). This is defined for all
352      * Values, but its real benefits come for a sequence Value stored extensionally
353      * (or for a MemoClosure, once all the values have been read)
354      */

355
356     public Item itemAt(int n) throws XPathException {
357         if ((getImplementationMethod() & EVALUATE_METHOD) != 0) {
358             if (n==0) {
359                 Item item = evaluateItem(null);
360                 return (item == null ? null : item);
361             } else {
362                 return null;
363             }
364         }
365         if (n < 0) {
366             return null;
367         }
368         int i = 0; // indexing is zero-based
369
SequenceIterator iter = iterate(null);
370         while (true) {
371             Item item = iter.next();
372             if (item == null) {
373                 return null;
374             }
375             if (i++ == n) {
376                 return item;
377             }
378         }
379     }
380
381     /**
382      * Get the length of the sequence
383      */

384
385     public int getLength() throws XPathException {
386         return Aggregate.count(iterate(null));
387     }
388
389     /**
390      * Evaluate as a singleton item (or empty sequence)
391      */

392
393     public Item evaluateItem(XPathContext context) throws XPathException {
394         return iterate(context).next();
395     }
396
397
398     /**
399       * Process the value as an instruction, without returning any tail calls
400       * @param context The dynamic context, giving access to the current node,
401       * the current variables, etc.
402       */

403
404     public void process(XPathContext context) throws XPathException {
405         SequenceIterator iter = iterate(context);
406         SequenceReceiver out = context.getReceiver();
407         while (true) {
408             Item it = iter.next();
409             if (it==null) break;
410             out.append(it, 0, NodeInfo.ALL_NAMESPACES);
411         }
412     }
413
414
415     /**
416      * Convert the value to a string, using the serialization rules.
417      * For atomic values this is the same as a cast; for sequence values
418      * it gives a space-separated list.
419      * @throws XPathException The method can fail if evaluation of the value
420      * has been deferred, and if a failure occurs during the deferred evaluation.
421      * No failure is possible in the case of an AtomicValue.
422      */

423
424     public String JavaDoc getStringValue() throws XPathException {
425         FastStringBuffer sb = new FastStringBuffer(1024);
426         SequenceIterator iter = iterate(null);
427         Item item = iter.next();
428         if (item != null) {
429             while (true) {
430                 sb.append(item.getStringValueCS());
431                 item = iter.next();
432                 if (item == null) {
433                     break;
434                 }
435                 sb.append(' ');
436             }
437         }
438         return sb.toString();
439     }
440
441     /**
442      * Evaluate an expression as a String. This function must only be called in contexts
443      * where it is known that the expression will return a single string (or where an empty sequence
444      * is to be treated as a zero-length string). Implementations should not attempt to convert
445      * the result to a string, other than converting () to "". This method is used mainly to
446      * evaluate expressions produced by compiling an attribute value template.
447      *
448      * @exception XPathException if any dynamic error occurs evaluating the
449      * expression
450      * @exception ClassCastException if the result type of the
451      * expression is not xs:string?
452      * @param context The context in which the expression is to be evaluated
453      * @return the value of the expression, evaluated in the current context.
454      * The expression must return a string or (); if the value of the
455      * expression is (), this method returns "".
456      */

457
458     public String JavaDoc evaluateAsString(XPathContext context) throws XPathException {
459         AtomicValue value = (AtomicValue) evaluateItem(context);
460         if (value == null) return "";
461         return value.getStringValue();
462     }
463
464
465     /**
466      * Get the effective boolean value of the expression. This returns false if the value
467      * is the empty sequence, a zero-length string, a number equal to zero, or the boolean
468      * false. Otherwise it returns true.
469      *
470      * @param context The context in which the expression is to be evaluated
471      * @exception XPathException if any dynamic error occurs evaluating the
472      * expression
473      * @return the effective boolean value
474      */

475
476     public boolean effectiveBooleanValue(XPathContext context) throws XPathException {
477         return ExpressionTool.effectiveBooleanValue(iterate(context));
478     }
479
480     /**
481      * Compare two (sequence) values for equality. This supports identity constraints in XML Schema,
482      * which allow list-valued elements and attributes to participate in key and uniqueness constraints.
483      * This method returns false if any error occurs during the comparison, or if any of the items
484      * in either sequence is a node rather than an atomic value.
485      */

486
487     public boolean equals(Object JavaDoc obj) {
488         try {
489             if (obj instanceof Value) {
490                 SequenceIterator iter1 = iterate(null);
491                 SequenceIterator iter2 = ((Value)obj).iterate(null);
492                 while (true) {
493                     Item item1 = iter1.next();
494                     Item item2 = iter2.next();
495                     if (item1 == null && item2 == null) {
496                         return true;
497                     }
498                     if (item1 == null || item2 == null) {
499                         return false;
500                     }
501                     if (item1 instanceof NodeInfo || item2 instanceof NodeInfo) {
502                         return false;
503                     }
504                     if (!item1.equals(item2)) {
505                         return false;
506                     }
507                 }
508             } else {
509                 return false;
510             }
511         } catch (XPathException e) {
512             return false;
513         }
514     }
515
516     /**
517      * Compare two (sequence) values for equality. This supports identity constraints in XML Schema,
518      * which allow list-valued elements and attributes to participate in key and uniqueness constraints.
519      * This method returns false if any error occurs during the comparison, or if any of the items
520      * in either sequence is a node rather than an atomic value.
521      */

522
523     public boolean schemaEquals(Value obj) {
524         try {
525             SequenceIterator iter1 = iterate(null);
526             SequenceIterator iter2 = obj.iterate(null);
527             while (true) {
528                 Item item1 = iter1.next();
529                 Item item2 = iter2.next();
530                 if (item1 == null && item2 == null) {
531                     return true;
532                 }
533                 if (item1 == null || item2 == null) {
534                     return false;
535                 }
536                 if (item1 instanceof NodeInfo || item2 instanceof NodeInfo) {
537                     return false;
538                 }
539                 if (!((AtomicValue)item1).schemaEquals((AtomicValue)item2)) {
540                     return false;
541                 }
542             }
543         } catch (XPathException e) {
544             return false;
545         }
546     }
547
548     /**
549      * Return a hash code to support the equals() function
550      */

551
552     public int hashCode() {
553         try {
554             int hash = 0x06639662; // arbitrary seed
555
SequenceIterator iter = iterate(null);
556             while (true) {
557                 Item item = iter.next();
558                 if (item == null) {
559                     return hash;
560                 }
561                 hash ^= item.hashCode();
562             }
563         } catch (XPathException e) {
564             return 0;
565         }
566     }
567
568
569     /**
570      * Check statically that the results of the expression are capable of constructing the content
571      * of a given schema type.
572      * @param parentType The schema type
573      * @param env the static context
574      * @param whole
575      * @throws XPathException if the expression doesn't match the required content type
576      */

577
578     public void checkPermittedContents(SchemaType parentType, StaticContext env, boolean whole) throws XPathException {
579         return;
580     }
581
582     /**
583      * Reduce a value to its simplest form. If the value is a closure or some other form of deferred value
584      * such as a FunctionCallPackage, then it is reduced to a SequenceExtent. If it is a SequenceExtent containing
585      * a single item, then it is reduced to that item. One consequence that is exploited by class FilterExpression
586      * is that if the value is a singleton numeric value, then the result will be an instance of NumericValue
587      */

588
589     public Value reduce() throws XPathException {
590         return this;
591     }
592
593     /**
594      * Convert to Java object (for passing to external functions)
595      */

596
597     public Object JavaDoc convertToJava(Class JavaDoc target, XPathContext context) throws XPathException {
598
599         if (target == Object JavaDoc.class) {
600             List list = new ArrayList(20);
601             return convertToJavaList(list, context);
602         }
603
604         // See if the extension function is written to accept native Saxon objects
605

606         if (target.isAssignableFrom(this.getClass())) {
607             return this;
608         } else if (target.isAssignableFrom(SequenceIterator.class)) {
609             return iterate(context);
610         }
611
612         // Offer the object to registered external object models
613

614         if ((this instanceof ObjectValue || !(this instanceof AtomicValue)) && !(this instanceof EmptySequence)) {
615             List externalObjectModels = context.getController().getConfiguration().getExternalObjectModels();
616             for (int m=0; m<externalObjectModels.size(); m++) {
617                 ExternalObjectModel model = (ExternalObjectModel)externalObjectModels.get(m);
618                 Object JavaDoc object = model.convertXPathValueToObject(this, target, context);
619                 if (object != null) {
620                     return object;
621                 }
622             }
623         }
624
625         if (Collection.class.isAssignableFrom(target)) {
626             Collection list;
627             if (target.isAssignableFrom(ArrayList.class)) {
628                 list = new ArrayList(100);
629             } else {
630                 try {
631                     list = (Collection)target.newInstance();
632                 } catch (InstantiationException JavaDoc e) {
633                     DynamicError de = new DynamicError("Cannot instantiate collection class " + target);
634                     de.setXPathContext(context);
635                     throw de;
636                 } catch (IllegalAccessException JavaDoc e) {
637                     DynamicError de = new DynamicError("Cannot access collection class " + target);
638                     de.setXPathContext(context);
639                     throw de;
640                 }
641             }
642             return convertToJavaList(list, context);
643         } else if (target.isArray()) {
644             Class JavaDoc component = target.getComponentType();
645             if (component.isAssignableFrom(Item.class) ||
646                     component.isAssignableFrom(NodeInfo.class) ||
647                     component.isAssignableFrom(DocumentInfo.class)) {
648                 Value extent = this;
649                 if (extent instanceof Closure) {
650                     extent = SequenceExtent.makeSequenceExtent(extent.iterate(null));
651                 }
652                 int length = extent.getLength();
653                 Object JavaDoc array = Array.newInstance(component, length);
654                 SequenceIterator iter = extent.iterate(null);
655                 for (int i=0; i<length; i++) {
656                     Item item = iter.next();
657                     try {
658                         Array.set(array, i, item);
659                     } catch (IllegalArgumentException JavaDoc err) {
660                         DynamicError d = new DynamicError(
661                                 "Item " + i + " in supplied sequence cannot be converted " +
662                                 "to the component type of the Java array (" + component + ')', err);
663                         d.setXPathContext(context);
664                         throw d;
665                     }
666                 }
667                 return array;
668             } else /* if (!(this instanceof AtomicValue)) */ {
669                 // try atomizing the sequence, unless this is a single atomic value, in which case we've already
670
// tried that.
671
SequenceIterator it = Atomizer.AtomizingFunction.getAtomizingIterator(iterate(context));
672                 int length;
673                 if ((it.getProperties() & SequenceIterator.LAST_POSITION_FINDER) != 0) {
674                     length = ((LastPositionFinder)it).getLastPosition();
675                 } else {
676                     SequenceExtent extent = new SequenceExtent(it);
677                     length = extent.getLength();
678                     it = extent.iterate(context);
679                 }
680                 Object JavaDoc array = Array.newInstance(component, length);
681                 for (int i=0; i<length; i++) {
682                     try {
683                         AtomicValue val = (AtomicValue)it.next();
684                         Object JavaDoc jval = val.convertToJava(component, context);
685                         Array.set(array, i, jval);
686                     } catch (XPathException err) {
687                         DynamicError d = new DynamicError(
688                                 "Cannot convert item in atomized sequence to the component type of the Java array", err);
689                         d.setXPathContext(context);
690                         throw d;
691                     }
692                 }
693                 return array;
694 // } else {
695
// DynamicError d = new DynamicError(
696
// "Cannot convert supplied argument value to the required type");
697
// d.setXPathContext(context);
698
// throw d;
699
}
700
701         } else if (target.isAssignableFrom(Item.class) ||
702                 target.isAssignableFrom(NodeInfo.class) ||
703                 target.isAssignableFrom(DocumentInfo.class)) {
704
705             // try passing the first item in the sequence provided it is the only one
706
SequenceIterator iter = iterate(null);
707             Item first = null;
708             while (true) {
709                 Item next = iter.next();
710                 if (next == null) {
711                     break;
712                 }
713                 if (first != null) {
714                     DynamicError err = new DynamicError("Sequence contains more than one value; Java method expects only one");
715                     err.setXPathContext(context);
716                     throw err;
717                 }
718                 first = next;
719             }
720             if (first == null) {
721                 // sequence is empty; pass a Java null
722
return null;
723             }
724             if (target.isAssignableFrom(first.getClass())) {
725                 // covers Item and NodeInfo
726
return first;
727             }
728
729             Object JavaDoc n = first;
730             while (n instanceof VirtualNode) {
731                 // If we've got a wrapper around a DOM or JDOM node, and the user wants a DOM
732
// or JDOM node, we unwrap it
733
Object JavaDoc vn = ((VirtualNode) n).getUnderlyingNode();
734                 if (target.isAssignableFrom(vn.getClass())) {
735                     return vn;
736                 } else {
737                     n = vn;
738                 }
739             }
740
741             throw new DynamicError("Cannot convert supplied XPath value to the required type for the extension function");
742         } else if (!(this instanceof AtomicValue)) {
743             // try atomizing the value, unless this is an atomic value, in which case we've already tried that
744
SequenceIterator it = Atomizer.AtomizingFunction.getAtomizingIterator(iterate(context));
745             Item first = null;
746             while (true) {
747                 Item next = it.next();
748                 if (next == null) {
749                     break;
750                 }
751                 if (first != null) {
752                     DynamicError err = new DynamicError("Sequence contains more than one value; Java method expects only one");
753                     err.setXPathContext(context);
754                     throw err;
755                 }
756                 first = next;
757             }
758             if (first == null) {
759                 // sequence is empty; pass a Java null
760
return null;
761             }
762             if (target.isAssignableFrom(first.getClass())) {
763                 return first;
764             } else {
765                 return ((AtomicValue)first).convertToJava(target, context);
766             }
767         } else {
768             throw new DynamicError("Cannot convert supplied XPath value to the required type for the extension function");
769         }
770     }
771
772     private Collection convertToJavaList(Collection list, XPathContext context) throws XPathException {
773         // TODO: with JDK 1.5, check to see if the item type of the list is constrained
774
SequenceIterator iter = iterate(null);
775         while (true) {
776             Item it = iter.next();
777             if (it == null) {
778 // if (list.size() == 0) {
779
// // map empty sequence to null
780
// return null;
781
// } else {
782
return list;
783 // }
784
}
785             if (it instanceof AtomicValue) {
786                 list.add(((AtomicValue)it).convertToJava(Object JavaDoc.class, context));
787             } else if (it instanceof VirtualNode) {
788                 list.add(((VirtualNode)it).getUnderlyingNode());
789             } else {
790                 list.add(it);
791             }
792         }
793     }
794
795     /**