Project

Profile

Help

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

he / latest9.9 / hen / csource / api / Saxon.Api / Model.cs @ aac4a1be

1
using System;
2
using System.Xml;
3
using System.Collections;
4
using System.Collections.Generic;
5
using JConfiguration = net.sf.saxon.Configuration;
6
using JNamePool = net.sf.saxon.om.NamePool;
7
using JAtomicValue = net.sf.saxon.value.AtomicValue;
8
using JFunction = net.sf.saxon.om.Function;
9
using JItem = net.sf.saxon.om.Item;
10
using JZeroOrOne = net.sf.saxon.om.ZeroOrOne;
11
using JOne = net.sf.saxon.om.One;
12
using JEmptySequence = net.sf.saxon.value.EmptySequence;
13
using JSequenceExtent = net.sf.saxon.value.SequenceExtent;
14
using JConversionResult = net.sf.saxon.type.ConversionResult;
15
using JValidationFailure = net.sf.saxon.type.ValidationFailure;
16
using JSequenceIterator = net.sf.saxon.om.SequenceIterator;
17
using JSequenceXdmIterator = net.sf.saxon.s9api.XdmSequenceIterator;
18
using JStandardNames = net.sf.saxon.om.StandardNames;
19
using JStructuredQName = net.sf.saxon.om.StructuredQName;
20
using JXPathContext = net.sf.saxon.expr.XPathContext;
21
using JDotNetReceiver = net.sf.saxon.dotnet.DotNetReceiver;
22
using JDotNetObjectValue = net.sf.saxon.dotnet.DotNetObjectValue;
23
using JBigDecimal = java.math.BigDecimal;
24
using JArrayList = java.util.ArrayList;
25
using JCharSequence = java.lang.CharSequence;
26
using JSequence = net.sf.saxon.om.Sequence;
27
using JNodeInfo = net.sf.saxon.om.NodeInfo;
28
using JAxisInfo = net.sf.saxon.om.AxisInfo;
29
using JInscopeNamespaceResolver = net.sf.saxon.om.InscopeNamespaceResolver;
30
using JNameChecker = net.sf.saxon.om.NameChecker;
31
using JSingletonIterator = net.sf.saxon.tree.iter.SingletonIterator;
32
using JQNameValue = net.sf.saxon.value.QNameValue;
33
using JStringValue = net.sf.saxon.value.StringValue;
34
using JInt64Value = net.sf.saxon.value.Int64Value;
35
using JBigDecimalValue = net.sf.saxon.value.BigDecimalValue;
36
using JFloatValue = net.sf.saxon.value.FloatValue;
37
using JDoubleValue = net.sf.saxon.value.DoubleValue;
38
using JBooleanValue = net.sf.saxon.value.BooleanValue;
39
using JAnyURIValue = net.sf.saxon.value.AnyURIValue;
40
using JNumericValue = net.sf.saxon.value.NumericValue;
41
using JStringToDouble11 = net.sf.saxon.value.StringToDouble11;
42
using JIntegerValue = net.sf.saxon.value.IntegerValue;
43
using JNameTest = net.sf.saxon.pattern.NameTest;
44
using JAtomicType = net.sf.saxon.type.AtomicType;
45
using JSchemaType = net.sf.saxon.type.SchemaType;
46
using JType = net.sf.saxon.type.Type;
47
using JStringToDouble = net.sf.saxon.type.StringToDouble;
48
using JSequenceTool = net.sf.saxon.om.SequenceTool;
49
using JExplicitLocation = net.sf.saxon.expr.parser.ExplicitLocation;
50
using JHashTrieMap = net.sf.saxon.ma.map.HashTrieMap;
51
using JMapItem = net.sf.saxon.ma.map.MapItem;
52
using JArrayItem = net.sf.saxon.ma.arrays.ArrayItem;
53
using JKeyValuePair = net.sf.saxon.ma.map.KeyValuePair;
54
using JSimpleArrayItem = net.sf.saxon.ma.arrays.SimpleArrayItem;
55
using JDecimalValue = net.sf.saxon.value.DecimalValue;
56
using JObjectValue = net.sf.saxon.value.ObjectValue;
57
using JGroundedValue = net.sf.saxon.om.GroundedValue;
58
using JQName = net.sf.saxon.s9api.QName;
59
using JItemConsumer = net.sf.saxon.om.ItemConsumer;
60
using JXdmValue = net.sf.saxon.s9api.XdmValue;
61

    
62
namespace Saxon.Api
63
{
64

    
65
    /// <summary>
66
    /// A value in the XDM data model. A value is a sequence of zero or more
67
    /// items, each item being an atomic value, a node, or a function item.
68
    /// </summary>
69
    /// <remarks>
70
    /// <para>An <c>XdmValue</c> is immutable.</para>
71
    /// <para>A sequence consisting of a single item <i>may</i> be represented
72
    /// as an instance of <see cref="XdmItem"/>, which is a subtype of <c>XdmValue</c>. However,
73
    /// there is no guarantee that all single-item sequences will be instances of
74
	/// <c>XdmItem</c>: if you want to ensure this, use the <see cref="Simplify"/> property.</para>
75
    /// <para>There are various ways of creating an <c>XdmValue</c>. To create an atomic
76
    /// value, use one of the constructors on <see cref="XdmAtomicValue"/> (which is a subtype of <c>XdmValue</c>).
77
    /// To construct an <see cref="XdmNode"/> (another subtype) by parsing an XML document, or by wrapping a DOM document,
78
	/// use a <see cref="DocumentBuilder"/>. To create a sequence of values, use the <see cref="Append(XdmValue)"/>
79
    /// method on this class to form a list from individual items or sublists.</para>
80
    /// <para>An <c>XdmValue</c> is also returned as the result of evaluating a query
81
    /// using the XQuery and XPath interfaces.</para>
82
    /// <para>The subtype <see cref="XdmEmptySequence"/> represents an empty sequence: an
83
    /// <c>XdmValue</c> of length zero. Again, there is no guarantee that every empty sequence
84
    /// will be represented as an instance of <c>XdmEmptySequence</c>, unless you use
85
    /// the <c>Simplify</c> property.</para>
86
    /// </remarks>
87

    
88
    [Serializable]
89
    public class XdmValue : IEnumerable<XdmItem>
90
    {
91

    
92
        internal JGroundedValue value;
93

    
94
        // Internal constructor
95

    
96
        internal XdmValue() { }
97

    
98
        /// <summary>
99
        /// Create a value from a collection of items
100
        /// </summary>
101
        /// <param name="items">An enumerable collection providing the items to make up the sequence. Every
102
        /// member of this collection must be an instance of <c>XdmItem</c>
103
        /// </param>
104

    
105
        public XdmValue(IEnumerable<XdmItem> items)
106
        {
107
            JArrayList list = new JArrayList();
108
            foreach (XdmItem c in items)
109
            {
110
                list.add((JItem)c.Unwrap());
111
            }
112
            value = JSequenceExtent.makeSequenceExtent(list);
113
        }
114

    
115
        /// <summary>
116
        /// Create a new <c>XdmValue</c> by concatenating the sequences of items in 
117
        /// this <c>XdmValue</c> and another <c>XdmValue</c>
118
        /// </summary>
119
        /// <remarks>
120
        /// Neither of the input <c>XdmValue</c> objects is modified by this operation
121
        /// </remarks>
122
        /// <param name="otherValue">
123
        /// The other <c>XdmValue</c>, whose items are to be appended to the items from this <c>XdmValue</c>
124
        /// </param>
125
        
126
        public XdmValue Append(XdmValue otherValue) {
127
            JArrayList list = new JArrayList();
128
            foreach (XdmItem item in this) {
129
                list.add(item.Unwrap());
130
            }
131
            foreach (XdmItem item in otherValue) {
132
                list.add(item.Unwrap());
133
            }
134
            JGroundedValue gv = JSequenceExtent.makeSequenceExtent(list);
135
            return FromGroundedValue(gv);
136
        }
137

    
138

    
139
        /// <summary>
140
        /// Create an <c>XdmValue</c> from an underlying Saxon <c>Sequence</c> object.
141
        /// This method is provided for the benefit of applications that need to mix
142
        /// use of the Saxon .NET API with direct use of the underlying objects
143
        /// and methods offered by the Java implementation.
144
        /// </summary>
145
        /// <param name="value">An object representing an XDM value in the
146
        /// underlying Saxon implementation. If the parameter is null,
147
        /// the method returns null.</param>
148
        /// <returns>An <c>XdmValue</c> that wraps the underlying Saxon XDM value
149
        /// representation.</returns>
150

    
151
        public static XdmValue Wrap(JSequence value)
152
        {
153
            if (value == null) {
154
                return XdmEmptySequence.INSTANCE;
155
            }
156
            JGroundedValue gv;
157
            try
158
            {
159
                gv = value.materialize();
160
            }
161
            catch (Exception e) {
162
                throw new DynamicError(e.Message);
163
            }
164
            XdmValue result;
165
            if (gv.getLength() == 0)
166
            {
167

    
168
                return XdmEmptySequence.INSTANCE;
169
            } else if (gv.getLength() == 1) {
170
                JItem first = gv.head();
171
                if (first is JAtomicValue)
172
                {
173
                    result = new XdmAtomicValue();
174
                    result.value = (JAtomicValue)first;
175
                    return result;
176
                }
177
                else if (first is JNodeInfo)
178
                {
179
                    result = new XdmNode();
180
                    result.value = (JNodeInfo)first;
181
                    return result;
182
                }
183
                else if (first is JZeroOrOne)
184
                {
185
                    return Wrap(((JZeroOrOne)value).head());
186
                }
187
                else if (first is JOne)
188
                {
189
                    return Wrap(((JOne)value).head());
190
                }
191
                else if (first is JMapItem)
192
                {
193
                    result = new XdmMap();
194
                    result.value = (JMapItem)first;
195
                    return result;
196
                }
197
                else if (first is JArrayItem)
198
                {
199
                    result = new XdmArray();
200
                    result.value = (JArrayItem)first;
201
                    return result;
202
                }
203
                else if (first is JFunction)
204
                {
205
                    result = new XdmFunctionItem();
206
                    result.value = (JFunction)first;
207
                    return result;
208
                }
209
                else if (first is JObjectValue)
210
                {
211
                    result = new XdmExternalObjectValue(((JObjectValue)first).getObject());
212
                    return result;
213
                }
214
                else {
215
                    result = new XdmValue();
216
                    result.value = first;
217
                    return result;
218
                }
219

    
220
            } 
221
            else
222
            {
223
                return FromGroundedValue(gv);
224
            }
225
            
226
        }
227

    
228
        static internal XdmValue FromGroundedValue(JGroundedValue value) {
229
            XdmValue result = new XdmValue();
230
            result.value = value;
231
            return result;
232
        }
233

    
234
        static internal JXdmValue FromGroundedValueToJXdmValue(JGroundedValue value) {
235
            return net.sf.saxon.s9api.XdmValue.wrap(value);
236
        }
237

    
238
        /// <summary>
239
        /// Make an XDM value from a .NET object. 
240
		/// </summary>
241
		/// <remarks>
242
		/// The supplied object may be any of the following:
243
        /// <list>
244
        /// <item>An instance of <c>XdmValue</c> (for example an <c>XdmAtomicValue</c>, 
245
        /// <c>XdmMap</c>, <c>XdmArray</c> or <c>XdmNode</c>), which is returned unchanged</item>
246
        /// <item>An instance of Saxon's Java class <c>net.sf.saxon.om.Sequence</c>, which is wrapped
247
        /// as an <c>XdmValue</c></item>
248
        /// <item>An instance of <c>IDictionary</c> (which is wrapped as an <c>XdmMap</c> using the method <see cref="XdmMap.MakeMap"/>)</item>
249
        /// <item>An array of objects, which are converted by applying these rules recursively,
250
		/// and then wrapped as an <c>XdmArray</c>.</item>
251
		/// </list>
252
		/// </remarks>
253
        /// <param name="o">The supplied object</param>
254
        /// <returns>the result of conversion if successful</returns>
255
        public static XdmValue MakeValue(object o) {
256
           
257
            if (o == null)
258
            {
259
                return null;
260
            }
261
            if (o is JSequence)
262
            {
263
                return XdmValue.Wrap((JSequence)o);
264
            }
265
            else if (o is XdmValue)
266
            {
267
                return (XdmValue)o;
268
            }
269
            else if (o is IDictionary)
270
            {
271
                return XdmMap.MakeMap((IDictionary)o);
272
            }
273
            else if (o.GetType().IsArray) {
274
                return XdmArray.MakeArray((object[])o);
275
            } else if (o is IEnumerable) {
276
                return XdmValue.MakeSequence((IEnumerable)o);
277
            }
278

    
279
            else
280
            {
281
                return XdmAtomicValue.MakeAtomicValue(o);
282

    
283
            }
284

    
285
        }
286

    
287
        private static XdmValue MakeSequence(IEnumerable o)
288
        {
289
            JArrayList list = new JArrayList();
290

    
291
            if (o is string)
292
            {
293
                return XdmAtomicValue.MakeAtomicValue((object)o);
294
            }
295
            foreach (object oi in o)
296
            {
297
                XdmValue v = XdmValue.MakeValue(oi);
298
                if (v is XdmItem)
299
                {
300
                    list.add((JItem)v.Unwrap());
301
                }
302
                else
303
                {
304
                    list.add(new XdmArray(v).Unwrap());
305
                }
306

    
307
            }
308
            JSequence value = new JSequenceExtent(list);
309
            return XdmValue.Wrap(value);
310
        }
311

    
312

    
313
        /// <summary>
314
        /// Extract the underlying Saxon <c>Sequence</c> object from an <c>XdmValue</c>.
315
        /// This method is provided for the benefit of applications that need to mix
316
        /// use of the Saxon .NET API with direct use of the underlying objects
317
        /// and methods offered by the Java implementation.
318
        /// </summary>
319
        /// <returns>An object representing the XDM value in the
320
        /// underlying Saxon implementation.</returns>
321

    
322

    
323
        public JSequence Unwrap()
324
        {
325
            return value;
326
        }
327

    
328
        /// <summary>
329
        /// Get the sequence of items in the form of an <c>IList</c>
330
        /// </summary>
331
        /// <returns>
332
        /// The list of items making up this XDM value. Each item in the list
333
        /// will be an object of type <c>XdmItem</c>
334
        /// </returns>        
335

    
336
        public IList<XdmItem> GetList()
337
        {
338
            if (value == null)
339
            {
340
                return new List<XdmItem>();
341
            }
342
            else if (value is JItem)
343
            {
344
                IList<XdmItem> list = new List<XdmItem>(1);
345
                list.Add((XdmItem)XdmValue.Wrap(value));
346
                return list;
347
            }
348
            else
349
            {
350
                IList<XdmItem> list = new List<XdmItem>();
351
                JSequenceIterator iter = value.iterate();
352
                while (true)
353
                {
354
                    JItem jitem = iter.next();
355
                    if (jitem == null)
356
                    {
357
                        break;
358
                    }
359
                    list.Add((XdmItem)XdmValue.Wrap(jitem));
360
                }
361
                return list;
362
            }
363
        }
364

    
365
        IEnumerator IEnumerable.GetEnumerator() {
366
            if (value == null)
367
            {
368
                return EmptyEnumerator<XdmItem>.INSTANCE;
369
            }
370
            else if (value is JItem)
371
            {
372
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(JSingletonIterator.makeIterator((JItem)value)));
373
            }
374
            else
375
            {
376
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(value.iterate()));
377
            }
378
        }
379

    
380
        /// <summary>
381
        /// Get the sequence of items in the form of an <c>IEnumerator</c>
382
        /// </summary>
383
        /// <returns>
384
        /// An enumeration over the list of items making up this XDM value. Each item in the list
385
        /// will be an object of type <c>XdmItem</c>
386
        /// </returns>    
387

    
388
       IEnumerator<XdmItem> IEnumerable<XdmItem>.GetEnumerator()
389
        {
390
            if (value == null)
391
            {
392
                return EmptyEnumerator<XdmItem>.INSTANCE;
393
            }
394
            else if (value is JItem)
395
            {
396
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(JSingletonIterator.makeIterator((JItem)value)));
397
            }
398
            else
399
            {
400
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(value.iterate()));
401
            }
402
        }
403

    
404

    
405
        /// <summary>
406
        /// Get the sequence of items in the form of an <c>IEnumerator</c>
407
        /// </summary>
408
        /// <returns>
409
        /// An enumeration over the list of items making up this XDM value. Each item in the list
410
        /// will be an object of type <c>XdmItem</c>
411
        /// </returns>    
412

    
413
        public IEnumerator<XdmItem> GetEnumerator()
414
        {
415
            if (value == null)
416
            {
417
                return EmptyEnumerator<XdmItem>.INSTANCE;
418
            }
419
            else if (value is JItem)
420
            {
421
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(JSingletonIterator.makeIterator((JItem)value)));
422
            }
423
            else
424
            {
425
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(value.iterate()));
426
            }
427
        }
428

    
429

    
430
        /// <summary>
431
        /// Get the i'th item in the value, counting from zero.
432
        /// </summary>
433
        /// <param name="i">the item that irequired, counting the first item in the sequence as item zero</param>
434
        /// <returns>the i'th item in the sequence making up the value, counting from zero.</returns>
435
        public XdmItem ItemAt(int i)
436
        {
437
            if (i < 0 || i >= Count) {
438
                throw new IndexOutOfRangeException("" + i);
439
            }
440
            try {
441
                JItem item = JSequenceTool.itemAt(value, i);
442
                return (XdmItem)XdmItem.Wrap(item);
443
            }
444
            catch (net.sf.saxon.trans.XPathException e) {
445
                throw new StaticError(e);
446
            }
447

    
448
        }
449

    
450

    
451

    
452
        /// <summary>
453
        /// Create a string representation of the value. The is the result of serializing
454
        /// the value using the adaptive serialization method.
455
        /// </summary>
456
        /// <returns>a string representation of the value</returns>
457
        public override String ToString() {
458
            return XdmValue.FromGroundedValueToJXdmValue(value).toString();
459

    
460
        }
461

    
462

    
463

    
464

    
465
        /// <summary>
466
        /// Return a new XdmValue containing the nodes present in this XdmValue,
467
        /// with duplicates eliminated, and sorted into document order
468
        /// </summary>
469
        /// <returns>the same nodes, sorted into document order, with duplicates eliminated</returns>
470
        public XdmValue DocumentOrder() {
471
            try
472
            {
473
                JSequenceIterator iter = value.iterate();
474
                JSequenceIterator sorted = new net.sf.saxon.expr.sort.DocumentOrderIterator(iter, net.sf.saxon.expr.sort.GlobalOrderComparer.getInstance());
475
                return XdmValue.Wrap(sorted.materialize());
476

    
477
            }
478
            catch (net.sf.saxon.trans.XPathException e) {
479
                throw new StaticError(e);
480
            }
481

    
482
        }
483

    
484
        /// <summary>
485
        /// Get the number of items in the sequence
486
        /// </summary>
487
        /// <returns>
488
        /// The number of items in the sequence. Note that for a single item (including
489
        /// a map or an array) this always returns 1 (one).
490
        /// </returns> 
491

    
492
        public int Count
493
        {
494
            get
495
            {
496
                if (value == null)
497
                {
498
                    return 0;
499
                }
500
                else if (value is JItem)
501
                {
502
                    return 1;
503
                }
504
                else
505
                {
506
                    return value.getLength();
507
                }
508
            }
509
        }
510

    
511
        /// <summary>
512
		/// Simplify an XDM value: that is, reduce it to the simplest possible form.
513
		/// </summary>
514
		/// <remarks>
515
        /// <list>
516
        /// <item>If the sequence is empty, the result will be an instance of <c>XdmEmptySequence</c></item>
517
        /// <item>If the sequence is a single node, the result will be an instance of <c>XdmNode</c></item>
518
        /// <item>If it is a single atomic value, it will be an instance of <c>XdmAtomicValue</c></item>
519
        /// <item>If it is a map, it will be an instance of <c>XdmMap</c></item>
520
        /// <item>If it is an array, it will be an instance of <c>XdmArray</c></item>
521
        /// <item>If it is any other kind of function, it will be an instance of <c>XdmFunctionItem</c></item>
522
        /// <item>If it is a wrapper around a .NET object, it will be an instance of <c>XdmExternalObjectValue</c></item>
523
        /// </list>
524
		/// </remarks>
525
		/// <returns>The XDM value reduced to the simplest possible form</returns>
526

    
527
        public XdmValue Simplify
528
        {
529
            get
530
            {
531
                switch (value.getLength())
532
                {
533
                    case 0:
534
                        if (this is XdmEmptySequence)
535
                        {
536
                            return this;
537
                        }
538
                        return XdmEmptySequence.INSTANCE;
539

    
540
                    case 1:
541
                        if (this is XdmItem)
542
                        {
543
                            return this;
544
                        }
545
                        return XdmValue.Wrap(value);
546

    
547
                    default:
548
                        return this;
549
                }
550
            }
551
        }
552

    
553
    }
554

    
555

    
556

    
557
    /// <summary inherits="XdmItem">
558
    /// The class <c>XdmExternalObjectValue</c> represents an XDM item that wraps an external .NET object.
559
    /// As such, it is outside the scope of the W3C XDM specification (but permitted as an extension).
560
    /// </summary>
561
    [Serializable]
562
    public class XdmExternalObjectValue : XdmItem
563
    {
564

    
565
        /// <summary>
566
        /// Constructor to create an <c>XdmExternalObjectValue</c> that wraps a supplied .NET object
567
        /// </summary>
568
        /// <param name="o">the supplied .NET object</param>
569
        public XdmExternalObjectValue(object o)
570
        {
571
            value = new JDotNetObjectValue(o);
572
        }
573

    
574
        /// <summary>
575
        /// Determine whether the item is an atomic value
576
        /// </summary>
577
        /// <returns>
578
        /// false (the item is not an atomic value)
579
        /// </returns>
580
        public override bool IsAtomic()
581
        {
582
            return false;
583
        }
584

    
585

    
586

    
587
        /// <summary>
588
        /// Compare two external objects for equality. Two instances of XdmExternalObjectValue are equal
589
        /// if the .NET objects that they wrap are equal.
590
        /// </summary>
591
        /// <param name="other">the object to be compared</param>
592
        /// <returns>tre if the other object is an XdmExternalObjectValue and the two wrapped objects are 
593
        /// equal under the equals method.</returns>
594
        public bool Equals(XdmExternalObjectValue other) {
595
            return other is XdmExternalObjectValue && value == other.value;
596
        }
597

    
598
        /// <summary>
599
        /// Return a hash code for the object. This respects the semantics of equals(Object)
600
        /// </summary>
601
        /// <returns>a suitable hash code</returns>
602
        public override int GetHashCode() {
603
            return ((java.lang.Object)value).hashCode();
604
        }
605

    
606
        /// <summary>
607
        /// Get the wrapped .NET object
608
        /// </summary>
609
        /// <returns>the wrapped object</returns>
610
        public object GetExternalObject()
611
        {
612
            return ((JObjectValue)value).getObject();
613
        }
614

    
615
        /// <summary>
616
        /// Get the result of converting the external value to a string.
617
        /// </summary>
618
        /// <returns>the result of applying <c>ToString()</c> to the wrapped external object</returns>
619
        public override string ToString()
620
        {
621
            return GetExternalObject().ToString();
622
        }
623
    }
624
    
625
    /// <summary inherits="XdmValue">
626
    /// The class <c>XdmItem</c> represents an item in a sequence, as defined
627
    /// by the XDM data model. An item may be an atomic value, a node, a function (including maps
628
    /// and arrays), or an external object.
629
    /// </summary>
630
    /// <remarks>
631
    /// <para>An item is a member of a sequence, but it can also be considered as
632
    /// a sequence (of length one) in its own right. <c>XdmItem</c> is a subtype
633
    /// of <c>XdmValue</c> because every item in the XDM data model is also a
634
    /// value.</para>
635
    /// <para>It cannot be assumed that every sequence of length one will always be 
636
    /// represented by an <c>XdmItem</c>. It is quite possible for an <c>XdmValue</c>
637
	/// that is not an <c>XdmItem</c> to hold a singleton sequence. Use <see cref="XdmValue.Simplify"/> 
638
    /// to ensure that a singleton is represented as an <c>XdmItem</c>.</para>
639
    /// </remarks> 
640

    
641
    [Serializable]
642
    public abstract class XdmItem : XdmValue
643
    {
644

    
645
        /// <summary>
646
        /// Determine whether the item is an atomic value
647
        /// </summary>
648
        /// <returns>
649
        /// true if the item is an atomic value, false if it is a node, function, or external object
650
        /// </returns>
651

    
652
        public abstract bool IsAtomic();
653
        
654
        /// <summary>
655
		/// Get the string value of the item. 
656
		/// </summary>
657
		/// <remarks>
658
        /// <list>
659
        /// <item>For an atomic value, the result is the same as casting the value to a string.</item>
660
        /// <item>For a node, the method returns the string
661
		/// value of the node. This is not the same as the result of <see cref="XdmNode.ToString()"/>, which
662
        /// returns the result of serializing the node.</item>
663
        /// <item>For a function, including a map or array, the result is an error.</item>
664
        /// <item>For an external object, the result is the same as the result of calling <c>ToString()</c>
665
        /// on the external object.</item>
666
		/// </list>
667
		/// <para>In all cases the result is the same as applying the XPath <c>string()</c> function.</para>
668
		/// </remarks>
669
        /// <returns>The result of converting the item to a string</returns>
670
        
671
        public String GetStringValue() {
672
            return ((JItem)value).getStringValue();
673
        }
674

    
675
        internal static net.sf.saxon.s9api.XdmItem FromXdmItemItemToJXdmItem(XdmItem value)
676
        {
677
            return (net.sf.saxon.s9api.XdmItem)net.sf.saxon.s9api.XdmValue.wrap(value== null ? null : value.value);
678
        }
679

    
680
        /// <summary>
681
        /// Determine whether this item matches a given item type
682
        /// </summary>
683
        /// <param name="typei">typei the item type to be tested against this item</param>
684
        /// <returns>true if the item matches this item type, false if it does not match.</returns>
685
        public bool Matches(XdmItemType typei)
686
        {
687
            return typei.Matches(this);
688
        }
689
    }
690

    
691
    /// <summary inherits="XdmItem">
692
    /// The class <c>XdmAtomicValue</c> represents an item in an XDM sequence
693
    /// that is an atomic value. The value may belong to any of the 19 primitive types
694
    /// defined in XML Schema, or to a type derived from these primitive types, or to 
695
    /// the XDM-specific type <c>xs:untypedAtomic</c>
696
    /// </summary>
697
    /// <remarks>
698
    /// Note that there is no guarantee that every <c>XdmValue</c> comprising a single
699
    /// atomic value will be an instance of this class. To force this, use the <c>Simplify</c>
700
    /// property of the <c>XdmValue</c>.
701
    /// </remarks>
702

    
703
    [Serializable]
704
    public class XdmAtomicValue : XdmItem
705
    {
706
		// Internal constructor
707

    
708
        internal XdmAtomicValue() { }
709

    
710
        /// <summary>
711
        /// Determine whether the item is an atomic value
712
        /// </summary>
713
        /// <returns>
714
        /// true (the item is an atomic value)
715
        /// </returns>
716

    
717
        public override bool IsAtomic()
718
        {
719
            return true;
720
        }
721

    
722
        /// <summary>
723
        /// Construct an atomic value of type <c>xs:string</c>
724
        /// </summary>
725
        /// <param name="str">The string value</param>
726

    
727
        public XdmAtomicValue(String str)
728
        {
729
            this.value = new JStringValue(str);
730
        }
731

    
732
        /// <summary>
733
        /// Construct an atomic value of type <c>xs:integer</c> from a supplied <c>long</c>
734
        /// </summary>
735
        /// <param name="i">The integer value</param>
736

    
737
        public XdmAtomicValue(long i)
738
        {
739
            this.value = JInt64Value.makeDerived(i, (JAtomicType)XdmAtomicType.LONG.Unwrap().getUnderlyingItemType());
740
        }
741

    
742

    
743
        /// <summary>
744
        /// Construct an atomic value of type <c>xs:integer</c> from a supplied <c>long</c>
745
        /// </summary>
746
        /// <param name="i">The integer value</param>
747

    
748
        public XdmAtomicValue(int i)
749
        {
750
            this.value = JInt64Value.makeDerived(i, (JAtomicType)XdmAtomicType.INT.Unwrap().getUnderlyingItemType());
751
        }
752

    
753
        /// <summary>
754
        /// Construct an atomic value of type <c>xs:integer</c> from a supplied <c>byte</c>
755
        /// </summary>
756
        /// <param name="i">The integer value, in the range -128 to +127</param>
757
        public XdmAtomicValue(byte i)
758
        {
759
            this.value = JInt64Value.makeDerived(i, (JAtomicType)XdmAtomicType.BYTE.Unwrap().getUnderlyingItemType());
760
        }
761

    
762
        /// <summary>
763
        /// Construct an atomic value of type <c>xs:decimal</c>
764
        /// </summary>
765
        /// <param name="d">The decimal value</param>
766

    
767
        public XdmAtomicValue(decimal d)
768
        {
769
            this.value = new JBigDecimalValue(new JBigDecimal(d.ToString(System.Globalization.CultureInfo.InvariantCulture)));
770
        }
771

    
772
        /// <summary>
773
        /// Construct an atomic value of type <c>xs:float</c>
774
        /// </summary>
775
        /// <param name="f">The float value</param>        
776

    
777
        public XdmAtomicValue(float f)
778
        {
779
            this.value = new JFloatValue(f);
780
        }
781

    
782
        /// <summary>
783
        /// Construct an atomic value of type <c>xs:double</c>
784
        /// </summary>
785
        /// <param name="d">The double value</param>
786

    
787
        public XdmAtomicValue(double d)
788
        {
789
            this.value = new JDoubleValue(d);
790
        }
791

    
792
        /// <summary>
793
        /// Construct an atomic value of type <c>xs:boolean</c>
794
        /// </summary>
795
        /// <param name="b">The boolean value</param>
796

    
797
        public XdmAtomicValue(bool b)
798
        {
799
            this.value = JBooleanValue.get(b);
800
        }
801

    
802
        /// <summary>
803
        /// Construct an atomic value of type <c>xs:anyURI</c>
804
        /// </summary>
805
        /// <param name="u">The uri value</param>
806

    
807
        public XdmAtomicValue(Uri u)
808
        {
809
            this.value = new JAnyURIValue(u.ToString());
810
        }
811

    
812
        /// <summary>
813
        /// Construct an atomic value of type <c>xs:QName</c>
814
        /// </summary>
815
        /// <param name="q">The QName value</param>                
816

    
817
        public XdmAtomicValue(QName q)
818
        {
819
            this.value = new JQNameValue(
820
                q.Prefix, q.Uri, q.LocalName);
821
		}
822

    
823
		/// <summary>
824
		/// Construct an atomic value of a given type
825
		/// </summary>
826
		/// <param name="lexicalForm">The string representation of the value (any value that is acceptable
827
		/// in the lexical space, as defined by XML Schema Part 2). Whitespace normalization as defined by
828
		/// the target type will be applied to the value.</param>
829
		/// <param name="type">The type given as an <c>XdmAtomicType</c></param>
830

    
831
        public XdmAtomicValue(String lexicalForm, XdmAtomicType type) {
832
            net.sf.saxon.type.ItemType it = type.Unwrap().getUnderlyingItemType();
833
            if (!it.isPlainType()) {
834
                throw new StaticError(new net.sf.saxon.s9api.SaxonApiException("Requested type is not atomic"));
835
            }
836
            if (((JAtomicType)it).isAbstract()) {
837
                throw new StaticError(new net.sf.saxon.s9api.SaxonApiException("Requested type is not namespace-sensitive"));
838

    
839
            }
840
            try
841
            {
842
                net.sf.saxon.type.StringConverter Converter = ((JAtomicType)it).getStringConverter(type.Unwrap().getConversionRules());
843
                this.value = Converter.convertString(lexicalForm).asAtomic();
844
            }
845
            catch (Exception ex) { }
846
            
847
        }
848

    
849
        /// <summary>
850
        /// Construct an atomic value of a given built-in or user-defined type
851
        /// </summary>
852
        /// <example>
853
        ///   <code>XdmAtomicValue("abcd", QName.XDT_UNTYPED_ATOMIC, processor)</code>
854
        ///   <para>creates an untyped atomic value containing the string "abcd"</para>
855
        /// </example>
856
        /// <param name="lexicalForm">The string representation of the value (any value that is acceptable
857
        /// in the lexical space, as defined by XML Schema Part 2). Whitespace normalization as defined by
858
        /// the target type will be applied to the value.</param>
859
        /// <param name="type">The QName giving the name of the target type. This must be an atomic
860
        /// type, and it must not be a type that is namespace-sensitive (QName, NOTATION, or types derived
861
        /// from these). If the type is a user-defined type then its definition must be present
862
        /// in the schema cache maintained by the <c>SchemaManager</c>.</param> 
863
        /// <param name="processor">The <c>Processor</c> object. This is needed for looking up user-defined
864
        /// types, and also because some conversions are context-sensitive, for example they depend on the
865
        /// implicit timezone or the choice of XML 1.0 versus XML 1.1 for validating names.</param>
866
        /// <exception cref="ArgumentException">Thrown if the type is unknown or unsuitable, or if the supplied string is not
867
        /// a valid lexical representation of a value of the given type.</exception>
868

    
869
        public XdmAtomicValue(String lexicalForm, QName type, Processor processor)
870
        {
871
			JConfiguration jconfig = processor.Implementation;
872
            int fp = jconfig.getNamePool().getFingerprint(type.Uri, type.LocalName);
873
            if (fp == -1)
874
            {
875
                throw new ArgumentException("Unknown name " + type);
876
            }
877
			JSchemaType st = jconfig.getSchemaType(new JStructuredQName("", type.Uri.ToString(), type.LocalName));
878
            if (st == null)
879
            {
880
                throw new ArgumentException("Unknown type " + type);
881
            }
882
            if (!(st is JAtomicType))
883
            {
884
                throw new ArgumentException("Specified type " + type + " is not atomic");
885
            }
886
            if (((JAtomicType)st).isNamespaceSensitive())
887
            {
888
                throw new ArgumentException("Specified type " + type + " is namespace-sensitive");
889
            }
890
			JConversionResult result = ((JAtomicType)st).getStringConverter(jconfig.getConversionRules()).convertString((JCharSequence)lexicalForm);
891
 
892
            if (result is JValidationFailure)
893
            {
894
                throw new ArgumentException(((JValidationFailure)result).getMessage());
895
            }
896
            this.value = (JAtomicValue)result;
897
        }
898

    
899

    
900
        
901
        /// <summary>
902
		/// Create an atomic value of a type appropriate to the supplied value. 
903
		/// </summary>
904
		/// <remarks>
905
		/// The supplied value must be one of the following:
906
        /// <list>
907
        /// <item>An instance of the Saxon Java class <c>net.sf.saxon.value.AtomicValue</c></item>
908
        /// <item>A <c>Boolean</c> - returns an instance of <c>xs:boolean</c></item>
909
        /// <item>A (signed) <c>int</c>, <c>long</c>, <c>short</c>, or <c>byte</c> - returns an instance of <c>xs:integer</c></item>
910
        /// <item>A <c>Char</c> - TODO ???????</item>
911
        /// <item>A <c>String</c> - returns an instance of <c>xs:string</c></item>
912
        /// <item>A <c>Double</c> - returns an instance of <c>xs:double</c></item>
913
        /// <item>A <c>Float</c> - returns an instance of <c>xs:float</c></item>
914
        /// <item>A <c>decimal</c> - returns an instance of <c>xs:decimal</c></item>
915
        /// <item>A <c>URI</c> - returns an instance of <c>xs:anyURI</c></item>
916
        /// <item>A <c>QName</c> - returns an instance of <c>xs:QName</c></item>
917
        /// </list>
918
		/// </remarks>
919
        /// <param name="value">The value to be converted.</param>
920
        /// <returns>The converted value</returns>
921

    
922
        public static XdmAtomicValue MakeAtomicValue(object value)
923
        {
924
            if (value is JAtomicValue)
925
            {
926
                return (XdmAtomicValue)XdmValue.Wrap((JAtomicValue)value);
927
            }
928
            else if (value is Boolean)
929
            {
930
                return new XdmAtomicValue((Boolean)value);
931
            }
932
            else if (value is int)
933
            {
934
                return new XdmAtomicValue((int)value);
935
            }
936
            else if (value is long)
937
            {
938
                return new XdmAtomicValue((long)value);
939
            }
940
            else if (value is short)
941
            {
942
                return new XdmAtomicValue((short)value);
943
            }
944
            else if (value is Char)
945
            {
946
                return new XdmAtomicValue((long)value);
947
            }
948
            else if (value is Byte)
949
            {
950
                return new XdmAtomicValue((Byte)value);
951
            }
952
            else if (value is String)
953
            {
954
                return new XdmAtomicValue((String)value);
955
            }
956
            else if (value is Double)
957
            {
958
                return new XdmAtomicValue((Double)value);
959
            }
960
            else if (value is float)
961
            {
962
                return new XdmAtomicValue((float)value);
963
            }
964
            else if (value is decimal)
965
            {
966
                return new XdmAtomicValue((decimal)value);
967
            }
968
            else if (value is Uri)
969
            {
970
                return new XdmAtomicValue((Uri)value);
971
            }
972
            else if (value is QName)
973
            {
974
                return new XdmAtomicValue((QName)value);
975
            }
976
            if (value is XdmAtomicValue)
977
            {
978
                return (XdmAtomicValue)value;
979
            }
980
            else
981
            {
982
                throw new ArgumentException(value.ToString());
983
            }
984
        }
985

    
986

    
987
        /// <summary>
988
        /// Get the value converted to a boolean using the XPath casting rules
989
        /// </summary>
990
        /// <returns>the result of converting to a boolean (Note: this is not the same as the
991
        /// effective boolean value).</returns> 
992

    
993
        public bool GetBooleanValue()
994
        {
995
            JAtomicValue av = (JAtomicValue)this.value;
996
            if (av is JBooleanValue) {
997
                return ((JBooleanValue)av).getBooleanValue();
998
            } else if (av is JNumericValue) {
999
                return !av.isNaN() && ((JNumericValue)av).signum() != 0;
1000
            } else if (av is JStringValue) {
1001
                String s = av.getStringValue().Trim();
1002
                return "1".Equals(s) || "true".Equals(s);
1003
            } else {
1004
                throw new ArgumentException("Cannot cast item to a boolean");
1005
            }
1006
        }
1007

    
1008

    
1009
        /// <summary>
1010
        /// Get the value converted to a long using the XPath casting rules
1011
        /// </summary>
1012
        /// <returns>the result of converting to a long</returns>
1013

    
1014
        public long GetLongValue()
1015
        {
1016
            JAtomicValue av = (JAtomicValue)this.value;
1017
            if (av is JBooleanValue) {
1018
                return ((JBooleanValue)av).getBooleanValue() ? 0L : 1L;
1019
            } else if (av is JNumericValue) {
1020
            try {
1021
                return ((JNumericValue)av).longValue();
1022
            } catch (Exception) {
1023
                throw new ArgumentException("Cannot cast item to an integer");
1024
            }
1025
            } else if (av is JStringValue) {
1026
                JStringToDouble converter = JStringToDouble.getInstance();
1027
                return (long)converter.stringToNumber(av.getStringValueCS());
1028
            } else {
1029
                throw new ArgumentException("Cannot cast item to an integer");
1030
            }
1031
        }
1032

    
1033

    
1034
        /// <summary>
1035
		/// Get the value converted to a double using the XPath casting rules.
1036
		/// </summary>
1037
        /// <remarks>If the value is a string, the XSD 1.1 rules are used, which means that the string
1038
		/// "+INF" is recognised.</remarks>
1039
        /// <returns>the result of converting to a double</returns>
1040

    
1041
        public double GetDoubleValue()
1042
        {
1043
            JAtomicValue av = (JAtomicValue)this.value;
1044
            if (av is JBooleanValue) {
1045
                return ((JBooleanValue)av).getBooleanValue() ? 0.0 : 1.0;
1046
            } else if (av is JNumericValue) {
1047
                return ((JNumericValue)av).getDoubleValue();
1048
            } else if (av is JStringValue) {
1049
            try {
1050
                JStringToDouble converter = JStringToDouble11.getInstance();
1051
                return converter.stringToNumber(av.getStringValueCS());
1052
            } catch (Exception e) {
1053
                throw new ArgumentException(e.Message);
1054
            }
1055
            } else {
1056
                throw new ArgumentException("Cannot cast item to a double");
1057
            }
1058
        }
1059

    
1060

    
1061
        /// <summary>
1062
        /// Get the value converted to a decimal using the XPath casting rules
1063
        /// </summary>
1064
        /// <returns>the result of converting to a decimal</returns>
1065

    
1066
        public Decimal GetDecimalValue() 
1067
        {
1068
            JAtomicValue av = (JAtomicValue)this.value;
1069
            if (av is JBooleanValue) {
1070
                return ((JBooleanValue)av).getBooleanValue() ? 0  : 1;
1071
            } else if (av is JNumericValue) {
1072
                try {
1073
                    return Convert.ToDecimal(((JNumericValue)av).getDecimalValue().toString());
1074
                } catch (Exception) {
1075
                    throw new ArgumentException("Cannot cast item to a decimal");
1076
                }   
1077
            } else if (av is JStringValue) {
1078
                return Convert.ToDecimal(av.getStringValueCS().toString());
1079
            } else {
1080
                throw new ArgumentException("Cannot cast item to a decimal");
1081
            }
1082
        }
1083

    
1084

    
1085

    
1086
        /// <summary>
1087
        /// Convert the atomic value to a string
1088
        /// </summary>
1089
        /// <returns>The value converted to a string, according to the rules
1090
        /// of the XPath cast expression</returns>        
1091

    
1092
        public override String ToString()
1093
        {
1094
            return ((JAtomicValue)value).getStringValue();
1095
        }
1096
        
1097
        /// <summary>
1098
        /// Compare two atomic values for equality
1099
        /// </summary>
1100
        /// <returns>The result of the equality comparison, using the rules of the
1101
		/// <c>op:is-same-key()</c> comparison used for comparing key values in maps</returns>
1102
        
1103
        public override Boolean Equals(object other)
1104
        {
1105
            if (other is XdmAtomicValue)
1106
            {
1107
                return ((JAtomicValue)value).asMapKey().Equals(((JAtomicValue)((XdmAtomicValue)other).value).asMapKey());
1108

    
1109
            }
1110
            else
1111
            {
1112
                return false;
1113
            }
1114
        }
1115
        
1116
        /// <summary>
1117
        /// Get a hash code to support equality comparison
1118
        /// </summary>
1119
        /// <returns>A suitable hash code</returns>
1120
        
1121
        public override int GetHashCode()
1122
        {
1123
            return ((JAtomicValue)value).asMapKey().GetHashCode();
1124
        }         
1125

    
1126
        /// <summary>
1127
        /// Get the name of the value's XDM type
1128
        /// </summary>
1129
		/// <returns>The type of the value, as a QName.</returns>
1130

    
1131

    
1132
        public QName GetTypeName()
1133
        {
1134
            JStructuredQName sqname = ((JAtomicValue)value).getItemType().getStructuredQName();
1135
            return new QName(sqname.getPrefix(),
1136
                             sqname.getURI(),
1137
                             sqname.getLocalPart());
1138
        }
1139
        
1140
        /// <summary>
1141
        /// Get the name of the value's XDM type
1142
        /// </summary>
1143
        /// <param name="processor">The <code>Processor</code> object. 
1144
        /// This parameter is no longer used, but is accepted for backwards compatibility.</param>
1145
		/// <returns>The type of the value, as a QName.</returns>
1146

    
1147

    
1148
        public QName GetTypeName(Processor processor)
1149
        {
1150
            return GetTypeName();
1151
        }
1152

    
1153
        /// <summary>
1154
        /// Get the name of the primitive type of the value
1155
        /// </summary>
1156
        /// <returns>The primitive type of the value, as a QName. This will be the name of
1157
        /// one of the primitive types defined in XML Schema Part 2, or the XPath-defined
1158
        /// type <c>xs:untypedAtomic</c>. For the purposes of this method, <c>xs:integer</c> is considered
1159
        /// to be a primitive type.
1160
        /// </returns>
1161

    
1162

    
1163
        public QName GetPrimitiveTypeName()
1164
        {
1165
            int fp = ((JAtomicValue)value).getItemType().getPrimitiveType();
1166
            return new QName(JStandardNames.getPrefix(fp),
1167
                             JStandardNames.getURI(fp),
1168
                             JStandardNames.getLocalName(fp));
1169
        }
1170

    
1171
        /// <summary>Get the value as a CLI object of the nearest equivalent type.</summary>
1172
        /// <remarks>
1173
        /// <para>The return type is as follows:</para>
1174
        /// <list>
1175
		/// <item><c>xs:string</c> - String</item>
1176
		/// <item><c>xs:integer</c> - Long</item>
1177
		/// <item><c>xs:decimal</c> - Decimal</item>
1178
		/// <item><c>xs:double</c> - Double</item>
1179
		/// <item><c>xs:float</c> - Float</item>
1180
		/// <item><c>xs:boolean</c> - Bool</item>
1181
		/// <item><c>xs:QName</c> - QName</item>
1182
		/// <item><c>xs:anyURI</c> - Uri</item>
1183
		/// <item><c>xs:untypedAtomic</c> - String</item>
1184
        /// <item>wrapped external object - the original external object</item>
1185
        /// <item>Other types - currently String, but this may change in the future</item>
1186
        /// </list>
1187
        /// </remarks>
1188
        /// <returns>The value converted to the most appropriate CLI type</returns>
1189

    
1190
        public Object Value
1191
        {
1192
            get
1193
            {
1194
                if (value is JIntegerValue)
1195
                {
1196
                    return ((JIntegerValue)value).longValue();
1197
                }
1198
                else if (value is JDoubleValue)
1199
                {
1200
                    return ((JDoubleValue)value).getDoubleValue();
1201
                }
1202
                else if (value is JFloatValue)
1203
                {
1204
                    return ((JFloatValue)value).getFloatValue();
1205
                }
1206
                else if (value is JDecimalValue)
1207
                {
1208
                    return Decimal.Parse(((JDecimalValue)value).getStringValue());
1209
                }
1210
                else if (value is JBooleanValue)
1211
                {
1212
                    return ((JBooleanValue)value).getBooleanValue();
1213
                }
1214
                else if (value is JAnyURIValue)
1215
                {
1216
                    return new Uri(((JAnyURIValue)value).getStringValue());
1217
                }
1218
                else if (value is JQNameValue)
1219
                {
1220
                    return new QName((JQNameValue)value);
1221
                }
1222
                else if (value is JDotNetObjectValue) // TODO: can't happen?
1223
                {
1224
                    return ((JDotNetObjectValue)value).getObject();
1225
                }
1226
                else
1227
                {
1228
                    return ((JAtomicValue)value).getStringValue();
1229
                }
1230
            }
1231
        }
1232

    
1233

    
1234
    }
1235

    
1236
    /// <summary inherits="XdmItem">
1237
    /// The class <c>XdmFunctionItem</c> represents an item in an XDM sequence
1238
    /// that holds a function.
1239
    /// </summary>
1240
    /// <remarks>
1241
    /// <para>Note that there is no guarantee that every <c>XdmValue</c> comprising a single
1242
    /// function item will be an instance of this class. To force this, use the <c>Simplify</c>
1243
    /// property of the <c>XdmValue</c>.</para>
1244
    /// <para>At present the only way of creating an instance of this class is as the result of
1245
    /// an XPath or XQuery expression that returns a function item.</para>
1246
    /// </remarks>
1247

    
1248
    [Serializable]
1249
    public class XdmFunctionItem : XdmItem
1250
    {
1251
        /// <summary>
1252
        /// The name of the function, as a QName
1253
        /// </summary>
1254
		/// <returns>The name of the function. The result will be null if the function is anonymous.</returns>
1255
        
1256
        public QName FunctionName
1257
        {
1258
            get
1259
            {
1260
                JStructuredQName sqname = ((JFunction)value).getFunctionName();
1261
                return (sqname == null ? null : QName.FromStructuredQName(sqname));
1262
            }
1263
        }
1264

    
1265
        /// <summary>
1266
        /// The arity of the function, that is, the number of arguments it expects
1267
        /// </summary>
1268
		/// <returns>The number of arguments that the function takes</returns>
1269

    
1270
        public int Arity
1271
        {
1272
            get
1273
            {
1274
                return ((JFunction)value).getArity();
1275
            }
1276
        }
1277

    
1278
        /// <summary>
1279
        /// Determine whether the item is an atomic value
1280
        /// </summary>
1281
        /// <returns>
1282
        /// false (a function item is not an atomic value)
1283
        /// </returns>
1284

    
1285
        public override bool IsAtomic()
1286
        {
1287
            return false;
1288
        }
1289

    
1290

    
1291
            /// <summary>
1292
            /// Invoke the function
1293
            /// </summary>
1294
            /// <param name="arguments">The arguments to the function</param>
1295
            /// <param name="processor">The Saxon processor, used to provide context information</param>
1296
            /// <returns>The result of calling the function</returns>
1297
            /// 
1298
            public XdmValue Invoke(XdmValue[] arguments, Processor processor)
1299
        {
1300
            JXdmValue[] args = new JXdmValue[arguments.Length];
1301
            for (int i = 0; i < arguments.Length; i++)
1302
            {
1303
                args[i] = FromGroundedValueToJXdmValue(arguments[i].value);
1304
            }
1305
            JFunction function = (JFunction)value;
1306
            net.sf.saxon.s9api.XdmFunctionItem functionItem = new net.sf.saxon.s9api.XdmFunctionItem(function);
1307
            JXdmValue result = functionItem.call(processor.JProcessor, args);
1308
           
1309
            return XdmValue.Wrap(result.getUnderlyingValue());
1310
        }
1311
    }
1312

    
1313
    /// <summary inherits="XdmFunctionItem">
1314
    /// The class <c>XdmArray</c> represents an array item in an XDM 3.1 sequence:
1315
    /// this is a new kind of item in the XDM data model. An array is a list of zero or 
1316
    /// more members, each of which is an arbitrary XDM value. An array is also a function:
1317
    /// it maps a positive integer to the array member found at that position in the array.
1318
    /// </summary>
1319
    [Serializable]
1320
    public class XdmArray : XdmFunctionItem
1321
    {
1322

    
1323

    
1324
		///<summary> Constructor to create an empty <c>XdmArray</c></summary>
1325
        public XdmArray() {
1326
            this.value = JSimpleArrayItem.EMPTY_ARRAY;
1327
        }
1328

    
1329
        ///<summary>Create an <c>XdmArray</c> whose members are single items, corresponding
1330
        ///one-to-one with the items making up a supplied sequence.</summary>
1331
        ///<param name="value">A sequence of items; each item becomes a member of the array.</param>
1332
        public XdmArray(XdmValue value)
1333
        {
1334
            int length = value.Count;
1335
            JArrayList list = new JArrayList(length);
1336
            foreach (XdmItem item in value.GetList())
1337
            {
1338
                list.add(item.Unwrap());
1339
            }
1340
            this.value = new JSimpleArrayItem(list);
1341
        }
1342

    
1343
        ///<summary> Create an <c>XdmArray</c> supplying the members as an array of <c>XdmValue</c> objects.</summary>
1344
        /// <param name="members">An array of <c>XdmValue</c> objects. Note that subsequent changes 
1345
        /// to the array will have no effect on the <c>XdmArray</c>.</param>
1346

    
1347

    
1348
        public XdmArray(XdmValue[] members) {
1349
            JArrayList list = new JArrayList(members.Length);
1350
            for (int i =0; i< members.Length;i++) {
1351
                list.add(members[i].Unwrap());
1352
            }
1353
            this.value = new JSimpleArrayItem(list);
1354
        }
1355

    
1356
		// Internal constructor
1357

    
1358
        internal XdmArray(JArrayList list)
1359
        {
1360
            this.value = new JSimpleArrayItem(list);
1361
        }
1362

    
1363
		// Internal constructor
1364

    
1365
        internal XdmArray(JArrayItem array) {
1366
            this.value = array;
1367
        }
1368

    
1369

    
1370
        /// <summary>Create an <c>XdmArray</c> supplying the members as a list of <c>XdmValue</c> objects</summary>
1371
        /// <param name="members">A sequence of <c>XdmValue</c> objects. Note that if this is supplied as 
1372
        /// a list or similar collection, subsequent changes to the list/collection will have no effect on 
1373
		/// the <c>XdmValue</c>.</param>
1374
		/// <remarks>Note that the argument can be a single <c>XdmValue</c> representing a sequence, in which case the
1375
        ///  constructed array will have one member for each item in the supplied sequence.</remarks>
1376
    
1377
        public XdmArray(List<XdmValue> members) {
1378
            JArrayList list = new JArrayList(members.Count);
1379
            for (int i = 0; i < members.Count; i++)
1380
            {
1381
                list.add(members[i].Unwrap());
1382
            }
1383
            this.value = new JSimpleArrayItem(list);
1384
        }
1385

    
1386
        /// <summary>
1387
        /// Get the number of members in the array
1388
        /// </summary>
1389
        /// <returns>the number of members in the array.</returns> 
1390
		/// <remarks>(Note that the <see cref="XdmValue.Count"/> property returns 1 (one),
1391
        /// because an XDM array is an item.)</remarks>
1392
        public int ArrayLength() {
1393
            return ((JArrayItem)value).arrayLength();
1394
        }
1395

    
1396
        /// <summary>
1397
        /// Get the n'th member in the array, counting from zero.
1398
        /// </summary>
1399
		/// <param name="n">the position of the member that is required, counting the first member in 
1400
		/// the array as member zero</param>
1401
        /// <returns>the n'th member in the sequence making up the array, counting from zero</returns>
1402
        public XdmValue Get(int n) {
1403
            try {
1404
                JSequence member = ((JArrayItem)value).get(n);
1405
                return XdmValue.Wrap(member);
1406
            }
1407
            catch (Exception) {
1408
                throw new IndexOutOfRangeException();
1409
            }
1410
        }
1411

    
1412

    
1413
        /// <summary>
1414
        /// Create a new array in which one member is replaced with a new value.
1415
        /// </summary>
1416
        /// <param name="n">the position of the member that is to be replaced, counting the first member
1417
        /// in the array as member zero</param>
1418
        /// <param name="valuei">the new value</param>
1419
        /// <returns>the new array</returns>
1420
        public XdmArray Put(int n, XdmValue valuei) {
1421
            try {
1422
                return (XdmArray)XdmValue.Wrap(((JArrayItem)this.value).put(n, valuei.value));
1423
            } catch (Exception) {
1424
                throw new IndexOutOfRangeException();
1425
            }
1426
        }
1427

    
1428

    
1429
        /// <summary>
1430
        /// Append a new member to an array
1431
        /// </summary>
1432
        /// <param name="value">the new member</param>
1433
        /// <returns>a new array, one item longer than the original</returns>
1434
        public XdmArray AppendMember(XdmValue value) {
1435
            try {
1436
                JGroundedValue member = value.value;
1437
                JArrayItem newArray = net.sf.saxon.ma.arrays.ArrayFunctionSet.ArrayAppend.append((JArrayItem)this.value, member);
1438
                return (XdmArray)Wrap(newArray);
1439
            }
1440
            catch (net.sf.saxon.trans.XPathException e) {
1441
                throw new StaticError(e);
1442
            }
1443
        }
1444

    
1445
        /// <summary>
1446
        /// Concatenate another array
1447
        /// </summary>
1448
        /// <param name="value">the other array</param>
1449
        /// <returns>a new array, containing the members of this array followed by the members 
1450
        /// of the other array</returns>
1451
        public XdmArray Concat(XdmArray value)
1452
        {
1453
            try
1454
            {
1455
                JArrayItem other = (JArrayItem)value.value;
1456
                JArrayItem newArray = ((JArrayItem)this.value).concat(other);
1457
                return (XdmArray)Wrap(newArray);
1458
            }
1459
            catch (net.sf.saxon.trans.XPathException e)
1460
            {
1461
                throw new StaticError(e);
1462
            }
1463
        }
1464

    
1465

    
1466
        /// <summary>
1467
        /// Get the members of the array in the form of a list.
1468
        /// </summary>
1469
        /// <returns>A list of the members of this array.</returns>
1470
        public List<XdmValue> AsList() {
1471

    
1472
            JArrayItem val = ((JArrayItem)value);
1473
            java.util.Iterator  iter = val.members().iterator();
1474
            List<XdmValue> result = new List<XdmValue>(val.getLength());
1475
            while (iter.hasNext()) {
1476
                result.Add(XdmValue.Wrap((JSequence)iter.next()));
1477

    
1478
            }
1479
            return result;
1480
        }
1481

    
1482
        /// <summary>
1483
        /// Make an XDM array from an object array. Each member of the supplied array
1484
        /// is converted to a single member in the result array using the method
1485
		/// <see cref="XdmValue.MakeValue(Object)"/>        
1486
        /// </summary>
1487
        /// <param name="o">the array of objects</param>
1488
        /// <returns>the result of the conversion if successful</returns>
1489
        
1490
        public static XdmArray MakeArray(object[] o)
1491
        {
1492
            JArrayList list = new JArrayList(o.Length);
1493
            for (int i = 0; i <o.Length; i++)
1494
            {
1495
                list.add(XdmValue.MakeValue(o[i]).Unwrap());
1496
            }
1497
            return new XdmArray(list);
1498
        }
1499

    
1500
        /// <summary>
1501
		/// Make an <c>XdmArray</c> whose members are <c>xs:boolean</c> values       
1502
        /// </summary>
1503
        /// <param name="o">the input array of booleans</param>
1504
		/// <returns>an <c>XdmArray</c> whose members are <c>xs:boolean</c> values corresponding one-to-one with the input</returns>
1505
        
1506
        public static XdmArray MakeArray(bool[] o)
1507
        {
1508
            JArrayList list = new JArrayList(o.Length);
1509
            for (int i = 0; i < o.Length; i++)
1510
            {
1511
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1512
            }
1513
            return new XdmArray(list);
1514
        }
1515

    
1516

    
1517
        /// <summary>
1518
		/// Make an <c>XdmArray</c> whose members are <c>xs:integer</c> values      
1519
        /// </summary>
1520
        /// <param name="o">the input array of long values</param>
1521
		/// <returns>an <c>XdmArray</c> whose members are <c>xs:integer</c> values corresponding one-to-one with the input</returns>
1522
        
1523
        public static XdmArray MakeArray(long[] o)
1524
        {
1525
            JArrayList list = new JArrayList(o.Length);
1526
            for (int i = 0; i < o.Length; i++)
1527
            {
1528
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1529
            }
1530
            return new XdmArray(list);
1531
        }
1532

    
1533

    
1534
        /// <summary>
1535
		/// Make an <c>XdmArray</c> whose members are <c>xs:integer</c> values      
1536
        /// </summary>
1537
        /// <param name="o">the input array of int values</param>
1538
		/// <returns>an <c>XdmArray</c> whose members are <c>xs:integer</c> values corresponding one-to-one with the input</returns>
1539
        
1540
        public static XdmArray MakeArray(int[] o)
1541
        {
1542
            JArrayList list = new JArrayList(o.Length);
1543
            for (int i = 0; i < o.Length; i++)
1544
            {
1545
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1546
            }
1547
            return new XdmArray(list);
1548
        }
1549

    
1550
        /// <summary>
1551
		/// Make an <c>XdmArray</c> whose members are <c>xs:integer</c> values      
1552
        /// </summary>
1553
        /// <param name="o">the input array of byte values</param>
1554
		/// <returns>an <c>XdmArray</c> whose members are <c>xs:integer</c> values corresponding one-to-one with the input</returns>
1555
        
1556
        public static XdmArray MakeArray(byte[] o)
1557
        {
1558
            JArrayList list = new JArrayList(o.Length);
1559
            for (int i = 0; i < o.Length; i++)
1560
            {
1561
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1562
            }
1563
            return new XdmArray(list);
1564
        }
1565
    }
1566

    
1567
    /// <summary inherits="XdmFunctionItem">
1568
    /// The class <c>XdmMap</c> represents a map item in an XPath 3.1 sequence:
1569
	/// this is a new kind of item in the XDM data model. A map is a list of zero or more entries, each of which
1570
    /// is a pair comprising a key (which is an atomic value) and a value (which is an arbitrary value).
1571
    /// </summary>
1572

    
1573

    
1574
    [Serializable]
1575
    public class XdmMap :  XdmFunctionItem
1576
    {
1577
  
1578

    
1579
        /// <summary>
1580
		/// Create an empty <c>XdmMap</c>
1581
        /// </summary>
1582
        public XdmMap() { 
1583
			this.value = new JHashTrieMap(); 
1584
		}
1585

    
1586
		// Internal constructor
1587

    
1588
        internal XdmMap(JHashTrieMap map) { 
1589
			this.value = map; 
1590
		}
1591

    
1592

    
1593
        /// <summary>
1594
        /// Get the number of entries in the map
1595
        /// </summary>
1596
		/// <remarks>(Note that the <see cref="XdmValue.Count"/> method returns 1 (one),
1597
        /// because an XDM map is an item.)</remarks>
1598
        
1599
        public int Size {
1600
            get {
1601
                return ((JMapItem)value).size();
1602
            }
1603
        }
1604

    
1605

    
1606
        /// <summary>
1607
		/// Ask whether the <c>XdmMap</c> is empty
1608
        /// </summary>
1609
        /// <returns>Returns <code>true</code> if this map contains no key-value pairs, that is
1610
        /// if the <c>Size</c> property is zero.</returns>
1611
        
1612
        public bool IsEmpty() {
1613
            return ((JMapItem)value).isEmpty();
1614
        }
1615

    
1616
        /// <summary>
1617
        /// Create a new map containing an additional (key, value) pair.
1618
        /// If there is an existing entry with the same key, it is removed.
1619
        /// </summary>
1620
        /// <param name="key">The key of the new entry.</param>
1621
        /// <param name="value">The value part of the new entry.</param>
1622
        /// <returns>A new map containing the additional entry (or replaced entry). The original map is unchanged.</returns>
1623
        
1624
        public XdmMap Put(XdmAtomicValue key, XdmValue value)
1625
        {
1626
            XdmMap map2 = new XdmMap();
1627
            map2.value = ((JMapItem)this.value).addEntry((JAtomicValue)key.Unwrap(), value.value);
1628
            return map2;
1629
        }
1630

    
1631

    
1632
        /// <summary>
1633
        /// Create a new map in which the entry for a given key has been removed.
1634
        /// If there is no entry with the same key, the new map has the same content as the old (it may or may not
1635
        /// be the same .NET object)
1636
        /// </summary>
1637
        /// <param name="key">The key of the entry that is to be removed</param>
1638
        /// <returns>A map without the specified entry. The original map is unchanged.</returns>
1639
        
1640
        public XdmMap Remove(XdmAtomicValue key)
1641
        {
1642
            XdmMap map2 = new XdmMap();
1643
            map2.value = ((JMapItem)this.value).remove((JAtomicValue)key.Unwrap());
1644
            return map2;
1645
        }
1646

    
1647

    
1648
        /// <summary>
1649
        /// Return a corresponding .NET Dictionary collection of keys and values.
1650
        /// </summary>
1651
        /// <returns>A mutable Dictionary from atomic values to (sequence) values, containing the
1652
        /// same entries as this map</returns>
1653
        
1654
        public Dictionary<XdmAtomicValue, XdmValue> AsDictionary() {
1655
            Dictionary<XdmAtomicValue, XdmValue> map = new Dictionary<XdmAtomicValue, XdmValue>();
1656
            JMapItem jmap = (JMapItem)value;
1657
            java.util.Iterator iter = jmap.keyValuePairs().iterator();
1658
            JKeyValuePair pair = null;
1659
            while (iter.hasNext()) {
1660
                pair = (JKeyValuePair)iter.next();
1661
                map.Add((XdmAtomicValue)XdmValue.Wrap(pair.key), XdmValue.Wrap(pair.value));
1662
            }
1663
            return map;
1664
        }
1665

    
1666

    
1667
        /// <summary>
1668
        /// Get the keys present in the map in the form of a set.
1669
        /// </summary>
1670
        /// <returns>a set of the keys present in this map, with no defined ordering.</returns>
1671
        public HashSet<XdmAtomicValue> KeySet()
1672
        {
1673
            HashSet<XdmAtomicValue> result = new HashSet<XdmAtomicValue>();
1674
            JMapItem jmap = (JMapItem)value;
1675
            net.sf.saxon.tree.iter.AtomicIterator iter = jmap.keys();
1676
            JAtomicValue key = null;
1677
            while ((key = iter.next()) != null)
1678
            {
1679
                result.Add((XdmAtomicValue)XdmValue.Wrap(key));
1680
            }
1681
            return result;
1682
        }
1683

    
1684

    
1685
        /// <summary>
1686
        /// Returns <code>true</code> if this map contains a mapping for the specified
1687
        /// key. More formally, returns <code>true</code> if and only if
1688
        /// this map contains a mapping for a key <code>k</code> such that
1689
        /// <code>(key==null ? k==null : key.Equals(k))</code>.  (There can be
1690
        /// at most one such mapping.)
1691
        /// </summary>
1692
        /// <param name="key">the key whose presence in this map is to be tested</param>
1693
        /// <returns><c>true</c> if this map contains a mapping for the specified key</returns>
1694
        
1695
        public bool ContainsKey(XdmAtomicValue key) {
1696
            JAtomicValue k = (JAtomicValue)key.value;
1697
            return ((JMapItem)value).get(k)!= null;
1698
        }
1699

    
1700

    
1701
        /// <summary>
1702
        /// Returns the value to which the specified key is mapped,
1703
		/// or <c>null</c> if this map contains no mapping for the key.
1704
        /// </summary>
1705
        /// <param name="key">the key whose associated value is to be returned. If this is
1706
		/// not an <c>XdmAtomicValue</c>, the method attempts to construct an
1707
		/// <c>XdmAtomicValue</c> using the method <see cref="XdmAtomicValue.MakeAtomicValue(Object)"/>;
1708
        /// it is therefore possible to pass a simple key such as a string or integer.</param>
1709
        /// <returns>the value to which the specified key is mapped, or
1710
		/// <c>null</c> if this map contains no mapping for the key</returns>
1711
        
1712
        public XdmValue Get(XdmAtomicValue key)
1713
        {
1714
            if (key == null) {
1715
                throw new ArgumentNullException();
1716
            }
1717
           
1718
            JAtomicValue k = (JAtomicValue)(key).value;
1719
            JSequence v = ((JMapItem)value).get(k);
1720
            return v==null ? null : XdmValue.Wrap(v);
1721
        }
1722

    
1723
        /// <summary>
1724
        /// Returns the value to which the specified key is mapped,
1725
        /// or <c>null</c> if this map contains no mapping for the key.
1726
        /// </summary>
1727
        /// <param name="key">the key whose associated value is to be returned.</param>
1728
        /// <returns>the value to which the specified key is mapped, or
1729
        /// <c>null</c> if this map contains no mapping for the key</returns>
1730

    
1731
        public XdmValue Get(String key)
1732
        {
1733
            if (key == null)
1734
            {
1735
                throw new ArgumentNullException();
1736
            }
1737
    
1738
            JAtomicValue k = (JAtomicValue)(new XdmAtomicValue(key)).value;
1739
            JSequence v = ((JMapItem)value).get(k);
1740
            return v == null ? null : XdmValue.Wrap(v);
1741
        }
1742

    
1743

    
1744
        /// <summary>
1745
        /// Returns the value to which the specified key is mapped,
1746
        /// or <c>null</c> if this map contains no mapping for the key.
1747
        /// </summary>
1748
        /// <param name="key">the key whose associated value is to be returned.</param>
1749
        /// <returns>the value to which the specified key is mapped, or
1750
        /// <c>null</c> if this map contains no mapping for the key</returns>
1751

    
1752
        public XdmValue Get(long key)
1753
        {
1754

    
1755
            JAtomicValue k = (JAtomicValue)(new XdmAtomicValue(key)).value;
1756
            JSequence v = ((JMapItem)value).get(k);
1757
            return v == null ? null : XdmValue.Wrap(v);
1758
        }
1759

    
1760
        /// <summary>
1761
        /// Returns a <c>Collection</c> containing the values found in this map.
1762
        /// </summary>
1763
        /// <returns>A collection of the values found in this map, that is, the value
1764
        /// parts of the key-value pairs. The result may contain duplicates, and the
1765
        /// order of results is unpredictable.</returns>
1766
        public ICollection Values() {
1767
            List<XdmValue> result = new List<XdmValue>();
1768

    
1769
            JMapItem jmap = (JMapItem)value;
1770
            java.util.Iterator iter = jmap.iterator();
1771
            JKeyValuePair pair = null;
1772
            while ((pair = (JKeyValuePair)iter.next()) != null)
1773
            {
1774
                result.Add((XdmAtomicValue)XdmValue.Wrap(pair.value));
1775
            }
1776

    
1777
            return result;
1778
        }
1779

    
1780

    
1781
        /// <summary>
1782
		/// Returns a <c>HashSet</c> view of the mappings contained in this map.
1783
        /// </summary>
1784
        /// <returns>a set view of the mappings contained in this map</returns>
1785
        public HashSet<DictionaryEntry> EntrySet() {
1786
            HashSet<DictionaryEntry> result = new HashSet<DictionaryEntry>();
1787
            JMapItem jmap = (JMapItem)value;
1788
            java.util.Iterator iter = jmap.iterator();
1789
            JKeyValuePair pair = null;
1790
            while ((pair = (JKeyValuePair)iter.next()) != null)
1791
            {
1792
                result.Add(new DictionaryEntry(pair.key, pair.value));
1793
            }
1794
            return result;
1795
        }
1796

    
1797

    
1798
        /// <summary>
1799
        /// Static factory method to construct an XDM map by converting each entry
1800
        /// in a supplied generic collection of key/value pairs; <code>IDictionary</code>. The keys in the 
1801
        /// Dictionary must be convertible to XDM atomic values using the 
1802
		/// <see cref="XdmAtomicValue.MakeAtomicValue(Object)"/> method. The associated values 
1803
        /// must be convertible to XDM sequences
1804
		/// using the <see cref="XdmValue.MakeValue(Object)"/> method.
1805
        /// </summary>
1806
        /// <param name="input">the supplied map</param>
1807
		/// <returns>the resulting <c>XdmMap</c></returns>
1808
        public static XdmMap MakeMap(IDictionary input) {
1809
            JHashTrieMap result = new JHashTrieMap();
1810
            XdmAtomicValue key;
1811
            XdmValue value;
1812
            
1813
            foreach (object keyi in input.Keys)
1814
            {
1815
                key = XdmAtomicValue.MakeAtomicValue(keyi);
1816
                value = XdmValue.MakeValue(input[keyi]);
1817
                result.initialPut((JAtomicValue)key.Unwrap(), value.value);
1818
            }
1819
           
1820
            return new XdmMap(result);
1821
        }
1822

    
1823
        
1824

    
1825

    
1826
    }
1827
    
1828
    /// <summary inherits="XdmItem">
1829
    /// The class <c>XdmNode</c> represents a Node in the XDM Data Model. A Node
1830
    /// is an <c>XdmItem</c>, and is therefore an <c>XdmValue</c> in its own right, and may also participate
1831
    /// as one item within a sequence value.
1832
    /// </summary>
1833
    /// <remarks>
1834
    /// <para>An <c>XdmNode</c> is implemented as a wrapper around an object
1835
    /// of type <c>net.sf.saxon.NodeInfo</c>. Because this is a key interface
1836
    /// within Saxon, it is exposed via this API, even though it is a Java
1837
    /// interface that is not part of the API proper.</para>
1838
    /// <para>The <c>XdmNode</c> interface exposes basic properties of the node, such
1839
    /// as its name, its string value, and its typed value. Navigation to other nodes
1840
    /// is supported through a single method, <c>EnumerateAxis</c>, which allows
1841
    /// other nodes to be retrieved by following any of the XPath axes.</para>
1842
    /// </remarks>
1843

    
1844
    [Serializable]
1845
    public class XdmNode : XdmItem
1846
    {
1847

    
1848
        /// <summary>
1849
        /// Determine whether the item is an atomic value
1850
        /// </summary>
1851
        /// <returns>
1852
        /// false (the item is not an atomic value)
1853
        /// </returns>
1854

    
1855
        public override bool IsAtomic()
1856
        {
1857
            return false;
1858
        }
1859

    
1860
        /// <summary>
1861
        /// The name of the node, as a <c>QName</c>. Returns null in the case of unnamed nodes.
1862
        /// </summary>
1863

    
1864
        public QName NodeName
1865
        {
1866
            get
1867
            {
1868
                JNodeInfo node = (JNodeInfo)value;
1869
                String local = node.getLocalPart();
1870
                if (local == "")
1871
                {
1872
                    return null;
1873
                }
1874
                String prefix = node.getPrefix();
1875
                String uri = node.getURI();
1876
                return new QName(prefix, uri, local);
1877
            }
1878
        }
1879

    
1880
        /// <summary>
1881
        /// The kind of node, as an instance of <c>System.Xml.XmlNodeType</c>.
1882
        /// </summary>
1883
		/// <remarks>For a namespace node in the XDM model, the value <c>XmlNodeType.None</c> 
1884
        /// is returned.
1885
        /// </remarks>
1886

    
1887
        public XmlNodeType NodeKind
1888
        {
1889
            get
1890
            {
1891
                JNodeInfo node = (JNodeInfo)value;
1892
                int kind = node.getNodeKind();
1893
                switch (kind)
1894
                {
1895
                    case JType.DOCUMENT:
1896
                        return XmlNodeType.Document;
1897
                    case JType.ELEMENT:
1898
                        return XmlNodeType.Element;
1899
                    case JType.ATTRIBUTE:
1900
                        return XmlNodeType.Attribute;
1901
                    case JType.TEXT:
1902
                        return XmlNodeType.Text;
1903
                    case JType.COMMENT:
1904
                        return XmlNodeType.Comment;
1905
                    case JType.PROCESSING_INSTRUCTION:
1906
                        return XmlNodeType.ProcessingInstruction;
1907
                    case JType.NAMESPACE:
1908
                        return XmlNodeType.None;
1909
                    default:
1910
                        throw new ArgumentException("Unknown node kind");
1911
                }
1912
            }
1913
        }
1914

    
1915
        /// <summary>
1916
		/// Get the line number of the node in a source document. 
1917
		/// </summary>
1918
		/// <remarks>
1919
		/// For a document constructed using the document
1920
        /// builder, this is available only if the line numbering option was set when the document was built (and
1921
        /// then only for element nodes). If the line number is not available, the value -1 is returned.
1922
        /// Line numbers will typically be as reported by a SAX parser; this means that the line number for an element
1923
        /// node is the line number containing the closing ">" of the start tag.
1924
		/// </remarks>
1925
         
1926
        public int LineNumber {
1927
            get { return ((JNodeInfo)value).getLineNumber(); }
1928
        }
1929

    
1930

    
1931
        /// <summary>
1932
		/// Get the column number of the node in a source document. 
1933
		/// </summary>
1934
		/// <remarks>
1935
		/// For a document constructed using the document
1936
        /// builder, this is available only if the line numbering option was set when the document was built (and
1937
        /// then only for element nodes). If the column number is not available, the value -1 is returned.
1938
        /// Line numbers will typically be as reported by a SAX parser; this means that the column number for an element
1939
        /// node is the column number containing the closing ">" of the start tag.
1940
		/// </remarks>
1941
        
1942
		public int ColumnNumber
1943
        {
1944
            get { return ((JNodeInfo)value).getColumnNumber(); }
1945
        }
1946

    
1947
        /// <summary>
1948
        /// The typed value of the node, as an instance of <c>XdmValue</c>.
1949
        /// </summary>
1950
        /// <remarks>
1951
		/// A <c>DynamicError</c> is thrown if the node has no typed value, as will be the case for
1952
        /// an element with element-only content.
1953
		/// </remarks>
1954

    
1955
        public XdmValue TypedValue
1956
        {
1957
            get { return XdmValue.Wrap(((JNodeInfo)value).atomize()); }
1958
        }
1959

    
1960
        /// <summary>
1961
		/// Get a <see cref="Processor"/> suitable for use with this <see cref="XdmNode"/>.
1962
        /// </summary>
1963
        /// <remarks>
1964
		/// <para>In most cases this will be the original <see cref="Processor"/>
1965
		/// object used to create the <see cref="DocumentBuilder"/> that built the document that 
1966
		/// contains this node. If that <see cref="Processor"/> is not available, it will be a 
1967
		/// compatible <c>Processor</c>, one that shares the same underlying <see cref="net.sf.saxon.Configuration"/>, 
1968
        /// and hence is initialized with the same configuration settings, schema components, license features,
1969
        /// and so on.</para>
1970
		/// <para><i>Note: the only case where the original <c>Processor</c> is not available is when
1971
		/// the same <c>Configuration</c> is used with multiple APIs, for example mixing s9api
1972
        /// and JAXP or XQJ in the same application.</i></para>
1973
        /// </remarks>
1974
		/// <returns>Returns a <c>Processor</c> suitable for performing further operations on this node, for example
1975
		/// for creating a <see cref="Serializer"/> or an <see cref="XPathCompiler"/>.</returns>
1976
        public Processor Processor {
1977
            get {
1978
                JConfiguration config = Implementation.getConfiguration();
1979
                object originator = config.getProcessor();
1980
                if (originator is Processor)
1981
                {
1982
                    return (Processor)originator;
1983
                }
1984
                else {
1985
                    return new Processor(new net.sf.saxon.s9api.Processor(config));
1986
                }
1987
            }
1988
        }
1989

    
1990

    
1991
        /// <summary>
1992
		/// Unwraps the underlying <c>XmlNode</c> object from the <c>XdmValue</c>.
1993
		/// If the method does not wrap a <c>XmlNode</c> then a null is returned
1994
        /// </summary>
1995
		/// <returns>The underlying <c>XmlNode</c></returns>
1996
        public XmlNode getUnderlyingXmlNode()
1997
        {
1998

    
1999
            if (value is net.sf.saxon.dotnet.DotNetNodeWrapper)
2000
            {
2001

    
2002
                return (XmlNode)((net.sf.saxon.dotnet.DotNetNodeWrapper)value).getRealNode();
2003
            }
2004
            return null;
2005
        }
2006

    
2007
        /// <summary>
2008
        /// Get the string value of the node.
2009
        /// </summary>
2010

    
2011
        public String StringValue
2012
        {
2013
            get { return ((JNodeInfo)value).getStringValue(); }
2014
        }
2015

    
2016
        /// <summary>
2017
        /// Get the parent of this node.
2018
        /// </summary>
2019
        /// <remarks>
2020
        /// Returns either a document node, an element node, or null in the case where
2021
        /// this node has no parent. 
2022
        /// </remarks>
2023

    
2024
        public XdmNode Parent
2025
        {
2026
            get {
2027
                JNodeInfo parent = ((JNodeInfo)value).getParent();
2028
                return (parent == null ? null : (XdmNode)XdmValue.Wrap(parent)); 
2029
            }
2030
        }
2031

    
2032
        /// <summary>
2033
        /// Get the root of the tree containing this node.
2034
        /// </summary>
2035
        /// <remarks>
2036
        /// Returns the root of the tree containing this node (which might be this node itself).
2037
        /// </remarks>
2038

    
2039
        public XdmNode Root
2040
        {
2041
            get
2042
            {
2043
                XdmNode parent = Parent;
2044
                if (parent == null)
2045
                {
2046
                    return this;
2047
                }
2048
                else
2049
                {
2050
                    return parent.Root;
2051
                }
2052
            }
2053
        }
2054

    
2055
        /// <summary>
2056
        /// Get a the string value of a named attribute of this element. 
2057
        /// </summary>
2058
        /// <remarks>
2059
        /// Returns null if this node is not an element, or if this element has no
2060
        /// attribute with the specified name.
2061
        /// </remarks>
2062
        /// <param name="name">The name of the attribute whose value is required</param>
2063

    
2064
        public String GetAttributeValue(QName name)
2065
        {
2066
            return ((JNodeInfo)value).getAttributeValue(name.Uri, name.LocalName);
2067
        }
2068

    
2069
        /// <summary>
2070
        /// Get an enumerator that supplies all the nodes on one of the XPath
2071
        /// axes, starting with this node.
2072
        /// </summary>
2073
        /// <param name="axis">
2074
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child axis.
2075
        /// </param>
2076
        /// <remarks>
2077
        /// The nodes are returned in axis order: that is, document order for a forwards
2078
        /// axis, reverse document order for a reverse axis.
2079
        /// </remarks>
2080

    
2081
        public IEnumerator<XdmNode> EnumerateAxis(XdmAxis axis)
2082
        {
2083
            return (new SequenceEnumerator<XdmNode>(JSequenceXdmIterator.ofNodes(((JNodeInfo)value).iterateAxis(GetAxisNumber(axis)))));
2084
        }
2085

    
2086
        /// <summary>
2087
        /// Get an enumerator that selects all the nodes on one of the XPath
2088
        /// axes, provided they have a given name. The nodes selected are those of the principal
2089
        /// node kind (elements for most axes, attributes for the attribute axis, namespace nodes
2090
        /// for the namespace axis) whose name matches the name given in the second argument.
2091
        /// </summary>
2092
        /// <param name="axis">
2093
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child axis.
2094
        /// </param>
2095
        /// <param name="nodeName">
2096
        /// The name of the required nodes, for example <c>new QName("", "item")</c> to select
2097
        /// nodes with local name "item", in no namespace.
2098
        /// </param>
2099
        /// <remarks>
2100
        /// The nodes are returned in axis order: that is, document order for a forwards
2101
        /// axis, reverse document order for a reverse axis.
2102
        /// </remarks>
2103

    
2104
        public IEnumerator<XdmNode> EnumerateAxis(XdmAxis axis, QName nodeName)
2105
        {
2106
            int kind;
2107
            switch (axis)
2108
            {
2109
                case XdmAxis.Attribute:
2110
                    kind = net.sf.saxon.type.Type.ATTRIBUTE;
2111
                    break;
2112
                case XdmAxis.Namespace:
2113
                    kind = net.sf.saxon.type.Type.NAMESPACE;
2114
                    break;
2115
                default:
2116
                    kind = net.sf.saxon.type.Type.ELEMENT;
2117
                    break;
2118
            }
2119
            JNamePool pool = ((JNodeInfo)value).getConfiguration().getNamePool();
2120
            JNameTest test = new JNameTest(kind, nodeName.Uri, nodeName.LocalName, pool);
2121
            return new SequenceEnumerator<XdmNode>(JSequenceXdmIterator.ofNodes(((JNodeInfo)value).iterateAxis(GetAxisNumber(axis), test)));
2122
        }
2123

    
2124
        private static byte GetAxisNumber(XdmAxis axis)
2125
        {
2126
            switch (axis)
2127
            {
2128
                case XdmAxis.Ancestor: return JAxisInfo.ANCESTOR;
2129
                case XdmAxis.AncestorOrSelf: return JAxisInfo.ANCESTOR_OR_SELF;
2130
                case XdmAxis.Attribute: return JAxisInfo.ATTRIBUTE;
2131
                case XdmAxis.Child: return JAxisInfo.CHILD;
2132
                case XdmAxis.Descendant: return JAxisInfo.DESCENDANT;
2133
                case XdmAxis.DescendantOrSelf: return JAxisInfo.DESCENDANT_OR_SELF;
2134
                case XdmAxis.Following: return JAxisInfo.FOLLOWING;
2135
                case XdmAxis.FollowingSibling: return JAxisInfo.FOLLOWING_SIBLING;
2136
                case XdmAxis.Namespace: return JAxisInfo.NAMESPACE;
2137
                case XdmAxis.Parent: return JAxisInfo.PARENT;
2138
                case XdmAxis.Preceding: return JAxisInfo.PRECEDING;
2139
                case XdmAxis.PrecedingSibling: return JAxisInfo.PRECEDING_SIBLING;
2140
                case XdmAxis.Self: return JAxisInfo.SELF;
2141
            }
2142
            return 0;
2143
        }
2144

    
2145
        /// <summary>
2146
        /// Get the base URI of the node.
2147
        /// </summary>
2148

    
2149
        public Uri BaseUri
2150
        {
2151
            get { 
2152
				string baseUriStr = ((JNodeInfo)value).getBaseURI();
2153
				if (baseUriStr == null || baseUriStr.Equals("")) {
2154
					return null;
2155
				}
2156
				return new Uri(baseUriStr); 
2157
			}
2158
        }
2159

    
2160
        /// <summary>
2161
        /// Get the document URI of the node.
2162
        /// </summary>
2163

    
2164
        public Uri DocumentUri
2165
        {
2166
            get
2167
            {
2168
                String s = ((JNodeInfo)value).getSystemId();
2169
                if (s == null || s.Length == 0)
2170
                {
2171
                    return null;
2172
                }
2173
                return new Uri(s);
2174
            }
2175
        }
2176

    
2177
        /// <summary>
2178
        /// Send the node (that is, the subtree rooted at this node) to an <c>XmlWriter</c>
2179
        /// </summary>
2180
        /// <remarks>
2181
        /// Note that an <c>XmlWriter</c> can only handle a well-formed XML document. This method
2182
        /// will therefore signal an exception if the node is a document node with no children, or with
2183
        /// more than one element child.
2184
        /// </remarks>
2185
        /// <param name="writer">
2186
        /// The <c>XmlWriter</c> to which the node is to be written
2187
        /// </param>
2188

    
2189
        public void WriteTo(XmlWriter writer)
2190
        {
2191
            JNodeInfo node = ((JNodeInfo)value);
2192
            JDotNetReceiver receiver = new JDotNetReceiver(writer);
2193
            receiver.setPipelineConfiguration(node.getConfiguration().makePipelineConfiguration());
2194
            receiver.open();
2195
			node.copy(receiver, net.sf.saxon.om.CopyOptions.ALL_NAMESPACES, JExplicitLocation.UNKNOWN_LOCATION);
2196
            receiver.close();
2197
        }
2198

    
2199
        /// <summary>
2200
        /// Return a serialization of this node as lexical XML
2201
        /// </summary>
2202
        /// <remarks>
2203
        /// <para>In the case of an element node, the result will be a well-formed
2204
        /// XML document serialized as defined in the W3C XSLT/XQuery serialization specification,
2205
		/// using options <c>method="xml"</c>, <c>indent="yes"</c>, <c>omit-xml-declaration="yes"</c>.</para>
2206
        /// <para>In the case of a document node, the result will be a well-formed
2207
        /// XML document provided that the document node contains exactly one element child,
2208
        /// and no text node children. In other cases it will be a well-formed external
2209
        /// general parsed entity.</para>
2210
        /// <para>In the case of an attribute node, the output is a string in the form
2211
        /// <c>name="value"</c>. The name will use the original namespace prefix.</para>
2212
        /// <para>Other nodes, such as text nodes, comments, and processing instructions, are
2213
        /// represented as they would appear in lexical XML.</para>
2214
        /// </remarks>
2215

    
2216
        public String OuterXml
2217
        {
2218
            get
2219
            {
2220
                JNodeInfo node = ((JNodeInfo)value);
2221

    
2222
                if (node.getNodeKind() == JType.ATTRIBUTE)
2223
                {
2224
                    String val = node.getStringValue().Replace("\"", "&quot;");
2225
                    val = val.Replace("<", "&lt;");
2226
                    val = val.Replace("&", "&amp;");
2227
                    return node.getDisplayName() + "=\"" + val + '"';
2228
                } else if (node.getNodeKind() == JType.NAMESPACE) {
2229
                    String val = node.getStringValue().Replace("\"", "&quot;");
2230
                    val = val.Replace("<", "&lt;");
2231
                    val = val.Replace("&", "&amp;");
2232
                    String name = node.getDisplayName();
2233
                    name = (name.Equals("") ? "xmlns" : "xmlns:" + name);
2234
                    return name + "=\"" + val + '"';
2235
                }
2236
                return net.sf.saxon.query.QueryResult.serialize(node);
2237
                
2238
            }
2239
        }
2240

    
2241
        /// <summary>
2242
		/// Two instances of <c>XdmNode</c> are equal if they represent the same node. That is, the <c>Equals()</c>
2243
        /// method returns the same result as the XPath "is" operator.
2244
        /// </summary>
2245
        /// <param name="obj">The object node to be compared</param>
2246
         
2247
        public override bool Equals(object obj)
2248
        {
2249
            return obj is XdmNode && ((JNodeInfo)value).equals((JNodeInfo)((XdmNode)obj).value);
2250
        }
2251

    
2252
        /// <summary>
2253
		/// The hash code of a node reflects the equality relationship: if two <c>XdmNode</c> instances
2254
        /// represent the same node, then they have the same hash code
2255
        /// </summary>
2256

    
2257
        public override int GetHashCode()
2258
        {
2259
            return ((JNodeInfo)value).hashCode();
2260
        }
2261

    
2262
        /// <summary>
2263
        /// Return a string representation of the node.
2264
        /// </summary>
2265
        /// <remarks>
2266
		/// This method returns the value of the <see cref="OuterXml"/> property.
2267
		/// To get the string value of a node as defined in XPath, use the <see cref="StringValue"/> property.
2268
        /// </remarks>
2269

    
2270
        public override String ToString()
2271
        {
2272
            return OuterXml;
2273
        }
2274

    
2275
        internal void SetProcessor(Processor processor)
2276
        {
2277
            Implementation.getConfiguration().setProcessor(processor.JProcessor);
2278
        }
2279

    
2280
        /// <summary>
2281
        /// Escape hatch to the underlying class in the Java implementation
2282
        /// </summary>
2283

    
2284
        public JNodeInfo Implementation
2285
        {
2286
            get { return ((JNodeInfo)value); }
2287
        }
2288

    
2289

    
2290
    }
2291

    
2292

    
2293
    /// <summary inherits="XdmValue">
2294
    /// The class <c>XdmEmptySequence</c> represents an empty sequence in the XDM Data Model.
2295
    /// </summary>
2296
    /// <remarks>
2297
    /// <para>An empty sequence <i>may</i> also be represented by an <c>XdmValue</c> whose length
2298
    /// happens to be zero. Applications should therefore not test to see whether an object
2299
    /// is an instance of this class in order to decide whether it is empty.</para>
2300
    /// <para>In interfaces that expect an <c>XdmItem</c>, an empty sequence is represented
2301
    /// by a CLI <c>null</c> value.</para> 
2302
    /// </remarks>
2303

    
2304
    [Serializable]
2305
    public sealed class XdmEmptySequence : XdmValue
2306
    {
2307

    
2308
        ///<summary>The singular instance of this class</summary>
2309

    
2310
        public static XdmEmptySequence INSTANCE = new XdmEmptySequence();
2311

    
2312
        private XdmEmptySequence()
2313
        {
2314
            this.value = JEmptySequence.getInstance();
2315
        }
2316
    }
2317

    
2318

    
2319
    /// <summary>
2320
	/// The <c>QName</c> class represents an instance of <c>xs:QName</c>, as defined in the XPath 2.0
2321
    /// data model. Internally, it has three components, a namespace URI, a local name, and
2322
    /// a prefix. The prefix is intended to be used only when converting the value back to 
2323
    /// a string.
2324
    /// </summary>
2325
    /// <remarks>
2326
	/// Note that a <c>QName</c> is not itself an <c>XdmItem</c> in this model; however it can
2327
    /// be converted to an <c>XdmAtomicValue</c>.
2328
    /// </remarks>    
2329

    
2330
    [Serializable]
2331
    public sealed class QName
2332
    {
2333

    
2334
        private JQName sqName;
2335
        //private String prefix;
2336
        //private String uri;
2337
        //private String local;
2338
        //int hashcode = -1;      // evaluated lazily
2339

    
2340

    
2341
        private static String XS = NamespaceConstant.SCHEMA;
2342

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

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

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

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

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

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

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

    
2364
        /// <summary>QName constant for the name xs:QName</summary>
2365
        public static readonly QName XS_QNAME = new QName(XS, "xs:QName");
2366

    
2367
        /// <summary>QName constant for the name xs:untypedAtomic</summary>
2368
        public static readonly QName XS_UNTYPED_ATOMIC = new QName(XS, "xs:untypedAtomic");
2369

    
2370
        /// <summary>QName constant for the name xs:untypedAtomic (for backwards compatibility)</summary>
2371
        public static readonly QName XDT_UNTYPED_ATOMIC = new QName(XS, "xs:untypedAtomic");
2372

    
2373
        /// <summary>
2374
		/// Construct a <c>QName</c> representing a name in no namespace
2375
        /// </summary>
2376
        /// <remarks>
2377
        /// This constructor does not check that the components of the QName are
2378
        /// lexically valid.
2379
        /// </remarks>
2380
        /// <param name="local">The local part of the name
2381
        /// </param>
2382

    
2383
        public QName(String local)
2384
        {
2385
            // TODO: check for validity
2386
            int colon = local.IndexOf(':');
2387
            if (colon < 0)
2388
            {
2389
                sqName = new JQName("", "", local);
2390
            }
2391
            else {
2392
                
2393
                    throw new ArgumentException("Local name contains a colon");
2394
                }             
2395
        }
2396

    
2397
        /// <summary>
2398
		/// Construct a <c>QName</c> using a namespace URI and a lexical representation.
2399
        /// The lexical representation may be a local name on its own, or it may 
2400
        /// be in the form <c>prefix:local-name</c>
2401
        /// </summary>
2402
        /// <remarks>
2403
        /// This constructor does not check that the components of the QName are
2404
        /// lexically valid.
2405
        /// </remarks>
2406
        /// <param name="uri">The namespace URI. Use either the string "" or null
2407
        /// for names that are not in any namespace.
2408
        /// </param>
2409
        /// <param name="lexical">Either the local part of the name, or the prefix
2410
        /// and local part in the format <c>prefix:local</c>
2411
        /// </param>
2412

    
2413
        public QName(String uri, String lexical)
2414
        {
2415
            // TODO: check for validity
2416
            uri = (uri == null ? "" : uri);
2417
            int colon = lexical.IndexOf(':');
2418
            if (colon < 0)
2419
            {
2420
                sqName = new JQName("", uri, lexical);
2421
            }
2422
            else
2423
            {
2424

    
2425
                string prefix = lexical.Substring(0, colon);
2426
                string local = lexical.Substring(colon + 1);
2427
                sqName = new JQName(prefix, uri, local);
2428
            }
2429
        }
2430

    
2431
        /// <summary>
2432
		/// Construct a <c>QName</c> using a namespace prefix, a namespace URI, and a local name
2433
        /// (in that order).
2434
        /// </summary>
2435
        /// <remarks>
2436
        /// This constructor does not check that the components of the QName are
2437
        /// lexically valid.
2438
        /// </remarks>
2439
        /// <param name="prefix">The prefix of the name. Use either the string ""
2440
        /// or null for names that have no prefix (that is, they are in the default
2441
        /// namespace)</param>
2442
        /// <param name="uri">The namespace URI. Use either the string "" or null
2443
        /// for names that are not in any namespace.
2444
        /// </param>
2445
        /// <param name="local">The local part of the name</param>
2446

    
2447
        public QName(String prefix, String uri, String local)
2448
        {
2449
            sqName = new JQName(prefix, uri, local);
2450
        }
2451

    
2452
        /// <summary>
2453
		/// Construct a <c>QName</c> from a lexical QName, supplying an element node whose
2454
        /// in-scope namespaces are to be used to resolve any prefix contained in the QName.
2455
        /// </summary>
2456
        /// <remarks>
2457
        /// <para>This constructor checks that the components of the QName are
2458
        /// lexically valid.</para>
2459
        /// <para>If the lexical QName has no prefix, the name is considered to be in the
2460
        /// default namespace, as defined by <c>xmlns="..."</c>.</para>
2461
        /// </remarks>
2462
        /// <param name="lexicalQName">The lexical QName, in the form <code>prefix:local</code>
2463
        /// or simply <c>local</c>.</param>
2464
        /// <param name="element">The element node whose in-scope namespaces are to be used
2465
        /// to resolve the prefix part of the lexical QName.</param>
2466
        /// <exception cref="ArgumentException">If the prefix of the lexical QName is not in scope</exception>
2467
        /// <exception cref="ArgumentException">If the lexical QName is invalid 
2468
        /// (for example, if it contains invalid characters)</exception>
2469
        /// 
2470

    
2471
        public QName(String lexicalQName, XdmNode element)
2472
        {
2473
            try
2474
            {
2475
                JNodeInfo node = (JNodeInfo)element.value;
2476
				sqName = new JQName(JStructuredQName.fromLexicalQName(lexicalQName, true, true, new JInscopeNamespaceResolver(node)));
2477
				
2478
            }
2479
            catch (net.sf.saxon.trans.XPathException err)
2480
            {
2481
                throw new ArgumentException(err.getMessage());
2482
            }
2483
        }
2484

    
2485
        /// <summary>
2486
        /// Construct a <c>QName</c> from an <c>XmlQualifiedName</c> (as defined in the
2487
        /// <c>System.Xml</c> package).
2488
        /// </summary>
2489
        /// <remarks>
2490
        /// Note that an <c>XmlQualifiedName</c> does not contain any prefix, so the result
2491
        /// will always have a prefix of ""
2492
        /// </remarks>
2493
		/// <param name="qualifiedName">The <c>XmlQualifiedName</c></param>
2494

    
2495
        public QName(XmlQualifiedName qualifiedName)
2496
        {
2497
            string uri = qualifiedName.Namespace;
2498
            string local = qualifiedName.Name;
2499
            string prefix = String.Empty;
2500
            sqName = new JQName(prefix, uri, prefix);
2501
        }
2502

    
2503
        //  internal constructor from a QNameValue
2504

    
2505
        internal QName(JQNameValue q)
2506
        {
2507
            sqName = new JQName(q.getPrefix(), q.getNamespaceURI(), q.getLocalName());
2508
        }
2509

    
2510
        //  internal constructor with JQName object as argument
2511

    
2512
        internal QName(JQName q)
2513
        {
2514
            sqName = q;
2515
        }
2516

    
2517
        /// <summary>
2518
		/// Factory method to construct a <c>QName</c> from a string containing the expanded
2519
        /// QName in Clark notation, that is, <c>{uri}local</c>
2520
        /// </summary>
2521
        /// <remarks>
2522
        /// The prefix part of the <c>QName</c> will be set to an empty string.
2523
        /// </remarks>
2524
        /// <param name="expandedName">The URI in Clark notation: <c>{uri}local</c> if the
2525
        /// name is in a namespace, or simply <c>local</c> if not.</param> 
2526

    
2527
        public static QName FromClarkName(String expandedName)
2528
        {
2529
            String namespaceURI;
2530
            String localName;
2531
            if (expandedName[0] == '{')
2532
            {
2533
                int closeBrace = expandedName.IndexOf('}');
2534
                if (closeBrace < 0)
2535
                {
2536
                    throw new ArgumentException("No closing '}' in Clark name");
2537
                }
2538
                namespaceURI = expandedName.Substring(1, closeBrace - 1);
2539
                if (closeBrace == expandedName.Length)
2540
                {
2541
                    throw new ArgumentException("Missing local part in Clark name");
2542
                }
2543
                localName = expandedName.Substring(closeBrace + 1);
2544
            }
2545
            else
2546
            {
2547
                namespaceURI = "";
2548
                localName = expandedName;
2549
            }
2550

    
2551
            return new QName("", namespaceURI, localName);
2552
        }
2553

    
2554

    
2555
        /// <summary>
2556
		/// Factory method to construct a <c>QName</c> from a string containing the expanded
2557
        /// QName in EQName notation, that is, <c>Q{uri}local</c>
2558
        /// </summary>
2559
        /// <remarks>
2560
        /// The prefix part of the <c>QName</c> will be set to an empty string.
2561
        /// </remarks>
2562
        /// <param name="expandedName">The QName in EQName notation: <c>Q{uri}local</c>. 
2563
		/// For a name in no namespace, either of the
2564
        /// forms <c>Q{}local</c> or simply <c>local</c> are accepted.</param>
2565
        /// <returns> the QName corresponding to the supplied name in EQName notation. This will always
2566
        /// have an empty prefix.</returns>
2567
       
2568
        public static QName FromEQName(String expandedName)
2569
        {
2570
            String namespaceURI;
2571
            String localName;
2572
            if (expandedName[0] == 'Q' && expandedName[1] == '{')
2573
            {
2574
                int closeBrace = expandedName.IndexOf('}');
2575
                if (closeBrace < 0)
2576
                {
2577
                    throw new ArgumentException("No closing '}' in EQName");
2578
                }
2579
                namespaceURI = expandedName.Substring(2, closeBrace);
2580
                if (closeBrace == expandedName.Length)
2581
                {
2582
                    throw new ArgumentException("Missing local part in EQName");
2583
                }
2584
                localName = expandedName.Substring(closeBrace + 1);
2585
            }
2586
            else
2587
            {
2588
                namespaceURI = "";
2589
                localName = expandedName;
2590
            }
2591

    
2592
            return new QName("", namespaceURI, localName);
2593
        }
2594

    
2595
        // internal method: Factory method to construct a QName from Saxon's internal <c>StructuredQName</c>
2596
        // representation.
2597

    
2598
        internal static QName FromStructuredQName(JStructuredQName sqn) {
2599
            return new QName(sqn.getPrefix(), sqn.getURI(), sqn.getLocalPart());
2600
        }
2601

    
2602
        /// <summary>
2603
		/// Register a <c>QName</c> with the <c>Processor</c>. This makes comparison faster
2604
        /// when the QName is compared with others that are also registered with the <c>Processor</c>.
2605
        /// Depreacted method.
2606
        /// </summary>
2607
        /// <remarks>
2608
        /// A given <c>QName</c> object can only be registered with one <c>Processor</c>.
2609
        /// </remarks>
2610
		/// <param name="processor">The <c>Processor</c> in which the name is to be registered.</param>
2611
        [System.Obsolete("This method is no longer in use")]
2612
        public void Register(Processor processor)
2613
        {}
2614

    
2615
        /// <summary>
2616
		/// Validate the <c>QName</c> against the XML 1.0 or XML 1.1 rules for valid names.
2617
        /// </summary>
2618
        /// <param name="processor">This argument is no longer used (at one time it was used
2619
        /// to establish whether XML 1.0 or XML 1.1 rules should be used for validation, but the
2620
        /// two versions of the XML specification have since been aligned).</param>
2621
        /// <returns>true if the name is valid, false if not</returns>
2622

    
2623
        public bool IsValid(Processor processor)
2624
        {
2625
            return IsValid();
2626
        }
2627
        
2628
        /// <summary>
2629
		/// Validate the <c>QName</c> against the XML rules for valid names.
2630
        /// </summary>
2631
        /// <returns>true if the name is valid, false if not</returns>
2632

    
2633
        public bool IsValid()
2634
        {
2635
            if(this.Prefix != String.Empty)
2636
            {
2637
                if (!JNameChecker.isValidNCName(Prefix))
2638
                {
2639
                    return false;
2640
                }
2641
            }
2642
            if (!JNameChecker.isValidNCName(this.LocalName))
2643
            {
2644
                return false;
2645
            }
2646
            return true;
2647
        }
2648

    
2649
		/// <summary>Get the prefix of the <c>QName</c>. This plays no role in operations such as comparison
2650
        /// of QNames for equality, but is retained (as specified in XPath) so that a string representation
2651
        /// can be reconstructed.
2652
        /// </summary>
2653
        /// <remarks>
2654
        /// Returns the zero-length string in the case of a QName that has no prefix.
2655
        /// </remarks>
2656

    
2657
        public String Prefix
2658
        {
2659
            get { return sqName.getPrefix(); }
2660
        }
2661

    
2662
		/// <summary>Get the namespace URI of the <c>QName</c>. Returns "" (the zero-length string) if the
2663
        /// QName is not in a namespace.
2664
        /// </summary>
2665

    
2666
        public String Uri
2667
        {
2668
            get { return sqName.getNamespaceURI(); }
2669
        }
2670

    
2671
		/// <summary>Get the local part of the <c>QName</c></summary>
2672

    
2673
        public String LocalName
2674
        {
2675
            get { return sqName.getLocalName(); }
2676
        }
2677

    
2678
        /// <summary>Get the expanded name, as a string using the notation devised by James Clark.
2679
        /// If the name is in a namespace, the resulting string takes the form <c>{uri}local</c>.
2680
        /// Otherwise, the value is the local part of the name.
2681
        /// </summary>
2682

    
2683
        public String ClarkName
2684
        {
2685
            get
2686
            {
2687
                string uri = Uri;
2688
                if (uri.Equals(""))
2689
                {
2690
                    return LocalName;
2691
                }
2692
                else
2693
                {
2694
                    return "{" + uri + "}" + LocalName;
2695
                }
2696
            }
2697
        }
2698

    
2699
        /// <summary>Get the expanded name in EQName format, that is <c>Q{uri}local</c>. A no namespace name is returned as <c>Q{}local</c>.
2700
        /// </summary>
2701
        public String EQName
2702
        {
2703
            get
2704
            {
2705
                return "Q{" + Uri + "}" + LocalName;
2706
            }
2707
        }
2708

    
2709
        /// <summary>
2710
        /// Convert the value to a string. The resulting string is the lexical form of the QName,
2711
        /// using the original prefix if there was one.
2712
        /// </summary>
2713

    
2714
        public override String ToString()
2715
        {
2716

    
2717
            if (Prefix.Equals(""))
2718
            {
2719
                return LocalName;
2720
            }
2721
            else
2722
            {
2723
				return Prefix + ":" + LocalName;
2724
            }
2725
        }
2726

    
2727
        /// <summary>
2728
		/// Get a hash code for the <c>QName</c>, to support equality matching. This supports the
2729
        /// semantics of equality, which considers only the namespace URI and local name, and
2730
        /// not the prefix.
2731
        /// </summary>
2732
        /// <remarks>
2733
        /// The algorithm for allocating a hash code does not depend on registering the QName 
2734
        /// with the <c>Processor</c>.
2735
        /// </remarks>
2736

    
2737
        public override int GetHashCode()
2738
        {
2739
            return sqName.hashCode();
2740
        }
2741

    
2742
        /// <summary>
2743
        /// Test whether two QNames are equal. This supports the
2744
        /// semantics of equality, which considers only the namespace URI and local name, and
2745
        /// not the prefix.
2746
        /// </summary>
2747
		/// <param name="other">The value to be compared with this <c>QName</c>. If this value is not a <c>QName</c>, the
2748
        /// result is always false. Otherwise, it is true if the namespace URI and local name both match.</param>
2749

    
2750
        public override bool Equals(Object other)
2751
        {
2752
            if (!(other is QName))
2753
            {
2754
                return false;
2755
            }
2756
            return sqName.equals(((QName)other).sqName);
2757
        }
2758

    
2759
        /// <summary>
2760
        /// Convert the value to an <c>XmlQualifiedName</c> (as defined in the
2761
        /// <c>System.Xml</c> package)
2762
        /// </summary>
2763
        /// <remarks>
2764
        /// Note that this loses the prefix.
2765
        /// </remarks>
2766

    
2767
        public XmlQualifiedName ToXmlQualifiedName()
2768
        {
2769
            return new XmlQualifiedName(LocalName, Uri);
2770
        }
2771

    
2772
		// internal method: Convert to a net.sf.saxon.value.QNameValue
2773

    
2774
        internal JQNameValue ToQNameValue()
2775
        {
2776
            return new JQNameValue(sqName.getPrefix(), sqName.getNamespaceURI(), sqName.getLocalName(), null);
2777
		}
2778

    
2779
		// internal method
2780

    
2781
        internal JStructuredQName ToStructuredQName()
2782
        {
2783
            return new JStructuredQName(Prefix, Uri, LocalName);
2784
        }
2785

    
2786
        // internal method
2787

    
2788
        internal JQName UnderlyingQName()
2789
        {
2790
            return sqName;
2791
        }
2792

    
2793

    
2794

    
2795

    
2796
    }
2797

    
2798

    
2799

    
2800

    
2801
    /// <summary>
2802
    /// This class is an implementation of <c>IEnumerator</c> that wraps
2803
	/// a (Java) <c>SequenceIterator</c>.
2804
    /// </summary>
2805
    /// <remarks>
2806
    /// Because the underlying value can be evaluated lazily, it is possible
2807
    /// for exceptions to occur as the sequence is being read.
2808
    /// </remarks>
2809

    
2810
    [Serializable]
2811
    internal class SequenceEnumerator<T> : IEnumerator<T>
2812
          where T : XdmItem
2813
    {
2814

    
2815
        private JSequenceXdmIterator iter;
2816
        private JItem current;
2817

    
2818
        internal SequenceEnumerator(JSequenceXdmIterator iter)
2819
        {
2820
            this.iter = iter;
2821
            current = null;
2822
        }
2823

    
2824

    
2825
        /// <summary>Return the current item in the sequence</summary>
2826
        /// <returns>An object which will always be an instance of <c>XdmItem</c></returns>
2827
        /// 
2828
        public XdmItem Current
2829
        {
2830
            get {
2831
                return current == null ? null : (XdmItem)XdmValue.Wrap(current);
2832
            }
2833
        }
2834

    
2835
        object IEnumerator.Current
2836
        {
2837
            get {
2838
                return Current;
2839
            }
2840
        }
2841

    
2842
        T IEnumerator<T>.Current
2843
        {
2844

    
2845
            get { return (T)Current; }
2846
        }
2847

    
2848
        /// <summary>Move to the next item in the sequence</summary>
2849
        /// <returns>true if there are more items in the sequence</returns>
2850

    
2851
        public bool MoveNext()
2852
        {
2853
            try
2854
            {
2855
                if (!iter.hasNext())
2856
                {
2857
                    return false;
2858
                }
2859
            }
2860
            catch (net.sf.saxon.s9api.SaxonApiUncheckedException e)
2861
            {
2862
                return false;
2863
            }
2864
            net.sf.saxon.s9api.XdmItem nextXdmItem = iter.next();
2865
                if (nextXdmItem != null)
2866
                {
2867
                    JItem nextItem = nextXdmItem.getUnderlyingValue();
2868
                    current = nextItem;
2869
                    return (nextItem != null);
2870
                }
2871
                return false;
2872
            
2873
        }
2874

    
2875
        /// <summary>Deprecated. Reset the enumeration so that the next call of
2876
        /// <c>MoveNext</c> will position the enumeration at the
2877
        /// first item in the sequence</summary>
2878
        [System.Obsolete("MethodAccessException no longer used")]
2879
        public void Reset()
2880
        {
2881
            
2882
        }
2883

    
2884
        /// <summary>
2885
        /// The Dispose method does not have any effect on this Enumerator
2886
        /// </summary>
2887
        public void Dispose()
2888
        {
2889
           
2890
        }
2891
    }
2892

    
2893
    /// <summary>
2894
	/// Implementation of the (Java) interface <c>SequenceIterator</c> that wraps
2895
	/// a (.NET) <c>IEnumerator</c>
2896
    /// </summary>
2897

    
2898
    internal class DotNetSequenceIterator : JSequenceIterator
2899
    {
2900
        // TODO: catch errors and throw an XPathException if necessary.
2901

    
2902
        IEnumerator iter;
2903
        int pos = 0;
2904

    
2905
        public DotNetSequenceIterator(IEnumerator iter)
2906
        {
2907
            this.iter = iter;
2908
        }
2909

    
2910
        public JItem next()
2911
        {
2912
            if (pos < 0)
2913
            {
2914
                return null;
2915
            }
2916
            bool more = iter.MoveNext();
2917
            if (more)
2918
            {
2919
                pos++;
2920
                XdmItem i = (XdmItem)iter.Current;
2921
                return (JItem)i.Unwrap();
2922
            }
2923
            else
2924
            {
2925
                pos = -1;
2926
                return null;
2927
            }
2928

    
2929
        }
2930

    
2931
        public JItem current()
2932
        {
2933
            if (pos < 0)
2934
            {
2935
                return null;
2936
            }
2937
            XdmItem i = (XdmItem)iter.Current;
2938
            return (JItem)i.Unwrap();
2939
        }
2940

    
2941
        public int position()
2942
        {
2943
            return pos;
2944
        }
2945

    
2946
        public void close()
2947
        {
2948
        }
2949

    
2950

    
2951
        public int getProperties()
2952
        {
2953
            return 0;
2954
        }
2955

    
2956
        public void forEachOrFail(JItemConsumer consumer)
2957
        {
2958
            JItem item = null;
2959

    
2960
            while ((item = next()) != null)
2961
            {
2962
                consumer.accept(item);
2963
            }
2964
        }
2965

    
2966
        public void forEachOrFail(JSequenceIterator value1, JItemConsumer consumer)
2967
        {
2968
            JItem item = null;
2969

    
2970
            while ((item = value1.next()) != null)
2971
            {
2972
                consumer.accept(item);
2973
            }
2974
        }
2975

    
2976
        public JGroundedValue materialize() {
2977
            return JSequenceExtent.fromIterator(this);
2978
        }
2979

    
2980

    
2981

    
2982
        public void Dispose()
2983
        {
2984
            throw new NotImplementedException();
2985
        }
2986

    
2987
        JGroundedValue JSequenceIterator.materialize()
2988
        {
2989
            return JSequenceExtent.fromIterator(this);
2990
        }
2991

    
2992

    
2993
    }
2994

    
2995
    /// <summary>
2996
    /// Enumeration identifying the thirteen XPath axes
2997
    /// </summary>
2998

    
2999
    public enum XdmAxis
3000
    {
3001
        /// <summary>The XPath ancestor axis</summary> 
3002
        Ancestor,
3003
        /// <summary>The XPath ancestor-or-self axis</summary> 
3004
        AncestorOrSelf,
3005
        /// <summary>The XPath attribute axis</summary> 
3006
        Attribute,
3007
        /// <summary>The XPath child axis</summary> 
3008
        Child,
3009
        /// <summary>The XPath descendant axis</summary> 
3010
        Descendant,
3011
        /// <summary>The XPath descandant-or-self axis</summary> 
3012
        DescendantOrSelf,
3013
        /// <summary>The XPath following axis</summary> 
3014
        Following,
3015
        /// <summary>The XPath following-sibling axis</summary> 
3016
        FollowingSibling,
3017
        /// <summary>The XPath namespace axis</summary> 
3018
        Namespace,
3019
        /// <summary>The XPath parent axis</summary> 
3020
        Parent,
3021
        /// <summary>The XPath preceding axis</summary> 
3022
        Preceding,
3023
        /// <summary>The XPath preceding-sibling axis</summary> 
3024
        PrecedingSibling,
3025
        /// <summary>The XPath self axis</summary> 
3026
        Self
3027
    }
3028

    
3029
    /// <summary>
3030
    /// An implementation of <code>IEnumerator</code> that iterates over an empty sequence.
3031
    /// </summary>
3032

    
3033
    public class EmptyEnumerator<T> : IEnumerator<T>
3034
       where T : XdmItem
3035
    {
3036

    
3037
        /// <summary>
3038
		/// Create an instance of the enumerator with the <c>XdmItem</c> as the generic type
3039
        /// </summary>
3040
        public static EmptyEnumerator<XdmItem> INSTANCE = new EmptyEnumerator<XdmItem>();
3041

    
3042
        /// <summary>
3043
		/// Create an instance of the enumerator with the <c>XdmNode</c> as the generic type
3044
        /// </summary>
3045
        public static EmptyEnumerator<XdmNode> NODE_INSTANCE = new EmptyEnumerator<XdmNode>();
3046

    
3047
        private EmptyEnumerator() { }
3048

    
3049
        /// <summary>
3050
        /// Reset the enumerator
3051
        /// </summary>
3052
        public void Reset() { }
3053
        
3054

    
3055

    
3056

    
3057
        object IEnumerator.Current
3058
        {
3059
            get
3060
            {
3061
                return null;
3062
            }
3063
        }
3064

    
3065
        /// <summary>
3066
        /// The current item in the enumerator
3067
        /// </summary>
3068
        T IEnumerator<T>.Current
3069
        {
3070
            get
3071
            {
3072
                return null;
3073
            }
3074
        }
3075

    
3076
        /// <summary>
3077
        /// Move to the next item in the enumerator..
3078
        /// </summary>
3079
        /// <returns>true if successful move, false otherwise.</returns>
3080
        public bool MoveNext()
3081
        {
3082
            return false;
3083
        }
3084

    
3085
		/// <summary>
3086
		/// The Dispose method is not implemented on this Enumerator
3087
		/// </summary>
3088
        public void Dispose()
3089
        {
3090
            throw new NotImplementedException();
3091
        }
3092
    }
3093

    
3094

    
3095
}
3096

    
3097
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3098
// Copyright (c) 2018 Saxonica Limited.
3099
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
3100
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
3101
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
3102
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(7-7/13)