Project

Profile

Help

How to connect?
Download (51.1 KB) Statistics
| Branch: | Tag: | Revision:

he / latest9.1 / bn / csource / api / Saxon.Api / Model.cs @ e090dcb1

1
using System;
2
using System.IO;
3
using System.Xml;
4
using System.Collections;
5
using JConfiguration = net.sf.saxon.Configuration;
6
using JAtomicValue = net.sf.saxon.value.AtomicValue;
7
using JSingletonNode = net.sf.saxon.value.SingletonNode;
8
using JConversionResult = net.sf.saxon.type.ConversionResult;
9
using JValidationFailure = net.sf.saxon.type.ValidationFailure;
10
using JStandardNames = net.sf.saxon.om.StandardNames;
11
using DotNetReceiver = net.sf.saxon.dotnet.DotNetReceiver;
12
using DotNetObjectValue = net.sf.saxon.dotnet.DotNetObjectValue;
13
using JBigDecimal = java.math.BigDecimal;
14
using JArrayList = java.util.ArrayList;
15
using net.sf.saxon.om;
16
using net.sf.saxon.value;
17
using net.sf.saxon.pattern;
18
using JAtomicType = net.sf.saxon.type.AtomicType;
19
using JSchemaType = net.sf.saxon.type.SchemaType;
20
using JType = net.sf.saxon.type.Type;
21

    
22

    
23
namespace Saxon.Api
24
{
25

    
26
    /// <summary>
27
    /// An value in the XDM data model. A value is a sequence of zero or more
28
    /// items, each item being either an atomic value or a node.
29
    /// </summary>
30
    /// <remarks>
31
    /// <para>An <c>XdmValue</c> is immutable.</para>
32
    /// <para>A sequence consisting of a single item <i>may</i> be represented
33
    /// as an instance of <c>XdmItem</c>, which is a subtype of <c>XdmValue</c>.</para>
34
    /// </remarks>
35

    
36
    [Serializable]
37
    public class XdmValue : IEnumerable
38
    {
39

    
40
        internal ValueRepresentation value;
41

    
42
        internal XdmValue() { }
43

    
44
        /// <summary>
45
        /// Create a value from a collection of items
46
        /// </summary>
47
        /// <param name="items">An enumerable collection providing the items to make up the sequence. Every
48
        /// member of this collection must be an instance of <c>XdmItem</c>
49
        /// </param>
50

    
51
        public XdmValue(IEnumerable items)
52
        {
53
            JArrayList list = new JArrayList();
54
            foreach (XdmItem c in items)
55
            {
56
                list.add((Item)c.Unwrap());
57
            }
58
            value = new SequenceExtent(list);
59
        }
60

    
61
        /// <summary>
62
        /// Create an XdmValue from an underlying Saxon ValueRepresentation object.
63
        /// This method is provided for the benefit of applications that need to mix
64
        /// use of the Saxon .NET API with direct use of the underlying objects
65
        /// and methods offered by the Java implementation.
66
        /// </summary>
67
        /// <param name="value">An object representing an XDM value in the
68
        /// underlying Saxon implementation.</param>
69
        /// <returns>An XdmValue that wraps the underlying Saxon value
70
        /// representation.</returns>
71

    
72
        public static XdmValue Wrap(ValueRepresentation value)
73
        {
74
            XdmValue result;
75
            if (value == null || value is EmptySequence)
76
            {
77
                return XdmEmptySequence.INSTANCE;
78
            }
79
            else if (value is JAtomicValue)
80
            {
81
                result = new XdmAtomicValue();
82
            }
83
            else if (value is NodeInfo)
84
            {
85
                result = new XdmNode();
86
            }
87
            else if (value is JSingletonNode)
88
            {
89
                value = ((JSingletonNode)value).getNode();
90
                result = new XdmNode();
91
            }
92
            else
93
            {
94
                result = new XdmValue();
95
            }
96
            result.value = value;
97
            return result;
98
        }
99

    
100
        /// <summary>
101
        /// Extract the underlying Saxon ValueRepresentation object from an XdmValue.
102
        /// This method is provided for the benefit of applications that need to mix
103
        /// use of the Saxon .NET API with direct use of the underlying objects
104
        /// and methods offered by the Java implementation.
105
        /// </summary>
106
        /// <returns>An object representing the XDM value in the
107
        /// underlying Saxon implementation.</returns>
108

    
109

    
110
        public ValueRepresentation Unwrap()
111
        {
112
            return value;
113
        }
114

    
115
        /// <summary>
116
        /// Get the sequence of items in the form of an <c>IList</c>
117
        /// </summary>
118
        /// <returns>
119
        /// The list of items making up this value. Each item in the list
120
        /// will be an object of type <c>XdmItem</c>
121
        /// </returns>        
122

    
123
        public IList GetList()
124
        {
125
            if (value == null)
126
            {
127
                return new ArrayList();
128
            }
129
            else if (value is Item)
130
            {
131
                ArrayList list = new ArrayList(1);
132
                list.Add((NodeInfo)value);
133
                return list;
134
            }
135
            else
136
            {
137
                ArrayList list = new ArrayList();
138
                SequenceIterator iter = ((Value)value).iterate();
139
                while (true)
140
                {
141
                    Item jitem = iter.next();
142
                    if (jitem == null)
143
                    {
144
                        break;
145
                    }
146
                    list.Add((XdmItem)XdmValue.Wrap(jitem));
147
                }
148
                return list;
149
            }
150
        }
151

    
152
        /// <summary>
153
        /// Get the sequence of items in the form of an <c>IEnumerator</c>
154
        /// </summary>
155
        /// <returns>
156
        /// An enumeration over the list of items making up this value. Each item in the list
157
        /// will be an object of type <c>XdmItem</c>
158
        /// </returns>    
159

    
160
        public IEnumerator GetEnumerator()
161
        {
162
            if (value == null)
163
            {
164
                return EmptyEnumerator.INSTANCE;
165
            }
166
            else if (value is Item)
167
            {
168
                return new SequenceEnumerator(SingletonIterator.makeIterator((Item)value));
169
            }
170
            else
171
            {
172
                return new SequenceEnumerator(((Value)value).iterate());
173
            }
174
        }
175

    
176
        /// <summary>
177
        /// Get the number of items in the sequence
178
        /// </summary>
179
        /// <returns>
180
        /// The number of items in the sequence
181
        /// </returns> 
182

    
183
        public int Count
184
        {
185
            get
186
            {
187
                if (value == null)
188
                {
189
                    return 0;
190
                }
191
                else if (value is Item)
192
                {
193
                    return 1;
194
                }
195
                else
196
                {
197
                    return ((Value)value).getLength();
198
                }
199
            }
200
        }
201

    
202

    
203
    }
204

    
205
    /// <summary>
206
    /// The class <c>XdmItem</c> represents an item in a sequence, as defined
207
    /// by the XDM data model. An item is either an atomic value or a node.
208
    /// </summary>
209
    /// <remarks>
210
    /// <para>An item is a member of a sequence, but it can also be considered as
211
    /// a sequence (of length one) in its own right. <c>XdmItem</c> is a subtype
212
    /// of <c>XdmValue</c> because every Item in the XDM data model is also a
213
    /// value.</para>
214
    /// <para>It cannot be assumed that every sequence of length one will be 
215
    /// represented by an <c>XdmItem</c>. It is quite possible for an <c>XdmValue</c>
216
    /// that is not an <c>XdmItem</c> to hold a singleton sequence.</para>
217
    /// </remarks> 
218

    
219
    [Serializable]
220
    public abstract class XdmItem : XdmValue
221
    {
222

    
223
        /// <summary>
224
        /// Determine whether the item is an atomic value
225
        /// </summary>
226
        /// <returns>
227
        /// true if the item is an atomic value, false if it is a Node
228
        /// </returns>
229

    
230
        public abstract bool IsAtomic();
231

    
232
    }
233

    
234
    /// <summary>
235
    /// The class <c>XdmAtomicValue</c> represents an item in an XPath 2.0 sequence
236
    /// that is an atomic value. The value may belong to any of the 19 primitive types
237
    /// defined in XML Schema, or to a type derived from these primitive types, or to 
238
    /// the XPath 2.0 type <c>xdt:untypedAtomic</c>
239
    /// </summary>
240

    
241
    [Serializable]
242
    public class XdmAtomicValue : XdmItem
243
    {
244

    
245
        //internal JAtomicValue atomicValue;
246

    
247
        internal XdmAtomicValue() { }
248

    
249
        /// <summary>
250
        /// Determine whether the item is an atomic value
251
        /// </summary>
252
        /// <returns>
253
        /// true (the item is an atomic value)
254
        /// </returns>
255

    
256
        public override bool IsAtomic()
257
        {
258
            return true;
259
        }
260

    
261
        //internal AtomicValue(JAtomicValue value) {
262
        //    this.value = value;
263
        //}
264

    
265
        /// <summary>
266
        /// Construct an atomic value of type <c>xs:string</c>
267
        /// </summary>
268
        /// <param name="str">The string value</param>
269

    
270
        public XdmAtomicValue(String str)
271
        {
272
            this.value = new StringValue(str);
273
        }
274

    
275
        /// <summary>
276
        /// Construct an atomic value of type <c>xs:integer</c>
277
        /// </summary>
278
        /// <param name="i">The integer value</param>
279

    
280
        public XdmAtomicValue(long i)
281
        {
282
            this.value = new Int64Value(i);
283
        }
284

    
285
        /// <summary>
286
        /// Construct an atomic value of type <c>xs:decimal</c>
287
        /// </summary>
288
        /// <param name="d">The decimal value</param>
289

    
290
        public XdmAtomicValue(decimal d)
291
        {
292
            this.value = new DecimalValue(new JBigDecimal(d.ToString()));
293
        }
294

    
295
        /// <summary>
296
        /// Construct an atomic value of type <c>xs:float</c>
297
        /// </summary>
298
        /// <param name="f">The float value</param>        
299

    
300
        public XdmAtomicValue(float f)
301
        {
302
            this.value = new FloatValue(f);
303
        }
304

    
305
        /// <summary>
306
        /// Construct an atomic value of type <c>xs:double</c>
307
        /// </summary>
308
        /// <param name="d">The double value</param>
309

    
310
        public XdmAtomicValue(double d)
311
        {
312
            this.value = new DoubleValue(d);
313
        }
314

    
315
        /// <summary>
316
        /// Construct an atomic value of type <c>xs:boolean</c>
317
        /// </summary>
318
        /// <param name="b">The boolean value</param>
319

    
320
        public XdmAtomicValue(bool b)
321
        {
322
            this.value = BooleanValue.get(b);
323
        }
324

    
325
        /// <summary>
326
        /// Construct an atomic value of type <c>xs:anyURI</c>
327
        /// </summary>
328
        /// <param name="u">The uri value</param>
329

    
330
        public XdmAtomicValue(Uri u)
331
        {
332
            this.value = new AnyURIValue(u.ToString());
333
        }
334

    
335
        /// <summary>
336
        /// Construct an atomic value of type <c>xs:QName</c>
337
        /// </summary>
338
        /// <param name="q">The QName value</param>                
339

    
340
        public XdmAtomicValue(QName q)
341
        {
342
            this.value = new QNameValue(
343
                q.Prefix, q.Uri, q.LocalName, null);
344
        }
345

    
346
        /// <summary>
347
        /// Construct an atomic value of a given built-in or user-defined type
348
        /// </summary>
349
        /// <example>
350
        ///   <code>AtomicValue("abcd", QName.XDT_UNTYPED_ATOMIC)</code>
351
        ///   <para>creates an untyped atomic value containing the string "abcd"</para>
352
        /// </example>
353
        /// <param name="lexicalForm">The string representation of the value (any value that is acceptable
354
        /// in the lexical space, as defined by XML Schema Part 2). Whitespace normalization as defined by
355
        /// the target type will be applied to the value.</param>
356
        /// <param name="type">The QName giving the name of the target type. This must be an atomic
357
        /// type, and it must not be a type that is namespace-sensitive (QName, NOTATION, or types derived
358
        /// from these). If the type is a user-defined type then its definition must be present
359
        /// in the schema cache maintained by the <c>SchemaManager</c>.</param> 
360
        /// <param name="processor">The <c>Processor</c> object. This is needed for looking up user-defined
361
        /// types, and also because some conversions are context-sensitive, for example they depend on the
362
        /// implicit timezone or the choice of XML 1.0 versus XML 1.1 for validating names.</param>
363
        /// <exception name="ArgumentException">Thrown if the type is unknown or unsuitable, or if the supplied string is not
364
        /// a valid lexical representation of a value of the given type.</exception>
365

    
366
        public XdmAtomicValue(String lexicalForm, QName type, Processor processor)
367
        {
368
            JConfiguration jconfig = processor.config;
369
            int fp = jconfig.getNamePool().getFingerprint(type.Uri, type.LocalName);
370
            if (fp == -1)
371
            {
372
                throw new ArgumentException("Unknown name " + type);
373
            }
374
            JSchemaType st = jconfig.getSchemaType(fp);
375
            if (st == null)
376
            {
377
                throw new ArgumentException("Unknown type " + type);
378
            }
379
            if (!(st is JAtomicType))
380
            {
381
                throw new ArgumentException("Specified type " + type + " is not atomic");
382
            }
383
            if (((JAtomicType)st).isNamespaceSensitive())
384
            {
385
                throw new ArgumentException("Specified type " + type + " is namespace-sensitive");
386
            }
387
            JConversionResult result = new StringValue(lexicalForm).convert(
388
                    (JAtomicType)st,
389
                    true,
390
                    jconfig.getConversionContext());
391
            if (result is JValidationFailure)
392
            {
393
                throw new ArgumentException(((JValidationFailure)result).getMessage());
394
            }
395
            this.value = (JAtomicValue)result;
396
        }
397

    
398
        /// <summary>
399
        /// Create an atomic value that wraps an external object. Such values can be used
400
        /// in conjunction with extension functions. (Synonym of <c>WrapExternalObject</c>,
401
        /// retained for backwards compatibility.)
402
        /// </summary>
403
        /// <param name="external">The object to be wrapped.</param>
404
        /// <returns>The wrapped object</returns>
405

    
406
        public static XdmAtomicValue wrapExternalObject(object external)
407
        {
408
            return (XdmAtomicValue)XdmValue.Wrap(new DotNetObjectValue(external));
409
        }
410

    
411
        /// <summary>
412
        /// Create an atomic value that wraps an external object. Such values can be used
413
        /// in conjunction with extension functions.
414
        /// </summary>
415
        /// <param name="external">The object to be wrapped.</param>
416
        /// <returns>The wrapped object</returns>
417

    
418
        public static XdmAtomicValue WrapExternalObject(object external)
419
        {
420
            return (XdmAtomicValue)XdmValue.Wrap(new DotNetObjectValue(external));
421
        }
422

    
423

    
424
        /// <summary>
425
        /// Convert the atomic value to a string
426
        /// </summary>
427
        /// <returns>The value converted to a string, according to the rules
428
        /// of the XPath 2.0 cast operator</returns>        
429

    
430
        public override String ToString()
431
        {
432
            return ((JAtomicValue)value).getStringValue();
433
        }
434

    
435
        /// <summary>
436
        /// Get the name of the value's XDM type
437
        /// </summary>
438
        /// <param name="processor">The <c>Processor</c> object. 
439
        /// This is needed for access to the NamePool,
440
        /// which maps the internal form of type names to their external form.</param>
441
        /// <returns>The type of the value, as a QName. This may be a built-in type or a user-defined
442
        /// atomic type.
443
        /// </returns>
444

    
445

    
446
        public QName GetTypeName(Processor processor)
447
        {
448
            int fp = ((JAtomicType)((JAtomicValue)value).getItemType(null)).getFingerprint();
449
            NamePool pool = processor.config.getNamePool();
450
            return new QName(pool.getPrefix(fp),
451
                             pool.getURI(fp),
452
                             pool.getLocalName(fp));
453
        }
454

    
455
        /// <summary>
456
        /// Get the name of the primitive type of the value
457
        /// </summary>
458
        /// <returns>The primitive type of the value, as a QName. This will be the name of
459
        /// one of the primitive types defined in XML Schema Part 2, or the XPath-defined
460
        /// type <c>xdt:untypedAtomic</c>. For the purposes of this method, <c>xs:integer</c> is considered
461
        /// to be a primitive type.
462
        /// </returns>
463

    
464

    
465
        public QName GetPrimitiveTypeName()
466
        {
467
            int fp = ((JAtomicValue)value).getItemType(null).getPrimitiveType();
468
            return new QName(JStandardNames.getPrefix(fp),
469
                             JStandardNames.getURI(fp),
470
                             JStandardNames.getLocalName(fp));
471
        }
472

    
473
        /// <summary>Get the value as a CLI object of the nearest equivalent type.</summary>
474
        /// <remarks>
475
        /// <para>The return type is as follows:</para>
476
        /// <para>xs:string - String</para>
477
        /// <para>xs:integer - Long</para>
478
        /// <para>xs:decimal - Decimal</para>
479
        /// <para>xs:double - Double</para>
480
        /// <para>xs:float - Float</para>
481
        /// <para>xs:boolean - Bool</para>
482
        /// <para>xs:QName - QName</para>
483
        /// <para>xs:anyURI - Uri</para>
484
        /// <para>xdt:untypedAtomic - String</para>
485
        /// <para>Other types - currently String, but this may change in the future</para>
486
        /// </remarks>
487
        /// <returns>The value converted to the most appropriate CLI type</returns>
488

    
489
        public Object Value
490
        {
491
            get
492
            {
493
                if (value is IntegerValue)
494
                {
495
                    return ((IntegerValue)value).longValue();
496
                }
497
                else if (value is DoubleValue)
498
                {
499
                    return ((DoubleValue)value).getDoubleValue();
500
                }
501
                else if (value is FloatValue)
502
                {
503
                    return ((FloatValue)value).getFloatValue();
504
                }
505
                else if (value is DecimalValue)
506
                {
507
                    return Decimal.Parse(((DecimalValue)value).getStringValue());
508
                }
509
                else if (value is BooleanValue)
510
                {
511
                    return ((BooleanValue)value).getBooleanValue();
512
                }
513
                else if (value is AnyURIValue)
514
                {
515
                    return new Uri(((AnyURIValue)value).getStringValue());
516
                }
517
                else if (value is QNameValue)
518
                {
519
                    return new QName((QNameValue)value);
520
                }
521
                else
522
                {
523
                    return ((JAtomicValue)value).getStringValue();
524
                }
525
            }
526
        }
527

    
528

    
529
    }
530

    
531
    /// <summary inherits="XdmItem">
532
    /// The class <c>XdmNode</c> represents a Node in the XDM Data Model. A Node
533
    /// is an <c>XdmItem</c>, and is therefore an <c>XdmValue</c> in its own right, and may also participate
534
    /// as one item within a sequence value.
535
    /// </summary>
536
    /// <remarks>
537
    /// <para>An <c>XdmNode</c> is implemented as a wrapper around an object
538
    /// of type <c>net.sf.saxon.NodeInfo</c>. Because this is a key interface
539
    /// within Saxon, it is exposed via this API, even though it is a Java
540
    /// interface that is not part of the API proper.</para>
541
    /// <para>The <c>XdmNode</c> interface exposes basic properties of the node, such
542
    /// as its name, its string value, and its typed value. Navigation to other nodes
543
    /// is supported through a single method, <c>EnumerateAxis</c>, which allows
544
    /// other nodes to be retrieved by following any of the XPath axes.</para>
545
    /// </remarks>
546

    
547
    [Serializable]
548
    public class XdmNode : XdmItem
549
    {
550

    
551
        /// <summary>
552
        /// Determine whether the item is an atomic value
553
        /// </summary>
554
        /// <returns>
555
        /// false (the item is not an atomic value)
556
        /// </returns>
557

    
558
        public override bool IsAtomic()
559
        {
560
            return false;
561
        }
562

    
563
        /// <summary>
564
        /// The name of the node, as a <c>QName</c>. Returns null in the case of unnamed nodes.
565
        /// </summary>
566

    
567
        public QName NodeName
568
        {
569
            get
570
            {
571
                NodeInfo node = (NodeInfo)value;
572
                String local = node.getLocalPart();
573
                if (local == "")
574
                {
575
                    return null;
576
                }
577
                String prefix = node.getPrefix();
578
                String uri = node.getURI();
579
                return new QName(prefix, uri, local);
580
            }
581
        }
582

    
583
        /// <summary>
584
        /// The kind of node, as an instance of <c>System.Xml.XmlNodeType</c>.
585
        /// </summary>
586
        /// <remarks>For a namespace node in the XDM model, the value XmlNodeType.None 
587
        /// is returned.
588
        /// </remarks>
589

    
590
        public XmlNodeType NodeKind
591
        {
592
            get
593
            {
594
                NodeInfo node = (NodeInfo)value;
595
                int kind = node.getNodeKind();
596
                switch (kind)
597
                {
598
                    case JType.DOCUMENT:
599
                        return XmlNodeType.Document;
600
                    case JType.ELEMENT:
601
                        return XmlNodeType.Element;
602
                    case JType.ATTRIBUTE:
603
                        return XmlNodeType.Attribute;
604
                    case JType.TEXT:
605
                        return XmlNodeType.Text;
606
                    case JType.COMMENT:
607
                        return XmlNodeType.Comment;
608
                    case JType.PROCESSING_INSTRUCTION:
609
                        return XmlNodeType.ProcessingInstruction;
610
                    case JType.NAMESPACE:
611
                        return XmlNodeType.None;
612
                    default:
613
                        throw new ArgumentException("Unknown node kind");
614
                }
615
            }
616
        }
617

    
618
        /// <summary>
619
        /// The typed value of the node, as an instance of <c>XdmValue</c>.
620
        /// </summary>
621
        /// <exception>
622
        /// A DynamicError is thrown if the node has no typed value, as will be the case for
623
        /// an element with element-only content.
624
        /// </exception>
625

    
626
        public XdmValue TypedValue
627
        {
628
            get { return XdmValue.Wrap(((NodeInfo)value).atomize()); }
629
        }
630

    
631
        /// <summary>
632
        /// The string value of the node.
633
        /// </summary>
634

    
635
        public String StringValue
636
        {
637
            get { return ((NodeInfo)value).getStringValue(); }
638
        }
639

    
640
        /// <summary>
641
        /// Get the parent of this node.
642
        /// </summary>
643
        /// <remarks>
644
        /// Returns either a document node, and element node, or null in the case where
645
        /// this node has no parent. 
646
        /// </remarks>
647

    
648
        public XdmNode Parent
649
        {
650
            get { return (XdmNode)XdmValue.Wrap(((NodeInfo)value).getParent()); }
651
        }
652

    
653
        /// <summary>
654
        /// Get the root of the tree containing this node.
655
        /// </summary>
656
        /// <remarks>
657
        /// Returns the root of the tree containing this node (which might be this node itself).
658
        /// </remarks>
659

    
660
        public XdmNode Root
661
        {
662
            get
663
            {
664
                XdmNode parent = Parent;
665
                if (parent == null)
666
                {
667
                    return this;
668
                }
669
                else
670
                {
671
                    return parent.Root;
672
                }
673
            }
674
        }
675

    
676
        /// <summary>
677
        /// Get a the string value of a named attribute of this element. 
678
        /// </summary>
679
        /// <remarks>
680
        /// Returns null if this node is not an element, or if this element has no
681
        /// attribute with the specified name.
682
        /// </remarks>
683
        /// <param name="name">The name of the attribute whose value is required</param>
684

    
685
        public String GetAttributeValue(QName name)
686
        {
687
            int fp = ((NodeInfo)value).getConfiguration().getNamePool().allocate(
688
                "", name.Uri, name.LocalName);
689
            return ((NodeInfo)value).getAttributeValue(fp);
690
        }
691

    
692
        /// <summary>
693
        /// Get an enumerator that supplies all the nodes on one of the XPath
694
        /// axes, starting with this node.
695
        /// </summary>
696
        /// <param name="axis">
697
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child axis.
698
        /// </param>
699
        /// <remarks>
700
        /// The nodes are returned in axis order: that is, document order for a forwards
701
        /// axis, reverse document order for a reverse axis.
702
        /// </remarks>
703

    
704
        public IEnumerator EnumerateAxis(XdmAxis axis)
705
        {
706
            return new SequenceEnumerator(((NodeInfo)value).iterateAxis(GetAxisNumber(axis)));
707
        }
708

    
709
        /// <summary>
710
        /// Get an enumerator that selects all the nodes on one of the XPath
711
        /// axes, provided they have a given name. The nodes selected are those of the principal
712
        /// node kind (elements for most axes, attributes for the attribute axis, namespace nodes
713
        /// for the namespace axis) whose name matches the name given in the second argument.
714
        /// </summary>
715
        /// <param name="axis">
716
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child axis.
717
        /// </param>
718
        /// <param name="nodeName">
719
        /// The name of the required nodes, for example <c>new QName("", "item")</c> to select
720
        /// nodes with local name "item", in no namespace.
721
        /// </param>
722
        /// <remarks>
723
        /// The nodes are returned in axis order: that is, document order for a forwards
724
        /// axis, reverse document order for a reverse axis.
725
        /// </remarks>
726

    
727
        public IEnumerator EnumerateAxis(XdmAxis axis, QName nodeName)
728
        {
729
            int kind;
730
            switch (axis)
731
            {
732
                case XdmAxis.Attribute:
733
                    kind = net.sf.saxon.type.Type.ATTRIBUTE;
734
                    break;
735
                case XdmAxis.Namespace:
736
                    kind = net.sf.saxon.type.Type.NAMESPACE;
737
                    break;
738
                default:
739
                    kind = net.sf.saxon.type.Type.ELEMENT;
740
                    break;
741
            }
742
            NamePool pool = ((NodeInfo)value).getConfiguration().getNamePool();
743
            int nameCode = pool.allocate("", nodeName.Uri, nodeName.LocalName);
744
            NameTest test = new NameTest(kind, nameCode, pool);
745
            return new SequenceEnumerator(((NodeInfo)value).iterateAxis(GetAxisNumber(axis), test));
746
        }
747

    
748
        private static byte GetAxisNumber(XdmAxis axis)
749
        {
750
            switch (axis)
751
            {
752
                case XdmAxis.Ancestor: return Axis.ANCESTOR;
753
                case XdmAxis.AncestorOrSelf: return Axis.ANCESTOR_OR_SELF;
754
                case XdmAxis.Attribute: return Axis.ATTRIBUTE;
755
                case XdmAxis.Child: return Axis.CHILD;
756
                case XdmAxis.Descendant: return Axis.DESCENDANT;
757
                case XdmAxis.DescendantOrSelf: return Axis.DESCENDANT_OR_SELF;
758
                case XdmAxis.Following: return Axis.FOLLOWING;
759
                case XdmAxis.FollowingSibling: return Axis.FOLLOWING_SIBLING;
760
                case XdmAxis.Namespace: return Axis.NAMESPACE;
761
                case XdmAxis.Parent: return Axis.PARENT;
762
                case XdmAxis.Preceding: return Axis.PRECEDING;
763
                case XdmAxis.PrecedingSibling: return Axis.PRECEDING_SIBLING;
764
                case XdmAxis.Self: return Axis.SELF;
765
            }
766
            return 0;
767
        }
768

    
769
        /// <summary>
770
        /// The Base URI of the node.
771
        /// </summary>
772

    
773
        public Uri BaseUri
774
        {
775
            get { return new Uri(((NodeInfo)value).getBaseURI()); }
776
        }
777

    
778
        /// <summary>
779
        /// The Document URI of the node.
780
        /// </summary>
781

    
782
        public Uri DocumentUri
783
        {
784
            get
785
            {
786
                String s = ((NodeInfo)value).getSystemId();
787
                if (s == null || s.Length == 0)
788
                {
789
                    return null;
790
                }
791
                return new Uri(s);
792
            }
793
        }
794

    
795
        /// <summary>
796
        /// Send the node (that is, the subtree rooted at this node) to an <c>XmlWriter</c>
797
        /// </summary>
798
        /// <remarks>
799
        /// Note that a <c>XmlWriter</c> can only handle a well-formed XML document. This method
800
        /// will therefore signal an exception if the node is a document node with no children, or with
801
        /// more than one element child.
802
        /// </remarks>
803

    
804
        public void WriteTo(XmlWriter writer)
805
        {
806
            NodeInfo node = ((NodeInfo)value);
807
            DotNetReceiver receiver = new DotNetReceiver(writer);
808
            receiver.setPipelineConfiguration(node.getConfiguration().makePipelineConfiguration());
809
            receiver.open();
810
            node.copy(receiver, 2, false, 0);
811
            receiver.close();
812
        }
813

    
814
        /// <summary>
815
        /// Return a serialization of this node as lexical XML
816
        /// </summary>
817
        /// <remarks>
818
        /// <para>In the case of an element node, the result will be a well-formed
819
        /// XML document serialized as defined in the W3C XSLT/XQuery serialization specification,
820
        /// using options method="xml", indent="yes", omit-xml-declaration="yes".</para>
821
        /// <para>In the case of a document node, the result will be a well-formed
822
        /// XML document provided that the document node contains exactly one element child,
823
        /// and no text node children. In other cases it will be a well-formed external
824
        /// general parsed entity.</para>
825
        /// <para>In the case of an attribute node, the output is a string in the form
826
        /// <c>name="value"</c>. The name will use the original namespace prefix.</para>
827
        /// <para>Other nodes, such as text nodes, comments, and processing instructions, are
828
        /// represented as they would appear in lexical XML.</para>
829
        /// </remarks>
830

    
831
        public String OuterXml
832
        {
833
            get
834
            {
835
                NodeInfo node = ((NodeInfo)value);
836

    
837
                if (node.getNodeKind() == JType.ATTRIBUTE)
838
                {
839
                    String val = node.getStringValue().Replace("\"", "&quot;");
840
                    val = val.Replace("<", "&lt;");
841
                    val = val.Replace("&", "&amp;");
842
                    return node.getDisplayName() + "=\"" + val + '"';
843
                }
844

    
845
                Serializer serializer = new Serializer();
846
                serializer.SetOutputProperty(Serializer.METHOD, "xml");
847
                serializer.SetOutputProperty(Serializer.INDENT, "yes");
848
                serializer.SetOutputProperty(Serializer.OMIT_XML_DECLARATION, "yes");
849

    
850
                StringWriter sw = new StringWriter();
851
                serializer.SetOutputWriter(sw);
852
                node.copy(serializer.GetReceiver(node.getConfiguration()), 2, false, 0);
853
                return sw.ToString();
854
            }
855
        }
856

    
857

    
858
        /// <summary>
859
        /// Return a string representation of the node.
860
        /// </summary>
861
        /// <remarks>
862
        /// This currently returns the same as the <c>OuterXml</c> property.
863
        /// To get the string value as defined in XPath, use the <c>StringValue</c> property.
864
        /// </remarks>
865

    
866
        public override String ToString()
867
        {
868
            return OuterXml;
869
        }
870

    
871
        /// <summary>
872
        /// Escape hatch to the underlying class in the Java implementation
873
        /// </summary>
874

    
875
        public NodeInfo Implementation
876
        {
877
            get { return ((NodeInfo)value); }
878
        }
879

    
880

    
881
    }
882

    
883

    
884
    /// <summary inherits="XdmValue">
885
    /// The class <c>XdmEmptySequence</c> represents an empty sequence in the XDM Data Model.
886
    /// </summary>
887
    /// <remarks>
888
    /// <para>An empty sequence <i>may</i> also be represented by an <c>XdmValue</c> whose length
889
    /// happens to be zero. Applications should therefore not test to see whether an object
890
    /// is an instance of this class in order to decide whether it is empty.</para>
891
    /// <para>In interfaces that expect an <c>XdmItem</c>, an empty sequence is represented
892
    /// by a CLI <c>null</c> value.</para> 
893
    /// </remarks>
894

    
895
    [Serializable]
896
    public sealed class XdmEmptySequence : XdmValue
897
    {
898

    
899
        ///<summary>The singular instance of this class</summary>
900

    
901
        public static XdmEmptySequence INSTANCE = new XdmEmptySequence();
902

    
903
        private XdmEmptySequence()
904
        {
905
            this.value = null;
906
        }
907
    }
908

    
909

    
910
    /// <summary>
911
    /// The QName class represents an instance of xs:QName, as defined in the XPath 2.0
912
    /// data model. Internally, it has three components, a namespace URI, a local name, and
913
    /// a prefix. The prefix is intended to be used only when converting the value back to 
914
    /// a string.
915
    /// </summary>
916
    /// <remarks>
917
    /// Note that a QName is not itself an <c>XdmItem</c> in this model; however it can
918
    /// be wrapped in an XdmItem.
919
    /// </remarks>    
920

    
921
    [Serializable]
922
    public sealed class QName
923
    {
924

    
925
        private String prefix;
926
        private String uri;
927
        private String local;
928
        int hashcode = -1;      // evaluated lazily
929
        int fingerprint = -1;   // evaluated only if the QName is registered with the Processor
930
        private NamePool pool = null;
931

    
932
        private static String XS = NamespaceConstant.SCHEMA;
933

    
934
        /// <summary>QName constant for the name xs:string</summary>
935
        public static readonly QName XS_STRING = new QName(XS, "xs:string");
936

    
937
        /// <summary>QName constant for the name xs:integer</summary>
938
        public static readonly QName XS_INTEGER = new QName(XS, "xs:integer");
939

    
940
        /// <summary>QName constant for the name xs:double</summary>
941
        public static readonly QName XS_DOUBLE = new QName(XS, "xs:double");
942

    
943
        /// <summary>QName constant for the name xs:float</summary>
944
        public static readonly QName XS_FLOAT = new QName(XS, "xs:float");
945

    
946
        /// <summary>QName constant for the name xs:decimal</summary>
947
        public static readonly QName XS_DECIMAL = new QName(XS, "xs:decimal");
948

    
949
        /// <summary>QName constant for the name xs:boolean</summary>
950
        public static readonly QName XS_BOOLEAN = new QName(XS, "xs:boolean");
951

    
952
        /// <summary>QName constant for the name xs:anyURI</summary>
953
        public static readonly QName XS_ANYURI = new QName(XS, "xs:anyURI");
954

    
955
        /// <summary>QName constant for the name xs:QName</summary>
956
        public static readonly QName XS_QNAME = new QName(XS, "xs:QName");
957

    
958
        /// <summary>QName constant for the name xs:untypedAtomic</summary>
959
        public static readonly QName XS_UNTYPED_ATOMIC = new QName(XS, "xdt:untypedAtomic");
960

    
961
        /// <summary>QName constant for the name xs:untypedAtomic (for backwards compatibility)</summary>
962
        public static readonly QName XDT_UNTYPED_ATOMIC = new QName(XS, "xdt:untypedAtomic");
963

    
964
        /// <summary>
965
        /// Construct a QName using a namespace URI and a lexical representation.
966
        /// The lexical representation may be a local name on its own, or it may 
967
        /// be in the form <c>prefix:local-name</c>
968
        /// </summary>
969
        /// <remarks>
970
        /// This constructor does not check that the components of the QName are
971
        /// lexically valid.
972
        /// </remarks>
973
        /// <param name="uri">The namespace URI. Use either the string "" or null
974
        /// for names that are not in any namespace.
975
        /// </param>
976
        /// <param name="lexical">Either the local part of the name, or the prefix
977
        /// and local part in the format <c>prefix:local</c>
978
        /// </param>
979

    
980
        public QName(String uri, String lexical)
981
        {
982
            // TODO: check for validity
983
            this.uri = (uri == null ? "" : uri);
984
            int colon = lexical.IndexOf(':');
985
            if (colon < 0)
986
            {
987
                this.prefix = "";
988
                this.local = lexical;
989
            }
990
            else
991
            {
992
                this.prefix = lexical.Substring(0, colon);
993
                this.local = lexical.Substring(colon + 1);
994
            }
995
        }
996

    
997
        /// <summary>
998
        /// Construct a QName using a namespace prefix, a namespace URI, and a local name
999
        /// (in that order).
1000
        /// </summary>
1001
        /// <remarks>
1002
        /// This constructor does not check that the components of the QName are
1003
        /// lexically valid.
1004
        /// </remarks>
1005
        /// <param name="prefix">The prefix of the name. Use either the string ""
1006
        /// or null for names that have no prefix (that is, they are in the default
1007
        /// namespace)</param>
1008
        /// <param name="uri">The namespace URI. Use either the string "" or null
1009
        /// for names that are not in any namespace.
1010
        /// </param>
1011
        /// <param name="local">The local part of the name</param>
1012

    
1013
        public QName(String prefix, String uri, String local)
1014
        {
1015
            this.uri = (uri == null ? String.Empty : uri);
1016
            this.local = local;
1017
            this.prefix = (prefix == null ? String.Empty : prefix);
1018
        }
1019

    
1020
        /// <summary>
1021
        /// Construct a QName from a lexical QName, supplying an element node whose
1022
        /// in-scope namespaces are to be used to resolve any prefix contained in the QName.
1023
        /// </summary>
1024
        /// <remarks>
1025
        /// <para>This constructor checks that the components of the QName are
1026
        /// lexically valid.</para>
1027
        /// <para>If the lexical QName has no prefix, the name is considered to be in the
1028
        /// default namespace, as defined by <c>xmlns="..."</c>.</para>
1029
        /// <para>If the prefix of the lexical QName is not in scope, returns null.</para>
1030
        /// </remarks>
1031
        /// <param name="lexicalQName">The lexical QName, in the form <code>prefix:local</code>
1032
        /// or simply <c>local</c>.</param>
1033
        /// <param name="element">The element node whose in-scope namespaces are to be used
1034
        /// to resolve the prefix part of the lexical QName.</param>
1035
        /// <exception cref="ArgumentException">If the prefix of the lexical QName is not in scope</exception>
1036
        /// <exception cref="ArgumentException">If the lexical QName is invalid 
1037
        /// (for example, if it contains invalid characters)</exception>
1038
        /// 
1039

    
1040
        public QName(String lexicalQName, XdmNode element)
1041
        {
1042
            try
1043
            {
1044
                NodeInfo node = (NodeInfo)element.value;
1045
                NamePool pool = node.getConfiguration().getNamePool();
1046
                int nc = pool.allocateLexicalQName(lexicalQName, true, new InscopeNamespaceResolver(node),
1047
                    node.getConfiguration().getNameChecker());
1048
                this.uri = pool.getURI(nc);
1049
                this.local = pool.getLocalName(nc);
1050
                this.prefix = pool.getPrefix(nc);
1051
            }
1052
            catch (net.sf.saxon.trans.XPathException err)
1053
            {
1054
                throw new ArgumentException(err.getMessage());
1055
            }
1056
        }
1057

    
1058
        /// <summary>
1059
        /// Construct a <c>QName</c> from an <c>XmlQualifiedName</c> (as defined in the
1060
        /// <c>System.Xml</c> package).
1061
        /// </summary>
1062
        /// <remarks>
1063
        /// Note that an <c>XmlQualifiedName</c> does not contain any prefix, so the result
1064
        /// will always have a prefix of ""
1065
        /// </remarks>
1066
        /// <param name="qualifiedName">The XmlQualifiedName</param>
1067

    
1068
        public QName(XmlQualifiedName qualifiedName)
1069
        {
1070
            this.uri = qualifiedName.Namespace;
1071
            this.local = qualifiedName.Name;
1072
            this.prefix = String.Empty;
1073
        }
1074

    
1075
        //  internal constructor from a QNameValue
1076

    
1077
        internal QName(QNameValue q)
1078
        {
1079
            this.uri = q.getNamespaceURI();
1080
            this.prefix = q.getPrefix();
1081
            this.local = q.getLocalName();
1082
        }
1083

    
1084
        /// <summary>
1085
        /// Factory method to construct a QName from a string containing the expanded
1086
        /// QName in Clark notation, that is, <c>{uri}local</c>
1087
        /// </summary>
1088
        /// <remarks>
1089
        /// The prefix part of the <c>QName</c> will be set to an empty string.
1090
        /// </remarks>
1091
        /// <param name="expandedName">The URI in Clark notation: <c>{uri}local</c> if the
1092
        /// name is in a namespace, or simply <c>local</c> if not.</param> 
1093

    
1094
        public static QName FromClarkName(String expandedName)
1095
        {
1096
            String namespaceURI;
1097
            String localName;
1098
            if (expandedName[0] == '{')
1099
            {
1100
                int closeBrace = expandedName.IndexOf('}');
1101
                if (closeBrace < 0)
1102
                {
1103
                    throw new ArgumentException("No closing '}' in Clark name");
1104
                }
1105
                namespaceURI = expandedName.Substring(1, closeBrace - 1);
1106
                if (closeBrace == expandedName.Length)
1107
                {
1108
                    throw new ArgumentException("Missing local part in Clark name");
1109
                }
1110
                localName = expandedName.Substring(closeBrace + 1);
1111
            }
1112
            else
1113
            {
1114
                namespaceURI = "";
1115
                localName = expandedName;
1116
            }
1117

    
1118
            return new QName("", namespaceURI, localName);
1119
        }
1120

    
1121
        /// <summary>
1122
        /// Register a QName with the <c>Processor</c>. This makes comparison faster
1123
        /// when the QName is compared with others that are also registered with the <c>Processor</c>.
1124
        /// </summary>
1125
        /// <param name="processor">The Processor in which the name is to be registered.</param>
1126

    
1127
        public void Register(Processor processor)
1128
        {
1129
            pool = processor.config.getNamePool();
1130
            fingerprint = pool.allocate(prefix, uri, local) & 0xfffff;
1131
        }
1132

    
1133
        /// <summary>
1134
        /// Validate the QName against the XML 1.0 or XML 1.1 rules for valid names.
1135
        /// </summary>
1136
        /// <param name="processor">The Processor in which the name is to be validated.
1137
        /// This determines whether the XML 1.0 or XML 1.1 rules for forming names are used.</param>
1138
        /// <returns>true if the name is valid, false if not</returns>
1139

    
1140
        public bool IsValid(Processor processor)
1141
        {
1142
            NameChecker nc = processor.config.getNameChecker();
1143
            if (prefix != String.Empty)
1144
            {
1145
                if (!nc.isValidNCName(prefix))
1146
                {
1147
                    return false;
1148
                }
1149
            }
1150
            if (!nc.isValidNCName(local))
1151
            {
1152
                return false;
1153
            }
1154
            return true;
1155
        }
1156

    
1157
        /// <summary>The prefix of the QName. This plays no role in operations such as comparison
1158
        /// of QNames for equality, but is retained (as specified in XPath) so that a string representation
1159
        /// can be reconstructed.
1160
        /// </summary>
1161
        /// <remarks>
1162
        /// Returns the zero-length string in the case of a QName that has no prefix.
1163
        /// </remarks>
1164

    
1165
        public String Prefix
1166
        {
1167
            get { return prefix; }
1168
        }
1169

    
1170
        /// <summary>The namespace URI of the QName. Returns "" (the zero-length string) if the
1171
        /// QName is not in a namespace.
1172
        /// </summary>
1173

    
1174
        public String Uri
1175
        {
1176
            get { return uri; }
1177
        }
1178

    
1179
        /// <summary>The local part of the QName</summary>
1180

    
1181
        public String LocalName
1182
        {
1183
            get { return local; }
1184
        }
1185

    
1186
        /// <summary>The expanded name, as a string using the notation devised by James Clark.
1187
        /// If the name is in a namespace, the resulting string takes the form <c>{uri}local</c>.
1188
        /// Otherwise, the value is the local part of the name.
1189
        /// </summary>
1190

    
1191
        public String ClarkName
1192
        {
1193
            get
1194
            {
1195
                if (uri == "")
1196
                {
1197
                    return local;
1198
                }
1199
                else
1200
                {
1201
                    return "{" + uri + "}" + local;
1202
                }
1203
            }
1204
        }
1205

    
1206
        /// <summary>
1207
        /// Convert the value to a string. The resulting string is the lexical form of the QName,
1208
        /// using the original prefix if there was one.
1209
        /// </summary>
1210

    
1211
        public override String ToString()
1212
        {
1213
            if (prefix == "")
1214
            {
1215
                return local;
1216
            }
1217
            else
1218
            {
1219
                return prefix + ":" + uri;
1220
            }
1221
        }
1222

    
1223
        /// <summary>
1224
        /// Get a hash code for the QName, to support equality matching. This supports the
1225
        /// semantics of equality, which considers only the namespace URI and local name, and
1226
        /// not the prefix.
1227
        /// </summary>
1228
        /// <remarks>
1229
        /// The algorithm for allocating a hash code does not depend on registering the QName 
1230
        /// with the <c>Processor</c>.
1231
        /// </remarks>
1232

    
1233
        public override int GetHashCode()
1234
        {
1235
            if (hashcode == -1)
1236
            {
1237
                hashcode = ClarkName.GetHashCode();
1238
            }
1239
            return hashcode;
1240
        }
1241

    
1242
        /// <summary>
1243
        /// Test whether two QNames are equal. This supports the
1244
        /// semantics of equality, which considers only the namespace URI and local name, and
1245
        /// not the prefix.
1246
        /// </summary>
1247
        /// <remarks>
1248
        /// The result of the function does not depend on registering the QName 
1249
        /// with the <c>Processor</c>, but is computed more quickly if the QNames have
1250
        /// both been registered
1251
        /// </remarks>
1252
        /// <param name="other">The value to be compared with this QName. If this value is not a QName, the
1253
        /// result is always false. Otherwise, it is true if the namespace URI and local name both match.</param>
1254

    
1255
        public override bool Equals(Object other)
1256
        {
1257
            if (!(other is QName))
1258
            {
1259
                return false;
1260
            }
1261
            if (pool != null && pool == ((QName)other).pool)
1262
            {
1263
                return fingerprint == ((QName)other).fingerprint;
1264
            }
1265
            if (GetHashCode() != ((QName)other).GetHashCode())
1266
            {
1267
                return false;
1268
            }
1269
            return ClarkName == ((QName)other).ClarkName;
1270
            //TODO: avoid computing ClarkName more than once
1271
        }
1272

    
1273
        /// <summary>
1274
        /// Convert the value to an <c>XmlQualifiedName</c> (as defined in the
1275
        /// <c>System.Xml</c> package)
1276
        /// </summary>
1277
        /// <remarks>
1278
        /// Note that this loses the prefix.
1279
        /// </remarks>
1280

    
1281
        public XmlQualifiedName ToXmlQualifiedName()
1282
        {
1283
            return new XmlQualifiedName(local, uri);
1284
        }
1285

    
1286
        /// <summary>
1287
        /// Convert to a net.sf.saxon.value.QNameValue
1288
        /// </summary>
1289

    
1290
        internal QNameValue ToQNameValue()
1291
        {
1292
            return new QNameValue(prefix, uri, local, null);
1293
        }
1294

    
1295

    
1296
    }
1297

    
1298
    /// <summary>
1299
    /// This class represents an enumeration of the values in an XPath
1300
    /// sequence. It implements the IEnumerator interface, and the objects
1301
    /// returned are always instances of <c>XPathItem</c>
1302
    /// </summary>
1303
    /// <remarks>
1304
    /// Because the underlying value can be evaluated lazily, it is possible
1305
    /// for exceptions to occur as the sequence is being read.
1306
    /// </remarks>
1307

    
1308
    [Serializable]
1309
    public class SequenceEnumerator : IEnumerator
1310
    {
1311

    
1312
        private SequenceIterator iter;
1313

    
1314
        internal SequenceEnumerator(SequenceIterator iter)
1315
        {
1316
            this.iter = iter;
1317
        }
1318

    
1319
        /// <summary>Return the current item in the sequence</summary>
1320
        /// <returns>An object which will always be an instance of <c>XdmItem</c></returns>
1321

    
1322
        public object Current
1323
        {
1324
            get { return XdmValue.Wrap(iter.current()); }
1325
        }
1326

    
1327
        /// <summary>Move to the next item in the sequence</summary>
1328
        /// <returns>true if there are more items in the sequence</returns>
1329

    
1330
        public bool MoveNext()
1331
        {
1332
            return (iter.next() != null);
1333
        }
1334

    
1335
        /// <summary>Reset the enumeration so that the next call of
1336
        /// <c>MoveNext</c> will position the enumeration at the
1337
        /// first item in the sequence</summary>
1338

    
1339
        public void Reset()
1340
        {
1341
            iter = iter.getAnother();
1342
        }
1343
    }
1344

    
1345
    /// <summary>
1346
    /// Enumeration identifying the thirteen XPath axes
1347
    /// </summary>
1348

    
1349
    public enum XdmAxis
1350
    {
1351
        /// <summary>The XPath ancestor axis</summary> 
1352
        Ancestor,
1353
        /// <summary>The XPath ancestor-or-self axis</summary> 
1354
        AncestorOrSelf,
1355
        /// <summary>The XPath attribute axis</summary> 
1356
        Attribute,
1357
        /// <summary>The XPath child axis</summary> 
1358
        Child,
1359
        /// <summary>The XPath descendant axis</summary> 
1360
        Descendant,
1361
        /// <summary>The XPath descandant-or-self axis</summary> 
1362
        DescendantOrSelf,
1363
        /// <summary>The XPath following axis</summary> 
1364
        Following,
1365
        /// <summary>The XPath following-sibling axis</summary> 
1366
        FollowingSibling,
1367
        /// <summary>The XPath namespace axis</summary> 
1368
        Namespace,
1369
        /// <summary>The XPath parent axis</summary> 
1370
        Parent,
1371
        /// <summary>The XPath preceding axis</summary> 
1372
        Preceding,
1373
        /// <summary>The XPath preceding-sibling axis</summary> 
1374
        PrecedingSibling,
1375
        /// <summary>The XPath self axis</summary> 
1376
        Self
1377
    }
1378

    
1379
    internal class EmptyEnumerator : IEnumerator
1380
    {
1381

    
1382
        public static EmptyEnumerator INSTANCE = new EmptyEnumerator();
1383

    
1384
        private EmptyEnumerator() { }
1385

    
1386
        public void Reset() { }
1387

    
1388
        public object Current
1389
        {
1390
            get { throw new InvalidOperationException("Collection is empty."); }
1391
        }
1392

    
1393
        public bool MoveNext()
1394
        {
1395
            return false;
1396
        }
1397
    }
1398

    
1399

    
1400
}
1401

    
1402
//
1403
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1404
// you may not use this file except in compliance with the License. You may obtain a copy of the
1405
// License at http://www.mozilla.org/MPL/
1406
//
1407
// Software distributed under the License is distributed on an "AS IS" basis,
1408
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
1409
// See the License for the specific language governing rights and limitations under the License.
1410
//
1411
// The Original Code is: all this file.
1412
//
1413
// The Initial Developer of the Original Code is Michael H. Kay.
1414
//
1415
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1416
//
1417
// Contributor(s): none.
1418
//
(4-4/8)