Project

Profile

Help

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

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

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 : IXdmEnumerable<XdmItem>, IEnumerable
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>IXdmEnumerator</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 (IEnumerator<XdmItem>)EmptyEnumerator<XdmItem>.INSTANCE;
393
            }
394
            else if (value is JItem)
395
            {
396
                return (IEnumerator<XdmItem>)new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(JSingletonIterator.makeIterator((JItem)value)));
397
            }
398
            else
399
            {
400
                return (IEnumerator<XdmItem>)new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(value.iterate()));
401
            }
402
        }
403
        
404

    
405
        /// <summary>
406
        /// Get the i'th item in the value, counting from zero.
407
        /// </summary>
408
        /// <param name="i">the item that irequired, counting the first item in the sequence as item zero</param>
409
        /// <returns>the i'th item in the sequence making up the value, counting from zero.</returns>
410
        public XdmItem ItemAt(int i)
411
        {
412
            if (i < 0 || i >= Count) {
413
                throw new IndexOutOfRangeException("" + i);
414
            }
415
            try {
416
                JItem item = JSequenceTool.itemAt(value, i);
417
                return (XdmItem)XdmItem.Wrap(item);
418
            }
419
            catch (net.sf.saxon.trans.XPathException e) {
420
                throw new StaticError(e);
421
            }
422

    
423
        }
424

    
425

    
426
        /// <summary>
427
        /// Create a string representation of the value. The is the result of serializing
428
        /// the value using the adaptive serialization method.
429
        /// </summary>
430
        /// <returns>a string representation of the value</returns>
431
        public override String ToString() {
432
            return XdmValue.FromGroundedValueToJXdmValue(value).toString();
433

    
434
        }
435

    
436

    
437

    
438

    
439
        /// <summary>
440
        /// Return a new XdmValue containing the nodes present in this XdmValue,
441
        /// with duplicates eliminated, and sorted into document order
442
        /// </summary>
443
        /// <returns>the same nodes, sorted into document order, with duplicates eliminated</returns>
444
        public XdmValue DocumentOrder() {
445
            try
446
            {
447
                JSequenceIterator iter = value.iterate();
448
                JSequenceIterator sorted = new net.sf.saxon.expr.sort.DocumentOrderIterator(iter, net.sf.saxon.expr.sort.GlobalOrderComparer.getInstance());
449
                return XdmValue.Wrap(sorted.materialize());
450

    
451
            }
452
            catch (net.sf.saxon.trans.XPathException e) {
453
                throw new StaticError(e);
454
            }
455

    
456
        }
457

    
458
        /// <summary>
459
        /// Get the number of items in the sequence
460
        /// </summary>
461
        /// <returns>
462
        /// The number of items in the sequence. Note that for a single item (including
463
        /// a map or an array) this always returns 1 (one).
464
        /// </returns> 
465

    
466
        public int Count
467
        {
468
            get
469
            {
470
                if (value == null)
471
                {
472
                    return 0;
473
                }
474
                else if (value is JItem)
475
                {
476
                    return 1;
477
                }
478
                else
479
                {
480
                    return value.getLength();
481
                }
482
            }
483
        }
484

    
485
        /// <summary>
486
		/// Simplify an XDM value: that is, reduce it to the simplest possible form.
487
		/// </summary>
488
		/// <remarks>
489
        /// <list>
490
        /// <item>If the sequence is empty, the result will be an instance of <c>XdmEmptySequence</c></item>
491
        /// <item>If the sequence is a single node, the result will be an instance of <c>XdmNode</c></item>
492
        /// <item>If it is a single atomic value, it will be an instance of <c>XdmAtomicValue</c></item>
493
        /// <item>If it is a map, it will be an instance of <c>XdmMap</c></item>
494
        /// <item>If it is an array, it will be an instance of <c>XdmArray</c></item>
495
        /// <item>If it is any other kind of function, it will be an instance of <c>XdmFunctionItem</c></item>
496
        /// <item>If it is a wrapper around a .NET object, it will be an instance of <c>XdmExternalObjectValue</c></item>
497
        /// </list>
498
		/// </remarks>
499
		/// <returns>The XDM value reduced to the simplest possible form</returns>
500

    
501
        public XdmValue Simplify
502
        {
503
            get
504
            {
505
                switch (value.getLength())
506
                {
507
                    case 0:
508
                        if (this is XdmEmptySequence)
509
                        {
510
                            return this;
511
                        }
512
                        return XdmEmptySequence.INSTANCE;
513

    
514
                    case 1:
515
                        if (this is XdmItem)
516
                        {
517
                            return this;
518
                        }
519
                        return XdmValue.Wrap(value);
520

    
521
                    default:
522
                        return this;
523
                }
524
            }
525
        }
526

    
527
    }
528

    
529

    
530

    
531
    /// <summary inherits="XdmItem">
532
    /// The class <c>XdmExternalObjectValue</c> represents an XDM item that wraps an external .NET object.
533
    /// As such, it is outside the scope of the W3C XDM specification (but permitted as an extension).
534
    /// </summary>
535
    [Serializable]
536
    public class XdmExternalObjectValue : XdmItem
537
    {
538

    
539
        /// <summary>
540
        /// Constructor to create an <c>XdmExternalObjectValue</c> that wraps a supplied .NET object
541
        /// </summary>
542
        /// <param name="o">the supplied .NET object</param>
543
        public XdmExternalObjectValue(object o)
544
        {
545
            value = new JDotNetObjectValue(o);
546
        }
547

    
548
        /// <summary>
549
        /// Determine whether the item is an atomic value
550
        /// </summary>
551
        /// <returns>
552
        /// false (the item is not an atomic value)
553
        /// </returns>
554
        public override bool IsAtomic()
555
        {
556
            return false;
557
        }
558

    
559

    
560

    
561
        /// <summary>
562
        /// Compare two external objects for equality. Two instances of XdmExternalObjectValue are equal
563
        /// if the .NET objects that they wrap are equal.
564
        /// </summary>
565
        /// <param name="other">the object to be compared</param>
566
        /// <returns>tre if the other object is an XdmExternalObjectValue and the two wrapped objects are 
567
        /// equal under the equals method.</returns>
568
        public bool Equals(XdmExternalObjectValue other) {
569
            return other is XdmExternalObjectValue && value == other.value;
570
        }
571

    
572
        /// <summary>
573
        /// Return a hash code for the object. This respects the semantics of equals(Object)
574
        /// </summary>
575
        /// <returns>a suitable hash code</returns>
576
        public override int GetHashCode() {
577
            return ((java.lang.Object)value).hashCode();
578
        }
579

    
580
        /// <summary>
581
        /// Get the wrapped .NET object
582
        /// </summary>
583
        /// <returns>the wrapped object</returns>
584
        public object GetExternalObject()
585
        {
586
            return ((JObjectValue)value).getObject();
587
        }
588

    
589
        /// <summary>
590
        /// Get the result of converting the external value to a string.
591
        /// </summary>
592
        /// <returns>the result of applying <c>ToString()</c> to the wrapped external object</returns>
593
        public override string ToString()
594
        {
595
            return GetExternalObject().ToString();
596
        }
597
    }
598
    
599
    /// <summary inherits="XdmValue">
600
    /// The class <c>XdmItem</c> represents an item in a sequence, as defined
601
    /// by the XDM data model. An item may be an atomic value, a node, a function (including maps
602
    /// and arrays), or an external object.
603
    /// </summary>
604
    /// <remarks>
605
    /// <para>An item is a member of a sequence, but it can also be considered as
606
    /// a sequence (of length one) in its own right. <c>XdmItem</c> is a subtype
607
    /// of <c>XdmValue</c> because every item in the XDM data model is also a
608
    /// value.</para>
609
    /// <para>It cannot be assumed that every sequence of length one will always be 
610
    /// represented by an <c>XdmItem</c>. It is quite possible for an <c>XdmValue</c>
611
	/// that is not an <c>XdmItem</c> to hold a singleton sequence. Use <see cref="XdmValue.Simplify"/> 
612
    /// to ensure that a singleton is represented as an <c>XdmItem</c>.</para>
613
    /// </remarks> 
614

    
615
    [Serializable]
616
    public abstract class XdmItem : XdmValue
617
    {
618

    
619
        /// <summary>
620
        /// Determine whether the item is an atomic value
621
        /// </summary>
622
        /// <returns>
623
        /// true if the item is an atomic value, false if it is a node, function, or external object
624
        /// </returns>
625

    
626
        public abstract bool IsAtomic();
627
        
628
        /// <summary>
629
		/// Get the string value of the item. 
630
		/// </summary>
631
		/// <remarks>
632
        /// <list>
633
        /// <item>For an atomic value, the result is the same as casting the value to a string.</item>
634
        /// <item>For a node, the method returns the string
635
		/// value of the node. This is not the same as the result of <see cref="XdmNode.ToString()"/>, which
636
        /// returns the result of serializing the node.</item>
637
        /// <item>For a function, including a map or array, the result is an error.</item>
638
        /// <item>For an external object, the result is the same as the result of calling <c>ToString()</c>
639
        /// on the external object.</item>
640
		/// </list>
641
		/// <para>In all cases the result is the same as applying the XPath <c>string()</c> function.</para>
642
		/// </remarks>
643
        /// <returns>The result of converting the item to a string</returns>
644
        
645
        public String GetStringValue() {
646
            return ((JItem)value).getStringValue();
647
        }
648

    
649
        internal static net.sf.saxon.s9api.XdmItem FromXdmItemItemToJXdmItem(XdmItem value)
650
        {
651
            return (net.sf.saxon.s9api.XdmItem)net.sf.saxon.s9api.XdmValue.wrap(value== null ? null : value.value);
652
        }
653

    
654
        /// <summary>
655
        /// Determine whether this item matches a given item type
656
        /// </summary>
657
        /// <param name="typei">typei the item type to be tested against this item</param>
658
        /// <returns>true if the item matches this item type, false if it does not match.</returns>
659
        public bool Matches(XdmItemType typei)
660
        {
661
            return typei.Matches(this);
662
        }
663
    }
664

    
665
    /// <summary inherits="XdmItem">
666
    /// The class <c>XdmAtomicValue</c> represents an item in an XDM sequence
667
    /// that is an atomic value. The value may belong to any of the 19 primitive types
668
    /// defined in XML Schema, or to a type derived from these primitive types, or to 
669
    /// the XDM-specific type <c>xs:untypedAtomic</c>
670
    /// </summary>
671
    /// <remarks>
672
    /// Note that there is no guarantee that every <c>XdmValue</c> comprising a single
673
    /// atomic value will be an instance of this class. To force this, use the <c>Simplify</c>
674
    /// property of the <c>XdmValue</c>.
675
    /// </remarks>
676

    
677
    [Serializable]
678
    public class XdmAtomicValue : XdmItem
679
    {
680
		// Internal constructor
681

    
682
        internal XdmAtomicValue() { }
683

    
684
        /// <summary>
685
        /// Determine whether the item is an atomic value
686
        /// </summary>
687
        /// <returns>
688
        /// true (the item is an atomic value)
689
        /// </returns>
690

    
691
        public override bool IsAtomic()
692
        {
693
            return true;
694
        }
695

    
696
        /// <summary>
697
        /// Construct an atomic value of type <c>xs:string</c>
698
        /// </summary>
699
        /// <param name="str">The string value</param>
700

    
701
        public XdmAtomicValue(String str)
702
        {
703
            this.value = new JStringValue(str);
704
        }
705

    
706
        /// <summary>
707
        /// Construct an atomic value of type <c>xs:integer</c> from a supplied <c>long</c>
708
        /// </summary>
709
        /// <param name="i">The integer value</param>
710

    
711
        public XdmAtomicValue(long i)
712
        {
713
            this.value = JInt64Value.makeDerived(i, (JAtomicType)XdmAtomicType.LONG.Unwrap().getUnderlyingItemType());
714
        }
715

    
716

    
717
        /// <summary>
718
        /// Construct an atomic value of type <c>xs:integer</c> from a supplied <c>long</c>
719
        /// </summary>
720
        /// <param name="i">The integer value</param>
721

    
722
        public XdmAtomicValue(int i)
723
        {
724
            this.value = JInt64Value.makeDerived(i, (JAtomicType)XdmAtomicType.INT.Unwrap().getUnderlyingItemType());
725
        }
726

    
727
        /// <summary>
728
        /// Construct an atomic value of type <c>xs:integer</c> from a supplied <c>byte</c>
729
        /// </summary>
730
        /// <param name="i">The integer value, in the range -128 to +127</param>
731
        public XdmAtomicValue(byte i)
732
        {
733
            this.value = JInt64Value.makeDerived(i, (JAtomicType)XdmAtomicType.BYTE.Unwrap().getUnderlyingItemType());
734
        }
735

    
736
        /// <summary>
737
        /// Construct an atomic value of type <c>xs:decimal</c>
738
        /// </summary>
739
        /// <param name="d">The decimal value</param>
740

    
741
        public XdmAtomicValue(decimal d)
742
        {
743
            this.value = new JBigDecimalValue(new JBigDecimal(d.ToString()));
744
        }
745

    
746
        /// <summary>
747
        /// Construct an atomic value of type <c>xs:float</c>
748
        /// </summary>
749
        /// <param name="f">The float value</param>        
750

    
751
        public XdmAtomicValue(float f)
752
        {
753
            this.value = new JFloatValue(f);
754
        }
755

    
756
        /// <summary>
757
        /// Construct an atomic value of type <c>xs:double</c>
758
        /// </summary>
759
        /// <param name="d">The double value</param>
760

    
761
        public XdmAtomicValue(double d)
762
        {
763
            this.value = new JDoubleValue(d);
764
        }
765

    
766
        /// <summary>
767
        /// Construct an atomic value of type <c>xs:boolean</c>
768
        /// </summary>
769
        /// <param name="b">The boolean value</param>
770

    
771
        public XdmAtomicValue(bool b)
772
        {
773
            this.value = JBooleanValue.get(b);
774
        }
775

    
776
        /// <summary>
777
        /// Construct an atomic value of type <c>xs:anyURI</c>
778
        /// </summary>
779
        /// <param name="u">The uri value</param>
780

    
781
        public XdmAtomicValue(Uri u)
782
        {
783
            this.value = new JAnyURIValue(u.ToString());
784
        }
785

    
786
        /// <summary>
787
        /// Construct an atomic value of type <c>xs:QName</c>
788
        /// </summary>
789
        /// <param name="q">The QName value</param>                
790

    
791
        public XdmAtomicValue(QName q)
792
        {
793
            this.value = new JQNameValue(
794
                q.Prefix, q.Uri, q.LocalName);
795
		}
796

    
797
		/// <summary>
798
		/// Construct an atomic value of a given type
799
		/// </summary>
800
		/// <param name="lexicalForm">The string representation of the value (any value that is acceptable
801
		/// in the lexical space, as defined by XML Schema Part 2). Whitespace normalization as defined by
802
		/// the target type will be applied to the value.</param>
803
		/// <param name="type">The type given as an <c>XdmAtomicType</c></param>
804

    
805
        public XdmAtomicValue(String lexicalForm, XdmAtomicType type) {
806
            net.sf.saxon.type.ItemType it = type.Unwrap().getUnderlyingItemType();
807
            if (!it.isPlainType()) {
808
                throw new StaticError(new net.sf.saxon.s9api.SaxonApiException("Requested type is not atomic"));
809
            }
810
            if (((JAtomicType)it).isAbstract()) {
811
                throw new StaticError(new net.sf.saxon.s9api.SaxonApiException("Requested type is not namespace-sensitive"));
812

    
813
            }
814
            try
815
            {
816
                net.sf.saxon.type.StringConverter Converter = ((JAtomicType)it).getStringConverter(type.Unwrap().getConversionRules());
817
                this.value = Converter.convertString(lexicalForm).asAtomic();
818
            }
819
            catch (Exception ex) { }
820
            
821
        }
822

    
823
        /// <summary>
824
        /// Construct an atomic value of a given built-in or user-defined type
825
        /// </summary>
826
        /// <example>
827
        ///   <code>XdmAtomicValue("abcd", QName.XDT_UNTYPED_ATOMIC, processor)</code>
828
        ///   <para>creates an untyped atomic value containing the string "abcd"</para>
829
        /// </example>
830
        /// <param name="lexicalForm">The string representation of the value (any value that is acceptable
831
        /// in the lexical space, as defined by XML Schema Part 2). Whitespace normalization as defined by
832
        /// the target type will be applied to the value.</param>
833
        /// <param name="type">The QName giving the name of the target type. This must be an atomic
834
        /// type, and it must not be a type that is namespace-sensitive (QName, NOTATION, or types derived
835
        /// from these). If the type is a user-defined type then its definition must be present
836
        /// in the schema cache maintained by the <c>SchemaManager</c>.</param> 
837
        /// <param name="processor">The <c>Processor</c> object. This is needed for looking up user-defined
838
        /// types, and also because some conversions are context-sensitive, for example they depend on the
839
        /// implicit timezone or the choice of XML 1.0 versus XML 1.1 for validating names.</param>
840
        /// <exception cref="ArgumentException">Thrown if the type is unknown or unsuitable, or if the supplied string is not
841
        /// a valid lexical representation of a value of the given type.</exception>
842

    
843
        public XdmAtomicValue(String lexicalForm, QName type, Processor processor)
844
        {
845
			JConfiguration jconfig = processor.Implementation;
846
            int fp = jconfig.getNamePool().getFingerprint(type.Uri, type.LocalName);
847
            if (fp == -1)
848
            {
849
                throw new ArgumentException("Unknown name " + type);
850
            }
851
			JSchemaType st = jconfig.getSchemaType(new JStructuredQName("", type.Uri.ToString(), type.LocalName));
852
            if (st == null)
853
            {
854
                throw new ArgumentException("Unknown type " + type);
855
            }
856
            if (!(st is JAtomicType))
857
            {
858
                throw new ArgumentException("Specified type " + type + " is not atomic");
859
            }
860
            if (((JAtomicType)st).isNamespaceSensitive())
861
            {
862
                throw new ArgumentException("Specified type " + type + " is namespace-sensitive");
863
            }
864
			JConversionResult result = ((JAtomicType)st).getStringConverter(jconfig.getConversionRules()).convertString((JCharSequence)lexicalForm);
865
 
866
            if (result is JValidationFailure)
867
            {
868
                throw new ArgumentException(((JValidationFailure)result).getMessage());
869
            }
870
            this.value = (JAtomicValue)result;
871
        }
872

    
873

    
874
        
875
        /// <summary>
876
		/// Create an atomic value of a type appropriate to the supplied value. 
877
		/// </summary>
878
		/// <remarks>
879
		/// The supplied value must be one of the following:
880
        /// <list>
881
        /// <item>An instance of the Saxon Java class <c>net.sf.saxon.value.AtomicValue</c></item>
882
        /// <item>A <c>Boolean</c> - returns an instance of <c>xs:boolean</c></item>
883
        /// <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>
884
        /// <item>A <c>Char</c> - TODO ???????</item>
885
        /// <item>A <c>String</c> - returns an instance of <c>xs:string</c></item>
886
        /// <item>A <c>Double</c> - returns an instance of <c>xs:double</c></item>
887
        /// <item>A <c>Float</c> - returns an instance of <c>xs:float</c></item>
888
        /// <item>A <c>decimal</c> - returns an instance of <c>xs:decimal</c></item>
889
        /// <item>A <c>URI</c> - returns an instance of <c>xs:anyURI</c></item>
890
        /// <item>A <c>QName</c> - returns an instance of <c>xs:QName</c></item>
891
        /// </list>
892
		/// </remarks>
893
        /// <param name="value">The value to be converted.</param>
894
        /// <returns>The converted value</returns>
895

    
896
        public static XdmAtomicValue MakeAtomicValue(object value)
897
        {
898
            if (value is JAtomicValue)
899
            {
900
                return (XdmAtomicValue)XdmValue.Wrap((JAtomicValue)value);
901
            }
902
            else if (value is Boolean)
903
            {
904
                return new XdmAtomicValue((Boolean)value);
905
            }
906
            else if (value is int)
907
            {
908
                return new XdmAtomicValue((int)value);
909
            }
910
            else if (value is long)
911
            {
912
                return new XdmAtomicValue((long)value);
913
            }
914
            else if (value is short)
915
            {
916
                return new XdmAtomicValue((short)value);
917
            }
918
            else if (value is Char)
919
            {
920
                return new XdmAtomicValue((long)value);
921
            }
922
            else if (value is Byte)
923
            {
924
                return new XdmAtomicValue((Byte)value);
925
            }
926
            else if (value is String)
927
            {
928
                return new XdmAtomicValue((String)value);
929
            }
930
            else if (value is Double)
931
            {
932
                return new XdmAtomicValue((Double)value);
933
            }
934
            else if (value is float)
935
            {
936
                return new XdmAtomicValue((float)value);
937
            }
938
            else if (value is decimal)
939
            {
940
                return new XdmAtomicValue((decimal)value);
941
            }
942
            else if (value is Uri)
943
            {
944
                return new XdmAtomicValue((Uri)value);
945
            }
946
            else if (value is QName)
947
            {
948
                return new XdmAtomicValue((QName)value);
949
            }
950
            if (value is XdmAtomicValue)
951
            {
952
                return (XdmAtomicValue)value;
953
            }
954
            else
955
            {
956
                throw new ArgumentException(value.ToString());
957
            }
958
        }
959

    
960

    
961
        /// <summary>
962
        /// Get the value converted to a boolean using the XPath casting rules
963
        /// </summary>
964
        /// <returns>the result of converting to a boolean (Note: this is not the same as the
965
        /// effective boolean value).</returns> 
966

    
967
        public bool GetBooleanValue()
968
        {
969
            JAtomicValue av = (JAtomicValue)this.value;
970
            if (av is JBooleanValue) {
971
                return ((JBooleanValue)av).getBooleanValue();
972
            } else if (av is JNumericValue) {
973
                return !av.isNaN() && ((JNumericValue)av).signum() != 0;
974
            } else if (av is JStringValue) {
975
                String s = av.getStringValue().Trim();
976
                return "1".Equals(s) || "true".Equals(s);
977
            } else {
978
                throw new ArgumentException("Cannot cast item to a boolean");
979
            }
980
        }
981

    
982

    
983
        /// <summary>
984
        /// Get the value converted to a long using the XPath casting rules
985
        /// </summary>
986
        /// <returns>the result of converting to a long</returns>
987

    
988
        public long GetLongValue()
989
        {
990
            JAtomicValue av = (JAtomicValue)this.value;
991
            if (av is JBooleanValue) {
992
                return ((JBooleanValue)av).getBooleanValue() ? 0L : 1L;
993
            } else if (av is JNumericValue) {
994
            try {
995
                return ((JNumericValue)av).longValue();
996
            } catch (Exception) {
997
                throw new ArgumentException("Cannot cast item to an integer");
998
            }
999
            } else if (av is JStringValue) {
1000
                JStringToDouble converter = JStringToDouble.getInstance();
1001
                return (long)converter.stringToNumber(av.getStringValueCS());
1002
            } else {
1003
                throw new ArgumentException("Cannot cast item to an integer");
1004
            }
1005
        }
1006

    
1007

    
1008
        /// <summary>
1009
		/// Get the value converted to a double using the XPath casting rules.
1010
		/// </summary>
1011
        /// <remarks>If the value is a string, the XSD 1.1 rules are used, which means that the string
1012
		/// "+INF" is recognised.</remarks>
1013
        /// <returns>the result of converting to a double</returns>
1014

    
1015
        public double GetDoubleValue()
1016
        {
1017
            JAtomicValue av = (JAtomicValue)this.value;
1018
            if (av is JBooleanValue) {
1019
                return ((JBooleanValue)av).getBooleanValue() ? 0.0 : 1.0;
1020
            } else if (av is JNumericValue) {
1021
                return ((JNumericValue)av).getDoubleValue();
1022
            } else if (av is JStringValue) {
1023
            try {
1024
                JStringToDouble converter = JStringToDouble11.getInstance();
1025
                return converter.stringToNumber(av.getStringValueCS());
1026
            } catch (Exception e) {
1027
                throw new ArgumentException(e.Message);
1028
            }
1029
            } else {
1030
                throw new ArgumentException("Cannot cast item to a double");
1031
            }
1032
        }
1033

    
1034

    
1035
        /// <summary>
1036
        /// Get the value converted to a decimal using the XPath casting rules
1037
        /// </summary>
1038
        /// <returns>the result of converting to a decimal</returns>
1039

    
1040
        public Decimal GetDecimalValue() 
1041
        {
1042
            JAtomicValue av = (JAtomicValue)this.value;
1043
            if (av is JBooleanValue) {
1044
                return ((JBooleanValue)av).getBooleanValue() ? 0  : 1;
1045
            } else if (av is JNumericValue) {
1046
                try {
1047
                    return Convert.ToDecimal(((JNumericValue)av).getDecimalValue().toString());
1048
                } catch (Exception) {
1049
                    throw new ArgumentException("Cannot cast item to a decimal");
1050
                }   
1051
            } else if (av is JStringValue) {
1052
                return Convert.ToDecimal(av.getStringValueCS().toString());
1053
            } else {
1054
                throw new ArgumentException("Cannot cast item to a decimal");
1055
            }
1056
        }
1057

    
1058

    
1059

    
1060
        /// <summary>
1061
        /// Convert the atomic value to a string
1062
        /// </summary>
1063
        /// <returns>The value converted to a string, according to the rules
1064
        /// of the XPath cast expression</returns>        
1065

    
1066
        public override String ToString()
1067
        {
1068
            return ((JAtomicValue)value).getStringValue();
1069
        }
1070
        
1071
        /// <summary>
1072
        /// Compare two atomic values for equality
1073
        /// </summary>
1074
        /// <returns>The result of the equality comparison, using the rules of the
1075
		/// <c>op:is-same-key()</c> comparison used for comparing key values in maps</returns>
1076
        
1077
        public override Boolean Equals(object other)
1078
        {
1079
            if (other is XdmAtomicValue)
1080
            {
1081
                return ((JAtomicValue)value).asMapKey().Equals(((JAtomicValue)((XdmAtomicValue)other).value).asMapKey());
1082

    
1083
            }
1084
            else
1085
            {
1086
                return false;
1087
            }
1088
        }
1089
        
1090
        /// <summary>
1091
        /// Get a hash code to support equality comparison
1092
        /// </summary>
1093
        /// <returns>A suitable hash code</returns>
1094
        
1095
        public override int GetHashCode()
1096
        {
1097
            return ((JAtomicValue)value).asMapKey().GetHashCode();
1098
        }         
1099

    
1100
        /// <summary>
1101
        /// Get the name of the value's XDM type
1102
        /// </summary>
1103
		/// <returns>The type of the value, as a QName.</returns>
1104

    
1105

    
1106
        public QName GetTypeName()
1107
        {
1108
            JStructuredQName sqname = ((JAtomicValue)value).getItemType().getStructuredQName();
1109
            return new QName(sqname.getPrefix(),
1110
                             sqname.getURI(),
1111
                             sqname.getLocalPart());
1112
        }
1113
        
1114
        /// <summary>
1115
        /// Get the name of the value's XDM type
1116
        /// </summary>
1117
        /// <param name="processor">The <code>Processor</code> object. 
1118
        /// This parameter is no longer used, but is accepted for backwards compatibility.</param>
1119
		/// <returns>The type of the value, as a QName.</returns>
1120

    
1121

    
1122
        public QName GetTypeName(Processor processor)
1123
        {
1124
            return GetTypeName();
1125
        }
1126

    
1127
        /// <summary>
1128
        /// Get the name of the primitive type of the value
1129
        /// </summary>
1130
        /// <returns>The primitive type of the value, as a QName. This will be the name of
1131
        /// one of the primitive types defined in XML Schema Part 2, or the XPath-defined
1132
        /// type <c>xs:untypedAtomic</c>. For the purposes of this method, <c>xs:integer</c> is considered
1133
        /// to be a primitive type.
1134
        /// </returns>
1135

    
1136

    
1137
        public QName GetPrimitiveTypeName()
1138
        {
1139
            int fp = ((JAtomicValue)value).getItemType().getPrimitiveType();
1140
            return new QName(JStandardNames.getPrefix(fp),
1141
                             JStandardNames.getURI(fp),
1142
                             JStandardNames.getLocalName(fp));
1143
        }
1144

    
1145
        /// <summary>Get the value as a CLI object of the nearest equivalent type.</summary>
1146
        /// <remarks>
1147
        /// <para>The return type is as follows:</para>
1148
        /// <list>
1149
		/// <item><c>xs:string</c> - String</item>
1150
		/// <item><c>xs:integer</c> - Long</item>
1151
		/// <item><c>xs:decimal</c> - Decimal</item>
1152
		/// <item><c>xs:double</c> - Double</item>
1153
		/// <item><c>xs:float</c> - Float</item>
1154
		/// <item><c>xs:boolean</c> - Bool</item>
1155
		/// <item><c>xs:QName</c> - QName</item>
1156
		/// <item><c>xs:anyURI</c> - Uri</item>
1157
		/// <item><c>xs:untypedAtomic</c> - String</item>
1158
        /// <item>wrapped external object - the original external object</item>
1159
        /// <item>Other types - currently String, but this may change in the future</item>
1160
        /// </list>
1161
        /// </remarks>
1162
        /// <returns>The value converted to the most appropriate CLI type</returns>
1163

    
1164
        public Object Value
1165
        {
1166
            get
1167
            {
1168
                if (value is JIntegerValue)
1169
                {
1170
                    return ((JIntegerValue)value).longValue();
1171
                }
1172
                else if (value is JDoubleValue)
1173
                {
1174
                    return ((JDoubleValue)value).getDoubleValue();
1175
                }
1176
                else if (value is JFloatValue)
1177
                {
1178
                    return ((JFloatValue)value).getFloatValue();
1179
                }
1180
                else if (value is JDecimalValue)
1181
                {
1182
                    return Decimal.Parse(((JDecimalValue)value).getStringValue());
1183
                }
1184
                else if (value is JBooleanValue)
1185
                {
1186
                    return ((JBooleanValue)value).getBooleanValue();
1187
                }
1188
                else if (value is JAnyURIValue)
1189
                {
1190
                    return new Uri(((JAnyURIValue)value).getStringValue());
1191
                }
1192
                else if (value is JQNameValue)
1193
                {
1194
                    return new QName((JQNameValue)value);
1195
                }
1196
                else if (value is JDotNetObjectValue) // TODO: can't happen?
1197
                {
1198
                    return ((JDotNetObjectValue)value).getObject();
1199
                }
1200
                else
1201
                {
1202
                    return ((JAtomicValue)value).getStringValue();
1203
                }
1204
            }
1205
        }
1206

    
1207

    
1208
    }
1209

    
1210
    /// <summary inherits="XdmItem">
1211
    /// The class <c>XdmFunctionItem</c> represents an item in an XDM sequence
1212
    /// that holds a function.
1213
    /// </summary>
1214
    /// <remarks>
1215
    /// <para>Note that there is no guarantee that every <c>XdmValue</c> comprising a single
1216
    /// function item will be an instance of this class. To force this, use the <c>Simplify</c>
1217
    /// property of the <c>XdmValue</c>.</para>
1218
    /// <para>At present the only way of creating an instance of this class is as the result of
1219
    /// an XPath or XQuery expression that returns a function item.</para>
1220
    /// </remarks>
1221

    
1222
    [Serializable]
1223
    public class XdmFunctionItem : XdmItem
1224
    {
1225
        /// <summary>
1226
        /// The name of the function, as a QName
1227
        /// </summary>
1228
		/// <returns>The name of the function. The result will be null if the function is anonymous.</returns>
1229
        
1230
        public QName FunctionName
1231
        {
1232
            get
1233
            {
1234
                JStructuredQName sqname = ((JFunction)value).getFunctionName();
1235
                return (sqname == null ? null : QName.FromStructuredQName(sqname));
1236
            }
1237
        }
1238

    
1239
        /// <summary>
1240
        /// The arity of the function, that is, the number of arguments it expects
1241
        /// </summary>
1242
		/// <returns>The number of arguments that the function takes</returns>
1243

    
1244
        public int Arity
1245
        {
1246
            get
1247
            {
1248
                return ((JFunction)value).getArity();
1249
            }
1250
        }
1251

    
1252
        /// <summary>
1253
        /// Determine whether the item is an atomic value
1254
        /// </summary>
1255
        /// <returns>
1256
        /// false (a function item is not an atomic value)
1257
        /// </returns>
1258

    
1259
        public override bool IsAtomic()
1260
        {
1261
            return false;
1262
        }
1263

    
1264

    
1265
            /// <summary>
1266
            /// Invoke the function
1267
            /// </summary>
1268
            /// <param name="arguments">The arguments to the function</param>
1269
            /// <param name="processor">The Saxon processor, used to provide context information</param>
1270
            /// <returns>The result of calling the function</returns>
1271
            /// 
1272
            public XdmValue Invoke(XdmValue[] arguments, Processor processor)
1273
        {
1274
            JXdmValue[] args = new JXdmValue[arguments.Length];
1275
            for (int i = 0; i < arguments.Length; i++)
1276
            {
1277
                args[i] = FromGroundedValueToJXdmValue(arguments[i].value);
1278
            }
1279
            JFunction function = (JFunction)value;
1280
            net.sf.saxon.s9api.XdmFunctionItem functionItem = new net.sf.saxon.s9api.XdmFunctionItem(function);
1281
            JXdmValue result = functionItem.call(processor.JProcessor, args);
1282
           
1283
            return XdmValue.Wrap(result.getUnderlyingValue());
1284
        }
1285
    }
1286

    
1287
    /// <summary inherits="XdmFunctionItem">
1288
    /// The class <c>XdmArray</c> represents an array item in an XDM 3.1 sequence:
1289
    /// this is a new kind of item in the XDM data model. An array is a list of zero or 
1290
    /// more members, each of which is an arbitrary XDM value. An array is also a function:
1291
    /// it maps a positive integer to the array member found at that position in the array.
1292
    /// </summary>
1293
    [Serializable]
1294
    public class XdmArray : XdmFunctionItem
1295
    {
1296

    
1297

    
1298
		///<summary> Constructor to create an empty <c>XdmArray</c></summary>
1299
        public XdmArray() {
1300
            this.value = JSimpleArrayItem.EMPTY_ARRAY;
1301
        }
1302

    
1303
        ///<summary>Create an <c>XdmArray</c> whose members are single items, corresponding
1304
        ///one-to-one with the items making up a supplied sequence.</summary>
1305
        ///<param name="value">A sequence of items; each item becomes a member of the array.</param>
1306
        public XdmArray(XdmValue value)
1307
        {
1308
            int length = value.Count;
1309
            JArrayList list = new JArrayList(length);
1310
            foreach (XdmItem item in value.GetList())
1311
            {
1312
                list.add(item.Unwrap());
1313
            }
1314
            this.value = new JSimpleArrayItem(list);
1315
        }
1316

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

    
1321

    
1322
        public XdmArray(XdmValue[] members) {
1323
            JArrayList list = new JArrayList(members.Length);
1324
            for (int i =0; i< members.Length;i++) {
1325
                list.add(members[i].Unwrap());
1326
            }
1327
            this.value = new JSimpleArrayItem(list);
1328
        }
1329

    
1330
		// Internal constructor
1331

    
1332
        internal XdmArray(JArrayList list)
1333
        {
1334
            this.value = new JSimpleArrayItem(list);
1335
        }
1336

    
1337
		// Internal constructor
1338

    
1339
        internal XdmArray(JArrayItem array) {
1340
            this.value = array;
1341
        }
1342

    
1343

    
1344
        /// <summary>Create an <c>XdmArray</c> supplying the members as a list of <c>XdmValue</c> objects</summary>
1345
        /// <param name="members">A sequence of <c>XdmValue</c> objects. Note that if this is supplied as 
1346
        /// a list or similar collection, subsequent changes to the list/collection will have no effect on 
1347
		/// the <c>XdmValue</c>.</param>
1348
		/// <remarks>Note that the argument can be a single <c>XdmValue</c> representing a sequence, in which case the
1349
        ///  constructed array will have one member for each item in the supplied sequence.</remarks>
1350
    
1351
        public XdmArray(List<XdmValue> members) {
1352
            JArrayList list = new JArrayList(members.Count);
1353
            for (int i = 0; i < members.Count; i++)
1354
            {
1355
                list.add(members[i].Unwrap());
1356
            }
1357
            this.value = new JSimpleArrayItem(list);
1358
        }
1359

    
1360
        /// <summary>
1361
        /// Get the number of members in the array
1362
        /// </summary>
1363
        /// <returns>the number of members in the array.</returns> 
1364
		/// <remarks>(Note that the <see cref="XdmValue.Count"/> property returns 1 (one),
1365
        /// because an XDM array is an item.)</remarks>
1366
        public int ArrayLength() {
1367
            return ((JArrayItem)value).arrayLength();
1368
        }
1369

    
1370
        /// <summary>
1371
        /// Get the n'th member in the array, counting from zero.
1372
        /// </summary>
1373
		/// <param name="n">the position of the member that is required, counting the first member in 
1374
		/// the array as member zero</param>
1375
        /// <returns>the n'th member in the sequence making up the array, counting from zero</returns>
1376
        public XdmValue Get(int n) {
1377
            try {
1378
                JSequence member = ((JArrayItem)value).get(n);
1379
                return XdmValue.Wrap(member);
1380
            }
1381
            catch (Exception) {
1382
                throw new IndexOutOfRangeException();
1383
            }
1384
        }
1385

    
1386

    
1387
        /// <summary>
1388
        /// Create a new array in which one member is replaced with a new value.
1389
        /// </summary>
1390
        /// <param name="n">the position of the member that is to be replaced, counting the first member
1391
        /// in the array as member zero</param>
1392
        /// <param name="valuei">the new value</param>
1393
        /// <returns>the new array</returns>
1394
        public XdmArray Put(int n, XdmValue valuei) {
1395
            try {
1396
                return (XdmArray)XdmValue.Wrap(((JArrayItem)this.value).put(n, valuei.value));
1397
            } catch (Exception) {
1398
                throw new IndexOutOfRangeException();
1399
            }
1400
        }
1401

    
1402

    
1403
        /// <summary>
1404
        /// Append a new member to an array
1405
        /// </summary>
1406
        /// <param name="value">the new member</param>
1407
        /// <returns>a new array, one item longer than the original</returns>
1408
        public XdmArray AppendMember(XdmValue value) {
1409
            try {
1410
                JGroundedValue member = value.value;
1411
                JArrayItem newArray = net.sf.saxon.ma.arrays.ArrayFunctionSet.ArrayAppend.append((JArrayItem)this.value, member);
1412
                return (XdmArray)Wrap(newArray);
1413
            }
1414
            catch (net.sf.saxon.trans.XPathException e) {
1415
                throw new StaticError(e);
1416
            }
1417
        }
1418

    
1419
        /// <summary>
1420
        /// Concatenate another array
1421
        /// </summary>
1422
        /// <param name="value">the other array</param>
1423
        /// <returns>a new array, containing the members of this array followed by the members 
1424
        /// of the other array</returns>
1425
        public XdmArray Concat(XdmArray value)
1426
        {
1427
            try
1428
            {
1429
                JArrayItem other = (JArrayItem)value.value;
1430
                JArrayItem newArray = ((JArrayItem)this.value).concat(other);
1431
                return (XdmArray)Wrap(newArray);
1432
            }
1433
            catch (net.sf.saxon.trans.XPathException e)
1434
            {
1435
                throw new StaticError(e);
1436
            }
1437
        }
1438

    
1439

    
1440
        /// <summary>
1441
        /// Get the members of the array in the form of a list.
1442
        /// </summary>
1443
        /// <returns>A list of the members of this array.</returns>
1444
        public List<XdmValue> AsList() {
1445

    
1446
            JArrayItem val = ((JArrayItem)value);
1447
            java.util.Iterator  iter = val.members().iterator();
1448
            List<XdmValue> result = new List<XdmValue>(val.getLength());
1449
            while (iter.hasNext()) {
1450
                result.Add(XdmValue.Wrap((JSequence)iter.next()));
1451

    
1452
            }
1453
            return result;
1454
        }
1455

    
1456
        /// <summary>
1457
        /// Make an XDM array from an object array. Each member of the supplied array
1458
        /// is converted to a single member in the result array using the method
1459
		/// <see cref="XdmValue.MakeValue(Object)"/>        
1460
        /// </summary>
1461
        /// <param name="o">the array of objects</param>
1462
        /// <returns>the result of the conversion if successful</returns>
1463
        
1464
        public static XdmArray MakeArray(object[] o)
1465
        {
1466
            JArrayList list = new JArrayList(o.Length);
1467
            for (int i = 0; i <o.Length; i++)
1468
            {
1469
                list.add(XdmValue.MakeValue(o[i]).Unwrap());
1470
            }
1471
            return new XdmArray(list);
1472
        }
1473

    
1474
        /// <summary>
1475
		/// Make an <c>XdmArray</c> whose members are <c>xs:boolean</c> values       
1476
        /// </summary>
1477
        /// <param name="o">the input array of booleans</param>
1478
		/// <returns>an <c>XdmArray</c> whose members are <c>xs:boolean</c> values corresponding one-to-one with the input</returns>
1479
        
1480
        public static XdmArray MakeArray(bool[] o)
1481
        {
1482
            JArrayList list = new JArrayList(o.Length);
1483
            for (int i = 0; i < o.Length; i++)
1484
            {
1485
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1486
            }
1487
            return new XdmArray(list);
1488
        }
1489

    
1490

    
1491
        /// <summary>
1492
		/// Make an <c>XdmArray</c> whose members are <c>xs:integer</c> values      
1493
        /// </summary>
1494
        /// <param name="o">the input array of long values</param>
1495
		/// <returns>an <c>XdmArray</c> whose members are <c>xs:integer</c> values corresponding one-to-one with the input</returns>
1496
        
1497
        public static XdmArray MakeArray(long[] o)
1498
        {
1499
            JArrayList list = new JArrayList(o.Length);
1500
            for (int i = 0; i < o.Length; i++)
1501
            {
1502
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1503
            }
1504
            return new XdmArray(list);
1505
        }
1506

    
1507

    
1508
        /// <summary>
1509
		/// Make an <c>XdmArray</c> whose members are <c>xs:integer</c> values      
1510
        /// </summary>
1511
        /// <param name="o">the input array of int values</param>
1512
		/// <returns>an <c>XdmArray</c> whose members are <c>xs:integer</c> values corresponding one-to-one with the input</returns>
1513
        
1514
        public static XdmArray MakeArray(int[] o)
1515
        {
1516
            JArrayList list = new JArrayList(o.Length);
1517
            for (int i = 0; i < o.Length; i++)
1518
            {
1519
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1520
            }
1521
            return new XdmArray(list);
1522
        }
1523

    
1524
        /// <summary>
1525
		/// Make an <c>XdmArray</c> whose members are <c>xs:integer</c> values      
1526
        /// </summary>
1527
        /// <param name="o">the input array of byte values</param>
1528
		/// <returns>an <c>XdmArray</c> whose members are <c>xs:integer</c> values corresponding one-to-one with the input</returns>
1529
        
1530
        public static XdmArray MakeArray(byte[] o)
1531
        {
1532
            JArrayList list = new JArrayList(o.Length);
1533
            for (int i = 0; i < o.Length; i++)
1534
            {
1535
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1536
            }
1537
            return new XdmArray(list);
1538
        }
1539
    }
1540

    
1541
    /// <summary inherits="XdmFunctionItem">
1542
    /// The class <c>XdmMap</c> represents a map item in an XPath 3.1 sequence:
1543
	/// 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
1544
    /// is a pair comprising a key (which is an atomic value) and a value (which is an arbitrary value).
1545
    /// </summary>
1546

    
1547

    
1548
    [Serializable]
1549
    public class XdmMap :  XdmFunctionItem
1550
    {
1551
  
1552

    
1553
        /// <summary>
1554
		/// Create an empty <c>XdmMap</c>
1555
        /// </summary>
1556
        public XdmMap() { 
1557
			this.value = new JHashTrieMap(); 
1558
		}
1559

    
1560
		// Internal constructor
1561

    
1562
        internal XdmMap(JHashTrieMap map) { 
1563
			this.value = map; 
1564
		}
1565

    
1566

    
1567
        /// <summary>
1568
        /// Get the number of entries in the map
1569
        /// </summary>
1570
		/// <remarks>(Note that the <see cref="XdmValue.Count"/> method returns 1 (one),
1571
        /// because an XDM map is an item.)</remarks>
1572
        
1573
        public int Size {
1574
            get {
1575
                return ((JMapItem)value).size();
1576
            }
1577
        }
1578

    
1579

    
1580
        /// <summary>
1581
		/// Ask whether the <c>XdmMap</c> is empty
1582
        /// </summary>
1583
        /// <returns>Returns <code>true</code> if this map contains no key-value pairs, that is
1584
        /// if the <c>Size</c> property is zero.</returns>
1585
        
1586
        public bool IsEmpty() {
1587
            return ((JMapItem)value).isEmpty();
1588
        }
1589

    
1590
        /// <summary>
1591
        /// Create a new map containing an additional (key, value) pair.
1592
        /// If there is an existing entry with the same key, it is removed.
1593
        /// </summary>
1594
        /// <param name="key">The key of the new entry.</param>
1595
        /// <param name="value">The value part of the new entry.</param>
1596
        /// <returns>A new map containing the additional entry (or replaced entry). The original map is unchanged.</returns>
1597
        
1598
        public XdmMap Put(XdmAtomicValue key, XdmValue value)
1599
        {
1600
            XdmMap map2 = new XdmMap();
1601
            map2.value = ((JMapItem)this.value).addEntry((JAtomicValue)key.Unwrap(), value.value);
1602
            return map2;
1603
        }
1604

    
1605

    
1606
        /// <summary>
1607
        /// Create a new map in which the entry for a given key has been removed.
1608
        /// If there is no entry with the same key, the new map has the same content as the old (it may or may not
1609
        /// be the same .NET object)
1610
        /// </summary>
1611
        /// <param name="key">The key of the entry that is to be removed</param>
1612
        /// <returns>A map without the specified entry. The original map is unchanged.</returns>
1613
        
1614
        public XdmMap Remove(XdmAtomicValue key)
1615
        {
1616
            XdmMap map2 = new XdmMap();
1617
            map2.value = ((JMapItem)this.value).remove((JAtomicValue)key.Unwrap());
1618
            return map2;
1619
        }
1620

    
1621

    
1622
        /// <summary>
1623
        /// Return a corresponding .NET Dictionary collection of keys and values.
1624
        /// </summary>
1625
        /// <returns>A mutable Dictionary from atomic values to (sequence) values, containing the
1626
        /// same entries as this map</returns>
1627
        
1628
        public Dictionary<XdmAtomicValue, XdmValue> AsDictionary() {
1629
            Dictionary<XdmAtomicValue, XdmValue> map = new Dictionary<XdmAtomicValue, XdmValue>();
1630
            JMapItem jmap = (JMapItem)value;
1631
            java.util.Iterator iter = jmap.keyValuePairs().iterator();
1632
            JKeyValuePair pair = null;
1633
            while (iter.hasNext()) {
1634
                pair = (JKeyValuePair)iter.next();
1635
                map.Add((XdmAtomicValue)XdmValue.Wrap(pair.key), XdmValue.Wrap(pair.value));
1636
            }
1637
            return map;
1638
        }
1639

    
1640

    
1641
        /// <summary>
1642
        /// Get the keys present in the map in the form of a set.
1643
        /// </summary>
1644
        /// <returns>a set of the keys present in this map, with no defined ordering.</returns>
1645
        public HashSet<XdmAtomicValue> KeySet()
1646
        {
1647
            HashSet<XdmAtomicValue> result = new HashSet<XdmAtomicValue>();
1648
            JMapItem jmap = (JMapItem)value;
1649
            net.sf.saxon.tree.iter.AtomicIterator iter = jmap.keys();
1650
            JAtomicValue key = null;
1651
            while ((key = iter.next()) != null)
1652
            {
1653
                result.Add((XdmAtomicValue)XdmValue.Wrap(key));
1654
            }
1655
            return result;
1656
        }
1657

    
1658

    
1659
        /// <summary>
1660
        /// Returns <code>true</code> if this map contains a mapping for the specified
1661
        /// key. More formally, returns <code>true</code> if and only if
1662
        /// this map contains a mapping for a key <code>k</code> such that
1663
        /// <code>(key==null ? k==null : key.Equals(k))</code>.  (There can be
1664
        /// at most one such mapping.)
1665
        /// </summary>
1666
        /// <param name="key">the key whose presence in this map is to be tested</param>
1667
        /// <returns><c>true</c> if this map contains a mapping for the specified key</returns>
1668
        
1669
        public bool ContainsKey(XdmAtomicValue key) {
1670
            JAtomicValue k = (JAtomicValue)key.value;
1671
            return ((JMapItem)value).get(k)!= null;
1672
        }
1673

    
1674

    
1675
        /// <summary>
1676
        /// Returns the value to which the specified key is mapped,
1677
		/// or <c>null</c> if this map contains no mapping for the key.
1678
        /// </summary>
1679
        /// <param name="key">the key whose associated value is to be returned. If this is
1680
		/// not an <c>XdmAtomicValue</c>, the method attempts to construct an
1681
		/// <c>XdmAtomicValue</c> using the method <see cref="XdmAtomicValue.MakeAtomicValue(Object)"/>;
1682
        /// it is therefore possible to pass a simple key such as a string or integer.</param>
1683
        /// <returns>the value to which the specified key is mapped, or
1684
		/// <c>null</c> if this map contains no mapping for the key</returns>
1685
        
1686
        public XdmValue Get(XdmAtomicValue key)
1687
        {
1688
            if (key == null) {
1689
                throw new ArgumentNullException();
1690
            }
1691
           
1692
            JAtomicValue k = (JAtomicValue)(key).value;
1693
            JSequence v = ((JMapItem)value).get(k);
1694
            return v==null ? null : XdmValue.Wrap(v);
1695
        }
1696

    
1697
        /// <summary>
1698
        /// Returns the value to which the specified key is mapped,
1699
        /// or <c>null</c> if this map contains no mapping for the key.
1700
        /// </summary>
1701
        /// <param name="key">the key whose associated value is to be returned.</param>
1702
        /// <returns>the value to which the specified key is mapped, or
1703
        /// <c>null</c> if this map contains no mapping for the key</returns>
1704

    
1705
        public XdmValue Get(String key)
1706
        {
1707
            if (key == null)
1708
            {
1709
                throw new ArgumentNullException();
1710
            }
1711
    
1712
            JAtomicValue k = (JAtomicValue)(new XdmAtomicValue(key)).value;
1713
            JSequence v = ((JMapItem)value).get(k);
1714
            return v == null ? null : XdmValue.Wrap(v);
1715
        }
1716

    
1717

    
1718
        /// <summary>
1719
        /// Returns the value to which the specified key is mapped,
1720
        /// or <c>null</c> if this map contains no mapping for the key.
1721
        /// </summary>
1722
        /// <param name="key">the key whose associated value is to be returned.</param>
1723
        /// <returns>the value to which the specified key is mapped, or
1724
        /// <c>null</c> if this map contains no mapping for the key</returns>
1725

    
1726
        public XdmValue Get(long key)
1727
        {
1728

    
1729
            JAtomicValue k = (JAtomicValue)(new XdmAtomicValue(key)).value;
1730
            JSequence v = ((JMapItem)value).get(k);
1731
            return v == null ? null : XdmValue.Wrap(v);
1732
        }
1733

    
1734
        /// <summary>
1735
        /// Returns a <c>Collection</c> containing the values found in this map.
1736
        /// </summary>
1737
        /// <returns>A collection of the values found in this map, that is, the value
1738
        /// parts of the key-value pairs. The result may contain duplicates, and the
1739
        /// order of results is unpredictable.</returns>
1740
        public ICollection Values() {
1741
            List<XdmValue> result = new List<XdmValue>();
1742

    
1743
            JMapItem jmap = (JMapItem)value;
1744
            java.util.Iterator iter = jmap.iterator();
1745
            JKeyValuePair pair = null;
1746
            while ((pair = (JKeyValuePair)iter.next()) != null)
1747
            {
1748
                result.Add((XdmAtomicValue)XdmValue.Wrap(pair.value));
1749
            }
1750

    
1751
            return result;
1752
        }
1753

    
1754

    
1755
        /// <summary>
1756
		/// Returns a <c>HashSet</c> view of the mappings contained in this map.
1757
        /// </summary>
1758
        /// <returns>a set view of the mappings contained in this map</returns>
1759
        public HashSet<DictionaryEntry> EntrySet() {
1760
            HashSet<DictionaryEntry> result = new HashSet<DictionaryEntry>();
1761
            JMapItem jmap = (JMapItem)value;
1762
            java.util.Iterator iter = jmap.iterator();
1763
            JKeyValuePair pair = null;
1764
            while ((pair = (JKeyValuePair)iter.next()) != null)
1765
            {
1766
                result.Add(new DictionaryEntry(pair.key, pair.value));
1767
            }
1768
            return result;
1769
        }
1770

    
1771

    
1772
        /// <summary>
1773
        /// Static factory method to construct an XDM map by converting each entry
1774
        /// in a supplied generic collection of key/value pairs; <code>IDictionary</code>. The keys in the 
1775
        /// Dictionary must be convertible to XDM atomic values using the 
1776
		/// <see cref="XdmAtomicValue.MakeAtomicValue(Object)"/> method. The associated values 
1777
        /// must be convertible to XDM sequences
1778
		/// using the <see cref="XdmValue.MakeValue(Object)"/> method.
1779
        /// </summary>
1780
        /// <param name="input">the supplied map</param>
1781
		/// <returns>the resulting <c>XdmMap</c></returns>
1782
        public static XdmMap MakeMap(IDictionary input) {
1783
            JHashTrieMap result = new JHashTrieMap();
1784
            XdmAtomicValue key;
1785
            XdmValue value;
1786
            
1787
            foreach (object keyi in input.Keys)
1788
            {
1789
                key = XdmAtomicValue.MakeAtomicValue(keyi);
1790
                value = XdmValue.MakeValue(input[keyi]);
1791
                result.initialPut((JAtomicValue)key.Unwrap(), value.value);
1792
            }
1793
           
1794
            return new XdmMap(result);
1795
        }
1796

    
1797
        
1798

    
1799

    
1800
    }
1801
    
1802
    /// <summary inherits="XdmItem">
1803
    /// The class <c>XdmNode</c> represents a Node in the XDM Data Model. A Node
1804
    /// is an <c>XdmItem</c>, and is therefore an <c>XdmValue</c> in its own right, and may also participate
1805
    /// as one item within a sequence value.
1806
    /// </summary>
1807
    /// <remarks>
1808
    /// <para>An <c>XdmNode</c> is implemented as a wrapper around an object
1809
    /// of type <c>net.sf.saxon.NodeInfo</c>. Because this is a key interface
1810
    /// within Saxon, it is exposed via this API, even though it is a Java
1811
    /// interface that is not part of the API proper.</para>
1812
    /// <para>The <c>XdmNode</c> interface exposes basic properties of the node, such
1813
    /// as its name, its string value, and its typed value. Navigation to other nodes
1814
    /// is supported through a single method, <c>EnumerateAxis</c>, which allows
1815
    /// other nodes to be retrieved by following any of the XPath axes.</para>
1816
    /// </remarks>
1817

    
1818
    [Serializable]
1819
    public class XdmNode : XdmItem
1820
    {
1821

    
1822
        /// <summary>
1823
        /// Determine whether the item is an atomic value
1824
        /// </summary>
1825
        /// <returns>
1826
        /// false (the item is not an atomic value)
1827
        /// </returns>
1828

    
1829
        public override bool IsAtomic()
1830
        {
1831
            return false;
1832
        }
1833

    
1834
        /// <summary>
1835
        /// The name of the node, as a <c>QName</c>. Returns null in the case of unnamed nodes.
1836
        /// </summary>
1837

    
1838
        public QName NodeName
1839
        {
1840
            get
1841
            {
1842
                JNodeInfo node = (JNodeInfo)value;
1843
                String local = node.getLocalPart();
1844
                if (local == "")
1845
                {
1846
                    return null;
1847
                }
1848
                String prefix = node.getPrefix();
1849
                String uri = node.getURI();
1850
                return new QName(prefix, uri, local);
1851
            }
1852
        }
1853

    
1854
        /// <summary>
1855
        /// The kind of node, as an instance of <c>System.Xml.XmlNodeType</c>.
1856
        /// </summary>
1857
		/// <remarks>For a namespace node in the XDM model, the value <c>XmlNodeType.None</c> 
1858
        /// is returned.
1859
        /// </remarks>
1860

    
1861
        public XmlNodeType NodeKind
1862
        {
1863
            get
1864
            {
1865
                JNodeInfo node = (JNodeInfo)value;
1866
                int kind = node.getNodeKind();
1867
                switch (kind)
1868
                {
1869
                    case JType.DOCUMENT:
1870
                        return XmlNodeType.Document;
1871
                    case JType.ELEMENT:
1872
                        return XmlNodeType.Element;
1873
                    case JType.ATTRIBUTE:
1874
                        return XmlNodeType.Attribute;
1875
                    case JType.TEXT:
1876
                        return XmlNodeType.Text;
1877
                    case JType.COMMENT:
1878
                        return XmlNodeType.Comment;
1879
                    case JType.PROCESSING_INSTRUCTION:
1880
                        return XmlNodeType.ProcessingInstruction;
1881
                    case JType.NAMESPACE:
1882
                        return XmlNodeType.None;
1883
                    default:
1884
                        throw new ArgumentException("Unknown node kind");
1885
                }
1886
            }
1887
        }
1888

    
1889
        /// <summary>
1890
		/// Get the line number of the node in a source document. 
1891
		/// </summary>
1892
		/// <remarks>
1893
		/// For a document constructed using the document
1894
        /// builder, this is available only if the line numbering option was set when the document was built (and
1895
        /// then only for element nodes). If the line number is not available, the value -1 is returned.
1896
        /// Line numbers will typically be as reported by a SAX parser; this means that the line number for an element
1897
        /// node is the line number containing the closing ">" of the start tag.
1898
		/// </remarks>
1899
         
1900
        public int LineNumber {
1901
            get { return ((JNodeInfo)value).getLineNumber(); }
1902
        }
1903

    
1904

    
1905
        /// <summary>
1906
		/// Get the column number of the node in a source document. 
1907
		/// </summary>
1908
		/// <remarks>
1909
		/// For a document constructed using the document
1910
        /// builder, this is available only if the line numbering option was set when the document was built (and
1911
        /// then only for element nodes). If the column number is not available, the value -1 is returned.
1912
        /// Line numbers will typically be as reported by a SAX parser; this means that the column number for an element
1913
        /// node is the column number containing the closing ">" of the start tag.
1914
		/// </remarks>
1915
        
1916
		public int ColumnNumber
1917
        {
1918
            get { return ((JNodeInfo)value).getColumnNumber(); }
1919
        }
1920

    
1921
        /// <summary>
1922
        /// The typed value of the node, as an instance of <c>XdmValue</c>.
1923
        /// </summary>
1924
        /// <remarks>
1925
		/// A <c>DynamicError</c> is thrown if the node has no typed value, as will be the case for
1926
        /// an element with element-only content.
1927
		/// </remarks>
1928

    
1929
        public XdmValue TypedValue
1930
        {
1931
            get { return XdmValue.Wrap(((JNodeInfo)value).atomize()); }
1932
        }
1933

    
1934
        /// <summary>
1935
		/// Get a <see cref="Processor"/> suitable for use with this <see cref="XdmNode"/>.
1936
        /// </summary>
1937
        /// <remarks>
1938
		/// <para>In most cases this will be the original <see cref="Processor"/>
1939
		/// object used to create the <see cref="DocumentBuilder"/> that built the document that 
1940
		/// contains this node. If that <see cref="Processor"/> is not available, it will be a 
1941
		/// compatible <c>Processor</c>, one that shares the same underlying <see cref="net.sf.saxon.Configuration"/>, 
1942
        /// and hence is initialized with the same configuration settings, schema components, license features,
1943
        /// and so on.</para>
1944
		/// <para><i>Note: the only case where the original <c>Processor</c> is not available is when
1945
		/// the same <c>Configuration</c> is used with multiple APIs, for example mixing s9api
1946
        /// and JAXP or XQJ in the same application.</i></para>
1947
        /// </remarks>
1948
		/// <returns>Returns a <c>Processor</c> suitable for performing further operations on this node, for example
1949
		/// for creating a <see cref="Serializer"/> or an <see cref="XPathCompiler"/>.</returns>
1950
        public Processor Processor {
1951
            get {
1952
                JConfiguration config = Implementation.getConfiguration();
1953
                object originator = config.getProcessor();
1954
                if (originator is Processor)
1955
                {
1956
                    return (Processor)originator;
1957
                }
1958
                else {
1959
                    return new Processor(new net.sf.saxon.s9api.Processor(config));
1960
                }
1961
            }
1962
        }
1963

    
1964

    
1965
        /// <summary>
1966
		/// Unwraps the underlying <c>XmlNode</c> object from the <c>XdmValue</c>.
1967
		/// If the method does not wrap a <c>XmlNode</c> then a null is returned
1968
        /// </summary>
1969
		/// <returns>The underlying <c>XmlNode</c></returns>
1970
        public XmlNode getUnderlyingXmlNode()
1971
        {
1972

    
1973
            if (value is net.sf.saxon.dotnet.DotNetNodeWrapper)
1974
            {
1975

    
1976
                return (XmlNode)((net.sf.saxon.dotnet.DotNetNodeWrapper)value).getRealNode();
1977
            }
1978
            return null;
1979
        }
1980

    
1981
        /// <summary>
1982
        /// Get the string value of the node.
1983
        /// </summary>
1984

    
1985
        public String StringValue
1986
        {
1987
            get { return ((JNodeInfo)value).getStringValue(); }
1988
        }
1989

    
1990
        /// <summary>
1991
        /// Get the parent of this node.
1992
        /// </summary>
1993
        /// <remarks>
1994
        /// Returns either a document node, an element node, or null in the case where
1995
        /// this node has no parent. 
1996
        /// </remarks>
1997

    
1998
        public XdmNode Parent
1999
        {
2000
            get {
2001
                JNodeInfo parent = ((JNodeInfo)value).getParent();
2002
                return (parent == null ? null : (XdmNode)XdmValue.Wrap(parent)); 
2003
            }
2004
        }
2005

    
2006
        /// <summary>
2007
        /// Get the root of the tree containing this node.
2008
        /// </summary>
2009
        /// <remarks>
2010
        /// Returns the root of the tree containing this node (which might be this node itself).
2011
        /// </remarks>
2012

    
2013
        public XdmNode Root
2014
        {
2015
            get
2016
            {
2017
                XdmNode parent = Parent;
2018
                if (parent == null)
2019
                {
2020
                    return this;
2021
                }
2022
                else
2023
                {
2024
                    return parent.Root;
2025
                }
2026
            }
2027
        }
2028

    
2029
        /// <summary>
2030
        /// Get a the string value of a named attribute of this element. 
2031
        /// </summary>
2032
        /// <remarks>
2033
        /// Returns null if this node is not an element, or if this element has no
2034
        /// attribute with the specified name.
2035
        /// </remarks>
2036
        /// <param name="name">The name of the attribute whose value is required</param>
2037

    
2038
        public String GetAttributeValue(QName name)
2039
        {
2040
            return ((JNodeInfo)value).getAttributeValue(name.Uri, name.LocalName);
2041
        }
2042

    
2043
        /// <summary>
2044
        /// Get an enumerator that supplies all the nodes on one of the XPath
2045
        /// axes, starting with this node.
2046
        /// </summary>
2047
        /// <param name="axis">
2048
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child axis.
2049
        /// </param>
2050
        /// <remarks>
2051
        /// The nodes are returned in axis order: that is, document order for a forwards
2052
        /// axis, reverse document order for a reverse axis.
2053
        /// </remarks>
2054

    
2055
        public IEnumerator<XdmNode> EnumerateAxis(XdmAxis axis)
2056
        {
2057
            return (new SequenceEnumerator<XdmNode>(JSequenceXdmIterator.ofNodes(((JNodeInfo)value).iterateAxis(GetAxisNumber(axis)))));
2058
        }
2059

    
2060
        /// <summary>
2061
        /// Get an enumerator that selects all the nodes on one of the XPath
2062
        /// axes, provided they have a given name. The nodes selected are those of the principal
2063
        /// node kind (elements for most axes, attributes for the attribute axis, namespace nodes
2064
        /// for the namespace axis) whose name matches the name given in the second argument.
2065
        /// </summary>
2066
        /// <param name="axis">
2067
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child axis.
2068
        /// </param>
2069
        /// <param name="nodeName">
2070
        /// The name of the required nodes, for example <c>new QName("", "item")</c> to select
2071
        /// nodes with local name "item", in no namespace.
2072
        /// </param>
2073
        /// <remarks>
2074
        /// The nodes are returned in axis order: that is, document order for a forwards
2075
        /// axis, reverse document order for a reverse axis.
2076
        /// </remarks>
2077

    
2078
        public IEnumerator<XdmNode> EnumerateAxis(XdmAxis axis, QName nodeName)
2079
        {
2080
            int kind;
2081
            switch (axis)
2082
            {
2083
                case XdmAxis.Attribute:
2084
                    kind = net.sf.saxon.type.Type.ATTRIBUTE;
2085
                    break;
2086
                case XdmAxis.Namespace:
2087
                    kind = net.sf.saxon.type.Type.NAMESPACE;
2088
                    break;
2089
                default:
2090
                    kind = net.sf.saxon.type.Type.ELEMENT;
2091
                    break;
2092
            }
2093
            JNamePool pool = ((JNodeInfo)value).getConfiguration().getNamePool();
2094
            JNameTest test = new JNameTest(kind, nodeName.Uri, nodeName.LocalName, pool);
2095
            return new SequenceEnumerator<XdmNode>(JSequenceXdmIterator.ofNodes(((JNodeInfo)value).iterateAxis(GetAxisNumber(axis), test)));
2096
        }
2097

    
2098
        private static byte GetAxisNumber(XdmAxis axis)
2099
        {
2100
            switch (axis)
2101
            {
2102
                case XdmAxis.Ancestor: return JAxisInfo.ANCESTOR;
2103
                case XdmAxis.AncestorOrSelf: return JAxisInfo.ANCESTOR_OR_SELF;
2104
                case XdmAxis.Attribute: return JAxisInfo.ATTRIBUTE;
2105
                case XdmAxis.Child: return JAxisInfo.CHILD;
2106
                case XdmAxis.Descendant: return JAxisInfo.DESCENDANT;
2107
                case XdmAxis.DescendantOrSelf: return JAxisInfo.DESCENDANT_OR_SELF;
2108
                case XdmAxis.Following: return JAxisInfo.FOLLOWING;
2109
                case XdmAxis.FollowingSibling: return JAxisInfo.FOLLOWING_SIBLING;
2110
                case XdmAxis.Namespace: return JAxisInfo.NAMESPACE;
2111
                case XdmAxis.Parent: return JAxisInfo.PARENT;
2112
                case XdmAxis.Preceding: return JAxisInfo.PRECEDING;
2113
                case XdmAxis.PrecedingSibling: return JAxisInfo.PRECEDING_SIBLING;
2114
                case XdmAxis.Self: return JAxisInfo.SELF;
2115
            }
2116
            return 0;
2117
        }
2118

    
2119
        /// <summary>
2120
        /// Get the base URI of the node.
2121
        /// </summary>
2122

    
2123
        public Uri BaseUri
2124
        {
2125
            get { 
2126
				string baseUriStr = ((JNodeInfo)value).getBaseURI();
2127
				if (baseUriStr == null || baseUriStr.Equals("")) {
2128
					return null;
2129
				}
2130
				return new Uri(baseUriStr); 
2131
			}
2132
        }
2133

    
2134
        /// <summary>
2135
        /// Get the document URI of the node.
2136
        /// </summary>
2137

    
2138
        public Uri DocumentUri
2139
        {
2140
            get
2141
            {
2142
                String s = ((JNodeInfo)value).getSystemId();
2143
                if (s == null || s.Length == 0)
2144
                {
2145
                    return null;
2146
                }
2147
                return new Uri(s);
2148
            }
2149
        }
2150

    
2151
        /// <summary>
2152
        /// Send the node (that is, the subtree rooted at this node) to an <c>XmlWriter</c>
2153
        /// </summary>
2154
        /// <remarks>
2155
        /// Note that an <c>XmlWriter</c> can only handle a well-formed XML document. This method
2156
        /// will therefore signal an exception if the node is a document node with no children, or with
2157
        /// more than one element child.
2158
        /// </remarks>
2159
        /// <param name="writer">
2160
        /// The <c>XmlWriter</c> to which the node is to be written
2161
        /// </param>
2162

    
2163
        public void WriteTo(XmlWriter writer)
2164
        {
2165
            JNodeInfo node = ((JNodeInfo)value);
2166
            JDotNetReceiver receiver = new JDotNetReceiver(writer);
2167
            receiver.setPipelineConfiguration(node.getConfiguration().makePipelineConfiguration());
2168
            receiver.open();
2169
			node.copy(receiver, net.sf.saxon.om.CopyOptions.ALL_NAMESPACES, JExplicitLocation.UNKNOWN_LOCATION);
2170
            receiver.close();
2171
        }
2172

    
2173
        /// <summary>
2174
        /// Return a serialization of this node as lexical XML
2175
        /// </summary>
2176
        /// <remarks>
2177
        /// <para>In the case of an element node, the result will be a well-formed
2178
        /// XML document serialized as defined in the W3C XSLT/XQuery serialization specification,
2179
		/// using options <c>method="xml"</c>, <c>indent="yes"</c>, <c>omit-xml-declaration="yes"</c>.</para>
2180
        /// <para>In the case of a document node, the result will be a well-formed
2181
        /// XML document provided that the document node contains exactly one element child,
2182
        /// and no text node children. In other cases it will be a well-formed external
2183
        /// general parsed entity.</para>
2184
        /// <para>In the case of an attribute node, the output is a string in the form
2185
        /// <c>name="value"</c>. The name will use the original namespace prefix.</para>
2186
        /// <para>Other nodes, such as text nodes, comments, and processing instructions, are
2187
        /// represented as they would appear in lexical XML.</para>
2188
        /// </remarks>
2189

    
2190
        public String OuterXml
2191
        {
2192
            get
2193
            {
2194
                JNodeInfo node = ((JNodeInfo)value);
2195

    
2196
                if (node.getNodeKind() == JType.ATTRIBUTE)
2197
                {
2198
                    String val = node.getStringValue().Replace("\"", "&quot;");
2199
                    val = val.Replace("<", "&lt;");
2200
                    val = val.Replace("&", "&amp;");
2201
                    return node.getDisplayName() + "=\"" + val + '"';
2202
                } else if (node.getNodeKind() == JType.NAMESPACE) {
2203
                    String val = node.getStringValue().Replace("\"", "&quot;");
2204
                    val = val.Replace("<", "&lt;");
2205
                    val = val.Replace("&", "&amp;");
2206
                    String name = node.getDisplayName();
2207
                    name = (name.Equals("") ? "xmlns" : "xmlns:" + name);
2208
                    return name + "=\"" + val + '"';
2209
                }
2210
                return net.sf.saxon.query.QueryResult.serialize(node);
2211
                
2212
            }
2213
        }
2214

    
2215
        /// <summary>
2216
		/// Two instances of <c>XdmNode</c> are equal if they represent the same node. That is, the <c>Equals()</c>
2217
        /// method returns the same result as the XPath "is" operator.
2218
        /// </summary>
2219
        /// <param name="obj">The object node to be compared</param>
2220
         
2221
        public override bool Equals(object obj)
2222
        {
2223
            return obj is XdmNode && ((JNodeInfo)value).equals((JNodeInfo)((XdmNode)obj).value);
2224
        }
2225

    
2226
        /// <summary>
2227
		/// The hash code of a node reflects the equality relationship: if two <c>XdmNode</c> instances
2228
        /// represent the same node, then they have the same hash code
2229
        /// </summary>
2230

    
2231
        public override int GetHashCode()
2232
        {
2233
            return ((JNodeInfo)value).hashCode();
2234
        }
2235

    
2236
        /// <summary>
2237
        /// Return a string representation of the node.
2238
        /// </summary>
2239
        /// <remarks>
2240
		/// This method returns the value of the <see cref="OuterXml"/> property.
2241
		/// To get the string value of a node as defined in XPath, use the <see cref="StringValue"/> property.
2242
        /// </remarks>
2243

    
2244
        public override String ToString()
2245
        {
2246
            return OuterXml;
2247
        }
2248

    
2249
        internal void SetProcessor(Processor processor)
2250
        {
2251
            Implementation.getConfiguration().setProcessor(processor.JProcessor);
2252
        }
2253

    
2254
        /// <summary>
2255
        /// Escape hatch to the underlying class in the Java implementation
2256
        /// </summary>
2257

    
2258
        public JNodeInfo Implementation
2259
        {
2260
            get { return ((JNodeInfo)value); }
2261
        }
2262

    
2263

    
2264
    }
2265

    
2266

    
2267
    /// <summary inherits="XdmValue">
2268
    /// The class <c>XdmEmptySequence</c> represents an empty sequence in the XDM Data Model.
2269
    /// </summary>
2270
    /// <remarks>
2271
    /// <para>An empty sequence <i>may</i> also be represented by an <c>XdmValue</c> whose length
2272
    /// happens to be zero. Applications should therefore not test to see whether an object
2273
    /// is an instance of this class in order to decide whether it is empty.</para>
2274
    /// <para>In interfaces that expect an <c>XdmItem</c>, an empty sequence is represented
2275
    /// by a CLI <c>null</c> value.</para> 
2276
    /// </remarks>
2277

    
2278
    [Serializable]
2279
    public sealed class XdmEmptySequence : XdmValue
2280
    {
2281

    
2282
        ///<summary>The singular instance of this class</summary>
2283

    
2284
        public static XdmEmptySequence INSTANCE = new XdmEmptySequence();
2285

    
2286
        private XdmEmptySequence()
2287
        {
2288
            this.value = JEmptySequence.getInstance();
2289
        }
2290
    }
2291

    
2292

    
2293
    /// <summary>
2294
	/// The <c>QName</c> class represents an instance of <c>xs:QName</c>, as defined in the XPath 2.0
2295
    /// data model. Internally, it has three components, a namespace URI, a local name, and
2296
    /// a prefix. The prefix is intended to be used only when converting the value back to 
2297
    /// a string.
2298
    /// </summary>
2299
    /// <remarks>
2300
	/// Note that a <c>QName</c> is not itself an <c>XdmItem</c> in this model; however it can
2301
    /// be converted to an <c>XdmAtomicValue</c>.
2302
    /// </remarks>    
2303

    
2304
    [Serializable]
2305
    public sealed class QName
2306
    {
2307

    
2308
        private JQName sqName;
2309
        //private String prefix;
2310
        //private String uri;
2311
        //private String local;
2312
        //int hashcode = -1;      // evaluated lazily
2313

    
2314

    
2315
        private static String XS = NamespaceConstant.SCHEMA;
2316

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

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

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

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

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

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

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

    
2338
        /// <summary>QName constant for the name xs:QName</summary>
2339
        public static readonly QName XS_QNAME = new QName(XS, "xs:QName");
2340

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

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

    
2347
        /// <summary>
2348
		/// Construct a <c>QName</c> representing a name in no namespace
2349
        /// </summary>
2350
        /// <remarks>
2351
        /// This constructor does not check that the components of the QName are
2352
        /// lexically valid.
2353
        /// </remarks>
2354
        /// <param name="local">The local part of the name
2355
        /// </param>
2356

    
2357
        public QName(String local)
2358
        {
2359
            // TODO: check for validity
2360
            int colon = local.IndexOf(':');
2361
            if (colon < 0)
2362
            {
2363
                sqName = new JQName("", "", local);
2364
            }
2365
            else {
2366
                
2367
                    throw new ArgumentException("Local name contains a colon");
2368
                }             
2369
        }
2370

    
2371
        /// <summary>
2372
		/// Construct a <c>QName</c> using a namespace URI and a lexical representation.
2373
        /// The lexical representation may be a local name on its own, or it may 
2374
        /// be in the form <c>prefix:local-name</c>
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="uri">The namespace URI. Use either the string "" or null
2381
        /// for names that are not in any namespace.
2382
        /// </param>
2383
        /// <param name="lexical">Either the local part of the name, or the prefix
2384
        /// and local part in the format <c>prefix:local</c>
2385
        /// </param>
2386

    
2387
        public QName(String uri, String lexical)
2388
        {
2389
            // TODO: check for validity
2390
            uri = (uri == null ? "" : uri);
2391
            int colon = lexical.IndexOf(':');
2392
            if (colon < 0)
2393
            {
2394
                sqName = new JQName("", uri, lexical);
2395
            }
2396
            else
2397
            {
2398

    
2399
                string prefix = lexical.Substring(0, colon);
2400
                string local = lexical.Substring(colon + 1);
2401
                sqName = new JQName(prefix, uri, local);
2402
            }
2403
        }
2404

    
2405
        /// <summary>
2406
		/// Construct a <c>QName</c> using a namespace prefix, a namespace URI, and a local name
2407
        /// (in that order).
2408
        /// </summary>
2409
        /// <remarks>
2410
        /// This constructor does not check that the components of the QName are
2411
        /// lexically valid.
2412
        /// </remarks>
2413
        /// <param name="prefix">The prefix of the name. Use either the string ""
2414
        /// or null for names that have no prefix (that is, they are in the default
2415
        /// namespace)</param>
2416
        /// <param name="uri">The namespace URI. Use either the string "" or null
2417
        /// for names that are not in any namespace.
2418
        /// </param>
2419
        /// <param name="local">The local part of the name</param>
2420

    
2421
        public QName(String prefix, String uri, String local)
2422
        {
2423
            sqName = new JQName(prefix, uri, local);
2424
        }
2425

    
2426
        /// <summary>
2427
		/// Construct a <c>QName</c> from a lexical QName, supplying an element node whose
2428
        /// in-scope namespaces are to be used to resolve any prefix contained in the QName.
2429
        /// </summary>
2430
        /// <remarks>
2431
        /// <para>This constructor checks that the components of the QName are
2432
        /// lexically valid.</para>
2433
        /// <para>If the lexical QName has no prefix, the name is considered to be in the
2434
        /// default namespace, as defined by <c>xmlns="..."</c>.</para>
2435
        /// </remarks>
2436
        /// <param name="lexicalQName">The lexical QName, in the form <code>prefix:local</code>
2437
        /// or simply <c>local</c>.</param>
2438
        /// <param name="element">The element node whose in-scope namespaces are to be used
2439
        /// to resolve the prefix part of the lexical QName.</param>
2440
        /// <exception cref="ArgumentException">If the prefix of the lexical QName is not in scope</exception>
2441
        /// <exception cref="ArgumentException">If the lexical QName is invalid 
2442
        /// (for example, if it contains invalid characters)</exception>
2443
        /// 
2444

    
2445
        public QName(String lexicalQName, XdmNode element)
2446
        {
2447
            try
2448
            {
2449
                JNodeInfo node = (JNodeInfo)element.value;
2450
				sqName = new JQName(JStructuredQName.fromLexicalQName(lexicalQName, true, true, new JInscopeNamespaceResolver(node)));
2451
				
2452
            }
2453
            catch (net.sf.saxon.trans.XPathException err)
2454
            {
2455
                throw new ArgumentException(err.getMessage());
2456
            }
2457
        }
2458

    
2459
        /// <summary>
2460
        /// Construct a <c>QName</c> from an <c>XmlQualifiedName</c> (as defined in the
2461
        /// <c>System.Xml</c> package).
2462
        /// </summary>
2463
        /// <remarks>
2464
        /// Note that an <c>XmlQualifiedName</c> does not contain any prefix, so the result
2465
        /// will always have a prefix of ""
2466
        /// </remarks>
2467
		/// <param name="qualifiedName">The <c>XmlQualifiedName</c></param>
2468

    
2469
        public QName(XmlQualifiedName qualifiedName)
2470
        {
2471
            string uri = qualifiedName.Namespace;
2472
            string local = qualifiedName.Name;
2473
            string prefix = String.Empty;
2474
            sqName = new JQName(prefix, uri, prefix);
2475
        }
2476

    
2477
        //  internal constructor from a QNameValue
2478

    
2479
        internal QName(JQNameValue q)
2480
        {
2481
            sqName = new JQName(q.getPrefix(), q.getNamespaceURI(), q.getLocalName());
2482
        }
2483

    
2484
        //  internal constructor with JQName object as argument
2485

    
2486
        internal QName(JQName q)
2487
        {
2488
            sqName = q;
2489
        }
2490

    
2491
        /// <summary>
2492
		/// Factory method to construct a <c>QName</c> from a string containing the expanded
2493
        /// QName in Clark notation, that is, <c>{uri}local</c>
2494
        /// </summary>
2495
        /// <remarks>
2496
        /// The prefix part of the <c>QName</c> will be set to an empty string.
2497
        /// </remarks>
2498
        /// <param name="expandedName">The URI in Clark notation: <c>{uri}local</c> if the
2499
        /// name is in a namespace, or simply <c>local</c> if not.</param> 
2500

    
2501
        public static QName FromClarkName(String expandedName)
2502
        {
2503
            String namespaceURI;
2504
            String localName;
2505
            if (expandedName[0] == '{')
2506
            {
2507
                int closeBrace = expandedName.IndexOf('}');
2508
                if (closeBrace < 0)
2509
                {
2510
                    throw new ArgumentException("No closing '}' in Clark name");
2511
                }
2512
                namespaceURI = expandedName.Substring(1, closeBrace - 1);
2513
                if (closeBrace == expandedName.Length)
2514
                {
2515
                    throw new ArgumentException("Missing local part in Clark name");
2516
                }
2517
                localName = expandedName.Substring(closeBrace + 1);
2518
            }
2519
            else
2520
            {
2521
                namespaceURI = "";
2522
                localName = expandedName;
2523
            }
2524

    
2525
            return new QName("", namespaceURI, localName);
2526
        }
2527

    
2528

    
2529
        /// <summary>
2530
		/// Factory method to construct a <c>QName</c> from a string containing the expanded
2531
        /// QName in EQName notation, that is, <c>Q{uri}local</c>
2532
        /// </summary>
2533
        /// <remarks>
2534
        /// The prefix part of the <c>QName</c> will be set to an empty string.
2535
        /// </remarks>
2536
        /// <param name="expandedName">The QName in EQName notation: <c>Q{uri}local</c>. 
2537
		/// For a name in no namespace, either of the
2538
        /// forms <c>Q{}local</c> or simply <c>local</c> are accepted.</param>
2539
        /// <returns> the QName corresponding to the supplied name in EQName notation. This will always
2540
        /// have an empty prefix.</returns>
2541
       
2542
        public static QName FromEQName(String expandedName)
2543
        {
2544
            String namespaceURI;
2545
            String localName;
2546
            if (expandedName[0] == 'Q' && expandedName[1] == '{')
2547
            {
2548
                int closeBrace = expandedName.IndexOf('}');
2549
                if (closeBrace < 0)
2550
                {
2551
                    throw new ArgumentException("No closing '}' in EQName");
2552
                }
2553
                namespaceURI = expandedName.Substring(2, closeBrace);
2554
                if (closeBrace == expandedName.Length)
2555
                {
2556
                    throw new ArgumentException("Missing local part in EQName");
2557
                }
2558
                localName = expandedName.Substring(closeBrace + 1);
2559
            }
2560
            else
2561
            {
2562
                namespaceURI = "";
2563
                localName = expandedName;
2564
            }
2565

    
2566
            return new QName("", namespaceURI, localName);
2567
        }
2568

    
2569
        // internal method: Factory method to construct a QName from Saxon's internal <c>StructuredQName</c>
2570
        // representation.
2571

    
2572
        internal static QName FromStructuredQName(JStructuredQName sqn) {
2573
            return new QName(sqn.getPrefix(), sqn.getURI(), sqn.getLocalPart());
2574
        }
2575

    
2576
        /// <summary>
2577
		/// Register a <c>QName</c> with the <c>Processor</c>. This makes comparison faster
2578
        /// when the QName is compared with others that are also registered with the <c>Processor</c>.
2579
        /// Depreacted method.
2580
        /// </summary>
2581
        /// <remarks>
2582
        /// A given <c>QName</c> object can only be registered with one <c>Processor</c>.
2583
        /// </remarks>
2584
		/// <param name="processor">The <c>Processor</c> in which the name is to be registered.</param>
2585
        [System.Obsolete("This method is no longer in use")]
2586
        public void Register(Processor processor)
2587
        {}
2588

    
2589
        /// <summary>
2590
		/// Validate the <c>QName</c> against the XML 1.0 or XML 1.1 rules for valid names.
2591
        /// </summary>
2592
        /// <param name="processor">This argument is no longer used (at one time it was used
2593
        /// to establish whether XML 1.0 or XML 1.1 rules should be used for validation, but the
2594
        /// two versions of the XML specification have since been aligned).</param>
2595
        /// <returns>true if the name is valid, false if not</returns>
2596

    
2597
        public bool IsValid(Processor processor)
2598
        {
2599
            return IsValid();
2600
        }
2601
        
2602
        /// <summary>
2603
		/// Validate the <c>QName</c> against the XML rules for valid names.
2604
        /// </summary>
2605
        /// <returns>true if the name is valid, false if not</returns>
2606

    
2607
        public bool IsValid()
2608
        {
2609
            if(this.Prefix != String.Empty)
2610
            {
2611
                if (!JNameChecker.isValidNCName(Prefix))
2612
                {
2613
                    return false;
2614
                }
2615
            }
2616
            if (!JNameChecker.isValidNCName(this.LocalName))
2617
            {
2618
                return false;
2619
            }
2620
            return true;
2621
        }
2622

    
2623
		/// <summary>Get the prefix of the <c>QName</c>. This plays no role in operations such as comparison
2624
        /// of QNames for equality, but is retained (as specified in XPath) so that a string representation
2625
        /// can be reconstructed.
2626
        /// </summary>
2627
        /// <remarks>
2628
        /// Returns the zero-length string in the case of a QName that has no prefix.
2629
        /// </remarks>
2630

    
2631
        public String Prefix
2632
        {
2633
            get { return sqName.getPrefix(); }
2634
        }
2635

    
2636
		/// <summary>Get the namespace URI of the <c>QName</c>. Returns "" (the zero-length string) if the
2637
        /// QName is not in a namespace.
2638
        /// </summary>
2639

    
2640
        public String Uri
2641
        {
2642
            get { return sqName.getNamespaceURI(); }
2643
        }
2644

    
2645
		/// <summary>Get the local part of the <c>QName</c></summary>
2646

    
2647
        public String LocalName
2648
        {
2649
            get { return sqName.getLocalName(); }
2650
        }
2651

    
2652
        /// <summary>Get the expanded name, as a string using the notation devised by James Clark.
2653
        /// If the name is in a namespace, the resulting string takes the form <c>{uri}local</c>.
2654
        /// Otherwise, the value is the local part of the name.
2655
        /// </summary>
2656

    
2657
        public String ClarkName
2658
        {
2659
            get
2660
            {
2661
                string uri = Uri;
2662
                if (uri.Equals(""))
2663
                {
2664
                    return LocalName;
2665
                }
2666
                else
2667
                {
2668
                    return "{" + uri + "}" + LocalName;
2669
                }
2670
            }
2671
        }
2672

    
2673
        /// <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>.
2674
        /// </summary>
2675
        public String EQName
2676
        {
2677
            get
2678
            {
2679
                return "Q{" + Uri + "}" + LocalName;
2680
            }
2681
        }
2682

    
2683
        /// <summary>
2684
        /// Convert the value to a string. The resulting string is the lexical form of the QName,
2685
        /// using the original prefix if there was one.
2686
        /// </summary>
2687

    
2688
        public override String ToString()
2689
        {
2690

    
2691
            if (Prefix.Equals(""))
2692
            {
2693
                return LocalName;
2694
            }
2695
            else
2696
            {
2697
				return Prefix + ":" + LocalName;
2698
            }
2699
        }
2700

    
2701
        /// <summary>
2702
		/// Get a hash code for the <c>QName</c>, to support equality matching. This supports the
2703
        /// semantics of equality, which considers only the namespace URI and local name, and
2704
        /// not the prefix.
2705
        /// </summary>
2706
        /// <remarks>
2707
        /// The algorithm for allocating a hash code does not depend on registering the QName 
2708
        /// with the <c>Processor</c>.
2709
        /// </remarks>
2710

    
2711
        public override int GetHashCode()
2712
        {
2713
            return sqName.hashCode();
2714
        }
2715

    
2716
        /// <summary>
2717
        /// Test whether two QNames are equal. This supports the
2718
        /// semantics of equality, which considers only the namespace URI and local name, and
2719
        /// not the prefix.
2720
        /// </summary>
2721
		/// <param name="other">The value to be compared with this <c>QName</c>. If this value is not a <c>QName</c>, the
2722
        /// result is always false. Otherwise, it is true if the namespace URI and local name both match.</param>
2723

    
2724
        public override bool Equals(Object other)
2725
        {
2726
            if (!(other is QName))
2727
            {
2728
                return false;
2729
            }
2730
            return sqName.equals(((QName)other).sqName);
2731
        }
2732

    
2733
        /// <summary>
2734
        /// Convert the value to an <c>XmlQualifiedName</c> (as defined in the
2735
        /// <c>System.Xml</c> package)
2736
        /// </summary>
2737
        /// <remarks>
2738
        /// Note that this loses the prefix.
2739
        /// </remarks>
2740

    
2741
        public XmlQualifiedName ToXmlQualifiedName()
2742
        {
2743
            return new XmlQualifiedName(LocalName, Uri);
2744
        }
2745

    
2746
		// internal method: Convert to a net.sf.saxon.value.QNameValue
2747

    
2748
        internal JQNameValue ToQNameValue()
2749
        {
2750
            return new JQNameValue(sqName.getPrefix(), sqName.getNamespaceURI(), sqName.getLocalName(), null);
2751
		}
2752

    
2753
		// internal method
2754

    
2755
        internal JStructuredQName ToStructuredQName()
2756
        {
2757
            return new JStructuredQName(Prefix, Uri, LocalName);
2758
        }
2759

    
2760
        // internal method
2761

    
2762
        internal JQName UnderlyingQName()
2763
        {
2764
            return sqName;
2765
        }
2766

    
2767

    
2768

    
2769

    
2770
    }
2771

    
2772
    /// <summary>
2773
    /// This class represents an enumeration of the values in an XPath
2774
    /// sequence. It implements the <c>IEnumerator</c> interface, and the objects
2775
    /// returned are always instances of <c>XdmItem</c>.
2776
    /// </summary>
2777
    /// <remarks>
2778
    /// Because the underlying value can be evaluated lazily, it is possible
2779
    /// for exceptions to occur as the sequence is being read.
2780
    /// </remarks>
2781

    
2782
    public interface IXdmEnumerator<out XdmItem> : IEnumerator<XdmItem>
2783
    {
2784

    
2785

    
2786
    }
2787

    
2788
    /// <summary>
2789
    /// This class represents an enumeration of the values in an XPath
2790
    /// sequence. It implements the <c>IEnumerable</c> interface, and the objects
2791
    /// returned are always instances of <c>XdmItem</c>.
2792
    /// </summary>
2793
    /// <remarks>
2794
    /// Because the underlying value can be evaluated lazily, it is possible
2795
    /// for exceptions to occur as the sequence is being read.
2796
    /// </remarks>
2797
    public interface IXdmEnumerable<out XdmItem> : IEnumerable<XdmItem>
2798
    {
2799

    
2800

    
2801
    }
2802

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

    
2812
    [Serializable]
2813
    internal class SequenceEnumerator<T> : IXdmEnumerator<T>
2814
          where T : XdmItem
2815
    {
2816

    
2817
        private JSequenceXdmIterator iter;
2818
        private JItem current;
2819

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

    
2826

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

    
2837
        object IEnumerator.Current
2838
        {
2839
            get {
2840
                return Current;
2841
            }
2842
        }
2843

    
2844
        T IEnumerator<T>.Current
2845
        {
2846

    
2847
            get { return (T)Current; }
2848
        }
2849

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

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

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

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

    
2895
    /// <summary>
2896
	/// Implementation of the (Java) interface <c>SequenceIterator</c> that wraps
2897
	/// a (.NET) <c>IXdmEnumerator</c>
2898
    /// </summary>
2899

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

    
2904
        IEnumerator iter;
2905
        int pos = 0;
2906

    
2907
        public DotNetSequenceIterator(IEnumerator iter)
2908
        {
2909
            this.iter = iter;
2910
        }
2911

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

    
2931
        }
2932

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

    
2943
        public int position()
2944
        {
2945
            return pos;
2946
        }
2947

    
2948
        public void close()
2949
        {
2950
        }
2951

    
2952

    
2953
        public int getProperties()
2954
        {
2955
            return 0;
2956
        }
2957

    
2958
        public void forEachOrFail(JItemConsumer consumer)
2959
        {
2960
            JItem item = null;
2961

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

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

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

    
2978
        public JGroundedValue materialize() {
2979
            return JSequenceExtent.fromIterator(this);
2980
        }
2981

    
2982
        public JGroundedValue materialize(JSequenceIterator value)
2983
        {
2984
            return JSequenceExtent.fromIterator(value);
2985
        }
2986

    
2987
       
2988

    
2989
        public void Dispose()
2990
        {
2991
            throw new NotImplementedException();
2992
        }
2993

    
2994
        JGroundedValue JSequenceIterator.materialize()
2995
        {
2996
            return JSequenceExtent.fromIterator(this);
2997
        }
2998

    
2999

    
3000
    }
3001

    
3002
    /// <summary>
3003
    /// Enumeration identifying the thirteen XPath axes
3004
    /// </summary>
3005

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

    
3036
    /// <summary>
3037
    /// An implementation of <code>IXdmEnumerator</code> that iterates over an empty sequence.
3038
    /// </summary>
3039

    
3040
    public class EmptyEnumerator<T> : IXdmEnumerator<T>
3041
       where T : XdmItem
3042
    {
3043

    
3044
        /// <summary>
3045
		/// Create an instance of the enumerator with the <c>XdmItem</c> as the generic type
3046
        /// </summary>
3047
        public static EmptyEnumerator<XdmItem> INSTANCE = new EmptyEnumerator<XdmItem>();
3048

    
3049
        /// <summary>
3050
		/// Create an instance of the enumerator with the <c>XdmNode</c> as the generic type
3051
        /// </summary>
3052
        public static EmptyEnumerator<XdmNode> NODE_INSTANCE = new EmptyEnumerator<XdmNode>();
3053

    
3054
        private EmptyEnumerator() { }
3055

    
3056
        /// <summary>
3057
        /// Reset the enumerator
3058
        /// </summary>
3059
        public void Reset() { }
3060
        
3061

    
3062

    
3063

    
3064
        object IEnumerator.Current
3065
        {
3066
            get
3067
            {
3068
                return null;
3069
            }
3070
        }
3071

    
3072
        /// <summary>
3073
        /// The current item in the enumerator
3074
        /// </summary>
3075
        T IEnumerator<T>.Current
3076
        {
3077
            get
3078
            {
3079
                return null;
3080
            }
3081
        }
3082

    
3083
        /// <summary>
3084
        /// Move to the next item in the enumerator..
3085
        /// </summary>
3086
        /// <returns>true if successful move, false otherwise.</returns>
3087
        public bool MoveNext()
3088
        {
3089
            return false;
3090
        }
3091

    
3092
		/// <summary>
3093
		/// The Dispose method is not implemented on this Enumerator
3094
		/// </summary>
3095
        public void Dispose()
3096
        {
3097
            throw new NotImplementedException();
3098
        }
3099
    }
3100

    
3101

    
3102
}
3103

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