Project

Profile

Help

Download (195 KB) Statistics
| Branch: | Tag: | Revision:

he / latest10 / hen / csource / api / Model.cs @ aac4a1be

1 b64b1e89 O'Neil Delpratt
´╗┐using System;
2
using System.Xml;
3
using System.Collections;
4
using System.Collections.Generic;
5
using System.Linq;
6
using JConfiguration = net.sf.saxon.Configuration;
7
using JNamePool = net.sf.saxon.om.NamePool;
8
using JAtomicValue = net.sf.saxon.value.AtomicValue;
9
using JFunction = net.sf.saxon.om.Function;
10
using JItem = net.sf.saxon.om.Item;
11
using JZeroOrOne = net.sf.saxon.om.ZeroOrOne;
12
using JOne = net.sf.saxon.om.One;
13
using JEmptySequence = net.sf.saxon.value.EmptySequence;
14
using JSequenceExtent = net.sf.saxon.value.SequenceExtent;
15
using JConversionResult = net.sf.saxon.type.ConversionResult;
16
using JValidationFailure = net.sf.saxon.type.ValidationFailure;
17
using JSequenceIterator = net.sf.saxon.om.SequenceIterator;
18
using JDotNetIterator = net.sf.saxon.dotnet.DotNetIterator;
19
using JSequenceXdmIterator = net.sf.saxon.s9api.XdmSequenceIterator;
20
using JStandardNames = net.sf.saxon.om.StandardNames;
21
using JStructuredQName = net.sf.saxon.om.StructuredQName;
22
using JXPathContext = net.sf.saxon.expr.XPathContext;
23
using JDotNetReceiver = net.sf.saxon.dotnet.DotNetReceiver;
24
using JDotNetObjectValue = net.sf.saxon.dotnet.DotNetObjectValue;
25
using JBigDecimal = java.math.BigDecimal;
26
using JArrayList = java.util.ArrayList;
27
using JCharSequence = java.lang.CharSequence;
28
using JSequence = net.sf.saxon.om.Sequence;
29
using JNodeInfo = net.sf.saxon.om.NodeInfo;
30
using JAxisInfo = net.sf.saxon.om.AxisInfo;
31
using JNameChecker = net.sf.saxon.om.NameChecker;
32
using JSingletonIterator = net.sf.saxon.tree.iter.SingletonIterator;
33
using JQNameValue = net.sf.saxon.value.QNameValue;
34
using JStringValue = net.sf.saxon.value.StringValue;
35
using JInt64Value = net.sf.saxon.value.Int64Value;
36
using JBigDecimalValue = net.sf.saxon.value.BigDecimalValue;
37
using JFloatValue = net.sf.saxon.value.FloatValue;
38
using JDoubleValue = net.sf.saxon.value.DoubleValue;
39
using JBooleanValue = net.sf.saxon.value.BooleanValue;
40
using JAnyURIValue = net.sf.saxon.value.AnyURIValue;
41
using JNumericValue = net.sf.saxon.value.NumericValue;
42
using JStringToDouble11 = net.sf.saxon.value.StringToDouble11;
43
using JIntegerValue = net.sf.saxon.value.IntegerValue;
44
using JNameTest = net.sf.saxon.pattern.NameTest;
45
using JAtomicType = net.sf.saxon.type.AtomicType;
46
using JSchemaType = net.sf.saxon.type.SchemaType;
47
using JType = net.sf.saxon.type.Type;
48
using JStringToDouble = net.sf.saxon.type.StringToDouble;
49
using JSequenceTool = net.sf.saxon.om.SequenceTool;
50
using JLoc = net.sf.saxon.expr.parser.Loc;
51
using JHashTrieMap = net.sf.saxon.ma.map.HashTrieMap;
52
using JMapItem = net.sf.saxon.ma.map.MapItem;
53
using JArrayItem = net.sf.saxon.ma.arrays.ArrayItem;
54
using JKeyValuePair = net.sf.saxon.ma.map.KeyValuePair;
55
using JSimpleArrayItem = net.sf.saxon.ma.arrays.SimpleArrayItem;
56
using JDecimalValue = net.sf.saxon.value.DecimalValue;
57
using JObjectValue = net.sf.saxon.value.ObjectValue;
58
using JGroundedValue = net.sf.saxon.om.GroundedValue;
59
using JQName = net.sf.saxon.s9api.QName;
60
using JXdmValue = net.sf.saxon.s9api.XdmValue;
61
62
namespace Saxon.Api
63
{
64
65
    /// <summary>
66
    /// A value in the XDM data model. A value is a sequence of zero or more
67
    /// items, each item being an atomic value, a node, or a function item.
68
    /// </summary>
69
    /// <remarks>
70
    /// <para>An <c>XdmValue</c> is immutable.</para>
71
    /// <para>A sequence consisting of a single item <i>may</i> be represented
72
    /// as an instance of <see cref="XdmItem"/>, which is a subtype of <c>XdmValue</c>. However,
73
    /// there is no guarantee that all single-item sequences will be instances of
74
	/// <c>XdmItem</c>: if you want to ensure this, use the <see cref="Simplify"/> property.</para>
75
    /// <para>There are various ways of creating an <c>XdmValue</c>. To create an atomic
76
    /// value, use one of the constructors on <see cref="XdmAtomicValue"/> (which is a subtype of <c>XdmValue</c>).
77
    /// To construct an <see cref="XdmNode"/> (another subtype) by parsing an XML document, or by wrapping a DOM document,
78
	/// use a <see cref="DocumentBuilder"/>. To create a sequence of values, use the <see cref="Append(XdmValue)"/>
79
    /// method on this class to form a list from individual items or sublists.</para>
80
    /// <para>An <c>XdmValue</c> is also returned as the result of evaluating a query
81
    /// using the XQuery and XPath interfaces.</para>
82
    /// <para>The subtype <see cref="XdmEmptySequence"/> represents an empty sequence: an
83
    /// <c>XdmValue</c> of length zero. Again, there is no guarantee that every empty sequence
84
    /// will be represented as an instance of <c>XdmEmptySequence</c>, unless you use
85
    /// the <c>Simplify</c> property.</para>
86
    /// </remarks>
87
88
    [Serializable]
89
    public class XdmValue : IEnumerable<XdmItem>
90
    {
91
92
        internal JGroundedValue value;
93
94
        // Internal constructor
95
96
        internal XdmValue() { }
97
98
        /// <summary>
99
        /// Create a value from a collection of items.
100
        /// </summary>
101
        /// <param name="items">An enumerable collection providing the items to make up the sequence. Every
102
        /// member of this collection must be an instance of <c>XdmItem</c>
103
        /// </param>
104
105
        public XdmValue(IEnumerable<XdmItem> items)
106
        {
107
            JArrayList list = new JArrayList();
108
            foreach (XdmItem c in items)
109
            {
110
                list.add((JItem)c.Unwrap());
111
            }
112
            value = JSequenceExtent.makeSequenceExtent(list);
113
        }
114
115
116
        /// <summary>
117
		/// Get an <c>IEnumerable</c> by applying a <c>Step</c> to the items in this value. This operation
118
        /// is analogous to the <c>SelectMany</c> operation in C#, or to the "!" operator
119
        /// in XPath.
120
        /// </summary>
121
		/// <typeparam name="TInput">Input items to the <c>Step</c> function, which can be subclass of <c>XdmItem</c></typeparam>
122
		/// <typeparam name="TResult">Result items to the <c>Step</c> function, which can be subclass of <c>XdmItem</c></typeparam>
123
		/// <param name="step">The <c>Step</c> to be applied to the items in this value.</param>
124
		/// <returns>An <c>IEnumerable</c> of items obtained by replacing each item X in this value by the items obtained
125
		/// by applying the <c>Step</c> function to X.</returns>
126
        public IEnumerable<TResult> Select<TInput, TResult>(Step<TInput, TResult> step)
127
        where TInput : XdmItem
128
        where TResult : XdmItem
129
        {
130
            foreach (XdmItem item in this)
131
            {
132
                if (item is TInput)
133
                {
134
                    foreach (TResult tresult in step.Invoke((TInput)item))
135
                    {
136
                        yield return tresult;
137
                    }
138
                }
139
140
            }
141
142
        }
143
144
145
        /// <summary>
146
		/// Concatenate two <c>IEnumerable</c> objects of <c>XdmItem</c> objects or items of its subclass.
147
        /// </summary>
148
		/// <typeparam name="TInput">The types of object to enumerate. The object must be an <c>XdmItem</c> or a derived type.</typeparam>
149
        /// <param name="first">The first enumerable object</param>
150
        /// <param name="second">The second enumerable object</param>
151
        /// <returns>The enumerable object as a result of the concatenation.</returns>
152
        public static IEnumerable<TInput> Concat<TInput>(IEnumerable<TInput> first, IEnumerable<TInput> second)
153
            where TInput : XdmItem
154
        {
155
            if (first == null)
156
            {
157
                throw new ArgumentNullException("first");
158
            }
159
            if (second == null)
160
            {
161
                throw new ArgumentNullException("second");
162
            }
163
            return ConcatImpl(first, second);
164
        }
165
166
        private static IEnumerable<TInput> ConcatImpl<TInput>(
167
    IEnumerable<TInput> first,
168
    IEnumerable<TInput> second)
169
            where TInput : XdmItem
170
        {
171
            foreach (TInput item in first)
172
            {
173
                yield return item;
174
            }
175
            first = null;
176
            foreach (TInput item in second)
177
            {
178
                yield return item;
179
            }
180
        }
181
182
        /// <summary>
183
        /// Get the enumerable object of items that satisfy a supplied <c>Predicate</c>.
184
        /// </summary>
185
		/// <typeparam name="T">The types of object to enumerate. The object must be an <c>XdmItem</c> or a derived type.</typeparam>
186
        /// <param name="predicate">The predicate to be applied</param>
187
        /// <returns>An enumerable of items that satisfy the suppplied <c>Predicate</c>.</returns>
188
        public IEnumerable<T> Where<T>(IPredicate<T> predicate)
189
            where T : XdmItem
190
        {
191
192
            if (predicate == null)
193
            {
194
                throw new ArgumentNullException("Predicate is null");
195
            }
196
            return this.Select(new Step<T, T>(x => {
197
                if (!(x is T)) {
198
                    throw new Exception("Type error for item in XdmValue");
199
                }
200
                return Enumerable.Repeat((T)x, predicate.Invoke((T)x) ? 1 : 0);
201
                }));
202
203
        }
204
205
        /// <summary>
206
		/// Returns whether any items of this <c>XdmValue</c> match the provided predicate.
207
        /// May not evaluate the predicate on all items if not necessary for 
208
        /// determining the result. 
209
        /// </summary>
210
		/// <typeparam name="T">The types of object in the enumerable. The object must be an <c>XdmItem</c> or a derived type.</typeparam>
211
		/// <param name="predicate">The predicate to apply to items of this <c>XdmValue</c></param>
212
		/// <returns>True if any items of the <c>XdmValue</c> match the provided predicate, otherwise false.</returns>
213
        public bool AnyMatch<T>(IPredicate<T> predicate)
214
            where T : XdmItem
215
        {
216
            if (predicate == null)
217
            {
218
                throw new ArgumentNullException("Predicate is null");
219
            }
220
221
            foreach (XdmItem item in this)
222
            {
223
                if (item is T && predicate.Func((T)item))
224
                {
225
                    return true;
226
                }
227
            }
228
            return false;
229
        }
230
231
        /// <summary>
232
		/// Returns whether all items of this <c>XdmValue</c> match the provided predicate.
233
        /// May not evaluate the predicate on all items if not necessary for determining the result.
234
        /// </summary>
235
		/// <typeparam name="T">The types of object in the enumerable. The object must be an <c>XdmItem</c> or a derived type.</typeparam>
236
		/// <param name="predicate">The predicate to apply to items of this <c>XdmValue</c></param>
237
		/// <returns><c>true</c> if either all items of the <c>XdmValue</c> match the provided predicate or the <c>XdmValue</c> is empty, otherwise <c>false</c></returns>
238
        public bool AllMatch<T>(IPredicate<T> predicate)
239
            where T : XdmItem
240
        {
241
            if (predicate == null)
242
            {
243
                throw new ArgumentNullException("Predicate is null");
244
            }
245
246
            foreach (XdmItem item in this)
247
            {
248
                if (!(item is T)) {
249
                    return false;
250
                }
251
252
                if (!predicate.Func((T)item))
253
                {
254
                    return false;
255
                }
256
            }
257
            return true;
258
259
        }
260
261
        /// <summary>
262
		/// Create an <c>XdmValue</c> from an enumerator of <c>XdmItem</c> objects.
263
        /// </summary>
264
		/// <param name="items">An enumerator of <c>XdmItem</c> objects</param>
265
        public XdmValue(IEnumerator<XdmItem> items)
266
        {
267
            JArrayList list = new JArrayList();
268
            while (items.MoveNext())
269
            {
270
                list.add((JItem)items.Current.Unwrap());
271
            }
272
            value = JSequenceExtent.makeSequenceExtent(list);
273
        }
274
275
276
277
        /// <summary>
278
        /// Create a new <c>XdmValue</c> by concatenating the sequences of items in 
279
        /// this <c>XdmValue</c> and another <c>XdmValue</c>.
280
        /// </summary>
281
        /// <remarks>
282
        /// Neither of the input <c>XdmValue</c> objects is modified by this operation.
283
        /// </remarks>
284
        /// <param name="otherValue">
285
        /// The other <c>XdmValue</c>, whose items are to be appended to the items from this <c>XdmValue</c>.
286
        /// </param>
287
288
        public XdmValue Append(XdmValue otherValue)
289
        {
290
            JArrayList list = new JArrayList();
291
            foreach (XdmItem item in this)
292
            {
293
                list.add(item.Unwrap());
294
            }
295
            foreach (XdmItem item in otherValue)
296
            {
297
                list.add(item.Unwrap());
298
            }
299
            JGroundedValue gv = JSequenceExtent.makeSequenceExtent(list);
300
            return FromGroundedValue(gv);
301
        }
302
303
304
        /// <summary>
305
        /// Create an <c>XdmValue</c> from an underlying Saxon <c>Sequence</c> object.
306
        /// This method is provided for the benefit of applications that need to mix
307
        /// use of the Saxon .NET API with direct use of the underlying objects
308
        /// and methods offered by the Java implementation.
309
        /// </summary>
310
        /// <param name="value">An object representing an XDM value in the
311
        /// underlying Saxon implementation. If the parameter is null,
312
        /// the method returns null.</param>
313
        /// <returns>An <c>XdmValue</c> that wraps the underlying Saxon XDM value
314
        /// representation.</returns>
315
316
        public static XdmValue Wrap(JSequence value)
317
        {
318
            if (value == null)
319
            {
320
                return XdmEmptySequence.INSTANCE;
321
            }
322
            JGroundedValue gv;
323
            try
324
            {
325
                gv = value.materialize();
326
            }
327
            catch (Exception e)
328
            {
329
                throw new DynamicError(e.Message);
330
            }
331
            XdmValue result;
332
            if (gv.getLength() == 0)
333
            {
334
335
                return XdmEmptySequence.INSTANCE;
336
            }
337
            else if (gv.getLength() == 1)
338
            {
339
                JItem first = gv.head();
340
                if (first is JAtomicValue)
341
                {
342
                    result = new XdmAtomicValue();
343
                    result.value = (JAtomicValue)first;
344
                    return result;
345
                }
346
                else if (first is JNodeInfo)
347
                {
348
                    result = new XdmNode();
349
                    result.value = (JNodeInfo)first;
350
                    return result;
351
                }
352
                else if (first is JZeroOrOne)
353
                {
354
                    return Wrap(((JZeroOrOne)value).head());
355
                }
356
                else if (first is JOne)
357
                {
358
                    return Wrap(((JOne)value).head());
359
                }
360
                else if (first is JMapItem)
361
                {
362
                    result = new XdmMap();
363
                    result.value = (JMapItem)first;
364
                    return result;
365
                }
366
                else if (first is JArrayItem)
367
                {
368
                    result = new XdmArray();
369
                    result.value = (JArrayItem)first;
370
                    return result;
371
                }
372
                else if (first is JFunction)
373
                {
374
                    result = new XdmFunctionItem();
375
                    result.value = (JFunction)first;
376
                    return result;
377
                }
378
                else if (first is JObjectValue)
379
                {
380
                    result = new XdmExternalObjectValue(((JObjectValue)first).getObject());
381
                    return result;
382
                }
383
                else
384
                {
385
                    result = new XdmValue();
386
                    result.value = first;
387
                    return result;
388
                }
389
390
            }
391
            else
392
            {
393
                return FromGroundedValue(gv);
394
            }
395
396
        }
397
398
        static internal XdmValue FromGroundedValue(JGroundedValue value)
399
        {
400
            XdmValue result = new XdmValue();
401
            result.value = value;
402
            return result;
403
        }
404
405
        static internal JXdmValue FromGroundedValueToJXdmValue(JGroundedValue value)
406
        {
407
            return net.sf.saxon.s9api.XdmValue.wrap(value);
408
        }
409
410
        /// <summary>
411
        /// Make an XDM value from a .NET object. 
412
		/// </summary>
413
		/// <remarks>
414
		/// The supplied object may be any of the following:
415
        /// <list>
416
        /// <item>An instance of <c>XdmValue</c> (for example an <c>XdmAtomicValue</c>, 
417
        /// <c>XdmMap</c>, <c>XdmArray</c> or <c>XdmNode</c>), which is returned unchanged</item>
418
        /// <item>An instance of Saxon's Java class <c>net.sf.saxon.om.Sequence</c>, which is wrapped
419
        /// as an <c>XdmValue</c></item>
420
        /// <item>An instance of <c>IDictionary</c> (which is wrapped as an <c>XdmMap</c> using the method <see cref="XdmMap.MakeMap"/>)</item>
421
        /// <item>An array of objects, which are converted by applying these rules recursively,
422
		/// and then wrapped as an <c>XdmArray</c>.</item>
423
		/// </list>
424
		/// </remarks>
425
        /// <param name="o">The supplied object</param>
426
        /// <returns>The result of conversion if successful.</returns>
427
        public static XdmValue MakeValue(object o)
428
        {
429
430
            if (o == null)
431
            {
432
                return null;
433
            }
434
            if (o is JSequence)
435
            {
436
                return XdmValue.Wrap((JSequence)o);
437
            }
438
            else if (o is XdmValue)
439
            {
440
                return (XdmValue)o;
441
            }
442
            else if (o is IDictionary)
443
            {
444
                return XdmMap.MakeMap((IDictionary)o);
445
            }
446
            else if (o.GetType().IsArray)
447
            {
448
                return XdmArray.MakeArray((object[])o);
449
            }
450
            else if (o is IEnumerable)
451
            {
452
                return XdmValue.MakeSequence((IEnumerable)o);
453
            }
454
455
            else
456
            {
457
                return XdmAtomicValue.MakeAtomicValue(o);
458
459
            }
460
461
        }
462
463
        private static XdmValue MakeSequence(IEnumerable o)
464
        {
465
            JArrayList list = new JArrayList();
466
467
            if (o is string)
468
            {
469
                return XdmAtomicValue.MakeAtomicValue((object)o);
470
            }
471
            foreach (object oi in o)
472
            {
473
                XdmValue v = XdmValue.MakeValue(oi);
474
                if (v is XdmItem)
475
                {
476
                    list.add((JItem)v.Unwrap());
477
                }
478
                else
479
                {
480
                    list.add(new XdmArray(v).Unwrap());
481
                }
482
483
            }
484
            JSequence value = new JSequenceExtent(list);
485
            return XdmValue.Wrap(value);
486
        }
487
488
489
        /// <summary>
490
        /// Extract the underlying Saxon <c>Sequence</c> object from an <c>XdmValue</c>.
491
        /// This method is provided for the benefit of applications that need to mix
492
        /// use of the Saxon .NET API with direct use of the underlying objects
493
        /// and methods offered by the Java implementation.
494
        /// </summary>
495
        /// <returns>An object representing the XDM value in the
496
        /// underlying Saxon implementation.</returns>
497
498
499
        public JSequence Unwrap()
500
        {
501
            return value;
502
        }
503
504
        /// <summary>
505
        /// Get the sequence of items in the form of an <c>IList</c>.
506
        /// </summary>
507
        /// <returns>
508
        /// The list of items making up this XDM value. Each item in the list
509
        /// will be an object of type <c>XdmItem</c>.
510
        /// </returns>        
511
512
        public IList<XdmItem> GetList()
513
        {
514
            if (value == null)
515
            {
516
                return new List<XdmItem>();
517
            }
518
            else if (value is JItem)
519
            {
520
                IList<XdmItem> list = new List<XdmItem>(1);
521
                list.Add((XdmItem)XdmValue.Wrap(value));
522
                return list;
523
            }
524
            else
525
            {
526
                IList<XdmItem> list = new List<XdmItem>();
527
                JSequenceIterator iter = value.iterate();
528
                while (true)
529
                {
530
                    JItem jitem = iter.next();
531
                    if (jitem == null)
532
                    {
533
                        break;
534
                    }
535
                    list.Add((XdmItem)XdmValue.Wrap(jitem));
536
                }
537
                return list;
538
            }
539
        }
540
541
        IEnumerator IEnumerable.GetEnumerator()
542
        {
543
            if (value == null)
544
            {
545
                return EmptyEnumerator<XdmItem>.INSTANCE;
546
            }
547
            else if (value is JItem)
548
            {
549
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(JSingletonIterator.makeIterator((JItem)value)));
550
            }
551
            else
552
            {
553
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(value.iterate()));
554
            }
555
        }
556
557
        /// <summary>
558
        /// Get the sequence of items in the form of an <c>IEnumerator</c>.
559
        /// </summary>
560
        /// <returns>
561
        /// An enumeration over the list of items making up this XDM value. Each item in the list
562
        /// will be an object of type <c>XdmItem</c>.
563
        /// </returns>    
564
565
        IEnumerator<XdmItem> IEnumerable<XdmItem>.GetEnumerator()
566
        {
567
            if (value == null)
568
            {
569
                return EmptyEnumerator<XdmItem>.INSTANCE;
570
            }
571
            else if (value is JItem)
572
            {
573
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(JSingletonIterator.makeIterator((JItem)value)));
574
            }
575
            else
576
            {
577
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(value.iterate()));
578
            }
579
        }
580
581
582
583
584
        /// <summary>
585
        /// Get the sequence of items in the form of an <c>IEnumerator</c>.
586
        /// </summary>
587
        /// <returns>
588
        /// An enumeration over the list of items making up this XDM value. Each item in the list
589
        /// will be an object of type <c>XdmItem</c>.
590
        /// </returns>    
591
592
        public IEnumerator<XdmItem> GetEnumerator()
593
        {
594
            if (value == null)
595
            {
596
                return EmptyEnumerator<XdmItem>.INSTANCE;
597
            }
598
            else if (value is JItem)
599
            {
600
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(JSingletonIterator.makeIterator((JItem)value)));
601
            }
602
            else
603
            {
604
                return new SequenceEnumerator<XdmItem>(new JSequenceXdmIterator(value.iterate()));
605
            }
606
        }
607
608
609
        /// <summary>
610
        /// Get the i'th item in the value, counting from zero.
611
        /// </summary>
612
        /// <param name="i">The item that is required, counting the first item in the sequence as item zero.</param>
613
        /// <returns>The i'th item in the sequence making up the value, counting from zero.</returns>
614
        public XdmItem ItemAt(int i)
615
        {
616
            if (i < 0 || i >= Count)
617
            {
618
                throw new IndexOutOfRangeException("" + i);
619
            }
620
            try
621
            {
622
                JItem item = JSequenceTool.itemAt(value, i);
623
                return (XdmItem)XdmItem.Wrap(item);
624
            }
625
            catch (net.sf.saxon.trans.XPathException e)
626
            {
627
                throw new StaticError(e);
628
            }
629
630
        }
631
632
633
634
        /// <summary>
635
        /// Create a string representation of the value. The is the result of serializing
636
        /// the value using the adaptive serialization method.
637
        /// </summary>
638
        /// <returns>A string representation of the value.</returns>
639
        public override String ToString()
640
        {
641
            return XdmValue.FromGroundedValueToJXdmValue(value).toString();
642
643
        }
644
645
646
647
648
        /// <summary>
649
		/// Return a new <c>XdmValue</c> containing the nodes present in this <c>XdmValue</c>,
650
        /// with duplicates eliminated, and sorted into document order.
651
        /// </summary>
652
        /// <returns>The same nodes, sorted into document order, with duplicates eliminated.</returns>
653
        public XdmValue DocumentOrder()
654
        {
655
            try
656
            {
657
                JSequenceIterator iter = value.iterate();
658
                JSequenceIterator sorted = new net.sf.saxon.expr.sort.DocumentOrderIterator(iter, net.sf.saxon.expr.sort.GlobalOrderComparer.getInstance());
659
                return XdmValue.Wrap(sorted.materialize());
660
661
            }
662
            catch (net.sf.saxon.trans.XPathException e)
663
            {
664
                throw new StaticError(e);
665
            }
666
667
        }
668
669
        /// <summary>
670
        /// Get the number of items in the sequence.
671
        /// </summary>
672
        /// <returns>
673
        /// The number of items in the sequence. Note that for a single item (including
674
        /// a map or an array) this always returns 1 (one).
675
        /// </returns> 
676
677
        public int Count
678
        {
679
            get
680
            {
681
                if (value == null)
682
                {
683
                    return 0;
684
                }
685
                else if (value is JItem)
686
                {
687
                    return 1;
688
                }
689
                else
690
                {
691
                    return value.getLength();
692
                }
693
            }
694
        }
695
696
        /// <summary>
697
		/// Simplify an XDM value: that is, reduce it to the simplest possible form.
698
		/// </summary>
699
		/// <remarks>
700
        /// <list>
701
        /// <item>If the sequence is empty, the result will be an instance of <c>XdmEmptySequence</c></item>
702
        /// <item>If the sequence is a single node, the result will be an instance of <c>XdmNode</c></item>
703
        /// <item>If it is a single atomic value, it will be an instance of <c>XdmAtomicValue</c></item>
704
        /// <item>If it is a map, it will be an instance of <c>XdmMap</c></item>
705
        /// <item>If it is an array, it will be an instance of <c>XdmArray</c></item>
706
        /// <item>If it is any other kind of function, it will be an instance of <c>XdmFunctionItem</c></item>
707
        /// <item>If it is a wrapper around a .NET object, it will be an instance of <c>XdmExternalObjectValue</c></item>
708
        /// </list>
709
		/// </remarks>
710
		/// <returns>The XDM value reduced to the simplest possible form.</returns>
711
712
        public XdmValue Simplify
713
        {
714
            get
715
            {
716
                switch (value.getLength())
717
                {
718
                    case 0:
719
                        if (this is XdmEmptySequence)
720
                        {
721
                            return this;
722
                        }
723
                        return XdmEmptySequence.INSTANCE;
724
725
                    case 1:
726
                        if (this is XdmItem)
727
                        {
728
                            return this;
729
                        }
730
                        return XdmValue.Wrap(value);
731
732
                    default:
733
                        return this;
734
                }
735
            }
736
        }
737
738
    }
739
740
741
742
    /// <summary inherits="XdmItem">
743
    /// The class <c>XdmExternalObjectValue</c> represents an XDM item that wraps an external .NET object.
744
    /// As such, it is outside the scope of the W3C XDM specification (but permitted as an extension).
745
    /// </summary>
746
    [Serializable]
747
    public class XdmExternalObjectValue : XdmItem
748
    {
749
750
        /// <summary>
751
        /// Constructor to create an <c>XdmExternalObjectValue</c> that wraps a supplied .NET object.
752
        /// </summary>
753
        /// <param name="o">The supplied .NET object.</param>
754
        public XdmExternalObjectValue(object o)
755
        {
756
            value = new JDotNetObjectValue(o);
757
        }
758
759
        /// <summary>
760
        /// Determine whether the item is an atomic value.
761
        /// </summary>
762
        /// <returns>
763
        /// False (the item is not an atomic value).
764
        /// </returns>
765
        public override bool IsAtomic()
766
        {
767
            return false;
768
        }
769
770
771
772
        /// <summary>
773
		/// Compare two external objects for equality. Two instances of <c>XdmExternalObjectValue</c> are equal
774
        /// if the .NET objects that they wrap are equal.
775
        /// </summary>
776
        /// <param name="other">The object to be compared</param>
777
		/// <returns>True if the other object is an <c>XdmExternalObjectValue</c> and the two wrapped objects are 
778
        /// equal under the equals method.</returns>
779
        public bool Equals(XdmExternalObjectValue other)
780
        {
781
            return other is XdmExternalObjectValue && value == other.value;
782
        }
783
784
        /// <summary>
785
		/// Return a hash code for the object. This respects the semantics of <c>equals(Object)</c>.
786
        /// </summary>
787
        /// <returns>A suitable hash code.</returns>
788
        public override int GetHashCode()
789
        {
790
            return ((java.lang.Object)value).hashCode();
791
        }
792
793
        /// <summary>
794
        /// Get the wrapped .NET object.
795
        /// </summary>
796
        /// <returns>The wrapped object.</returns>
797
        public object GetExternalObject()
798
        {
799
            return ((JObjectValue)value).getObject();
800
        }
801
802
        /// <summary>
803
        /// Get the result of converting the external value to a string.
804
        /// </summary>
805
        /// <returns>The result of applying <c>ToString()</c> to the wrapped external object.</returns>
806
        public override string ToString()
807
        {
808
            return GetExternalObject().ToString();
809
        }
810
    }
811
812
    /// <summary inherits="XdmValue">
813
    /// The class <c>XdmItem</c> represents an item in a sequence, as defined
814
    /// by the XDM data model. An item may be an atomic value, a node, a function (including maps
815
    /// and arrays), or an external object.
816
    /// </summary>
817
    /// <remarks>
818
    /// <para>An item is a member of a sequence, but it can also be considered as
819
    /// a sequence (of length one) in its own right. <c>XdmItem</c> is a subtype
820
    /// of <c>XdmValue</c> because every item in the XDM data model is also a
821
    /// value.</para>
822
    /// <para>It cannot be assumed that every sequence of length one will always be 
823
    /// represented by an <c>XdmItem</c>. It is quite possible for an <c>XdmValue</c>
824
    /// that is not an <c>XdmItem</c> to hold a singleton sequence. Use <see cref="XdmValue.Simplify"/> 
825
    /// to ensure that a singleton is represented as an <c>XdmItem</c>.</para>
826
    /// </remarks> 
827
828
    [Serializable]
829
    public abstract class XdmItem : XdmValue
830
    {
831
832
        /// <summary>
833
        /// Determine whether the item is an atomic value.
834
        /// </summary>
835
        /// <returns>
836
        /// True if the item is an atomic value, false if it is a node, function, or external object.
837
        /// </returns>
838
839
        public abstract bool IsAtomic();
840
841
        /// <summary>
842
        /// Determine whether the item is a node or some other type of item.
843
        /// </summary>
844
        /// <returns>True if the item is a node, false if it is an atomic value or a function (including maps and arrays).</returns>
845
        public bool IsNode()
846
        {
847
            return value is JNodeInfo;
848
        }
849
850
        /// <summary>
851
        /// Get the string value of the item. 
852
        /// </summary>
853
        /// <remarks>
854
        /// <list>
855
        /// <item>For an atomic value, the result is the same as casting the value to a string.</item>
856
        /// <item>For a node, the method returns the string
857
        /// value of the node. This is not the same as the result of <see cref="XdmNode.ToString()"/>, which
858
        /// returns the result of serializing the node.</item>
859
        /// <item>For a function, including a map or array, the result is an error.</item>
860
        /// <item>For an external object, the result is the same as the result of calling <c>ToString()</c>
861
        /// on the external object.</item>
862
        /// </list>
863
        /// <para>In all cases the result is the same as applying the XPath <c>string()</c> function.</para>
864
        /// </remarks>
865
        /// <returns>The result of converting the item to a string.</returns>
866
867
        public String GetStringValue()
868
        {
869
            return ((JItem)value).getStringValue();
870
        }
871
872
        internal static net.sf.saxon.s9api.XdmItem FromXdmItemItemToJXdmItem(XdmItem value)
873
        {
874
            return (net.sf.saxon.s9api.XdmItem)net.sf.saxon.s9api.XdmValue.wrap(value == null ? null : value.value);
875
        }
876
877
        /// <summary>
878
        /// Determine whether this item matches a given item type.
879
        /// </summary>
880
        /// <param name="typei">The item type to be tested against this item</param>
881
        /// <returns>True if the item matches this item type, false if it does not match.</returns>
882
        public bool Matches(XdmItemType typei)
883
        {
884
            return typei.Matches(this);
885
        }
886
    }
887
888
    /// <summary inherits="XdmItem">
889
    /// The class <c>XdmAtomicValue</c> represents an item in an XDM sequence
890
    /// that is an atomic value. The value may belong to any of the 19 primitive types
891
    /// defined in XML Schema, or to a type derived from these primitive types, or to 
892
    /// the XDM-specific type <c>xs:untypedAtomic</c>.
893
    /// </summary>
894
    /// <remarks>
895
    /// Note that there is no guarantee that every <c>XdmValue</c> comprising a single
896
    /// atomic value will be an instance of this class. To force this, use the <c>Simplify</c>
897
    /// property of the <c>XdmValue</c>.
898
    /// </remarks>
899
900
    [Serializable]
901
    public class XdmAtomicValue : XdmItem
902
    {
903
        // Internal constructor
904
905
        internal XdmAtomicValue() { }
906
907
        /// <summary>
908
        /// Determine whether the item is an atomic value
909
        /// </summary>
910
        /// <returns>
911
        /// True (the item is an atomic value).
912
        /// </returns>
913
914
        public override bool IsAtomic()
915
        {
916
            return true;
917
        }
918
919
        /// <summary>
920
        /// Construct an atomic value of type <c>xs:string</c>
921
        /// </summary>
922
        /// <param name="str">The string value</param>
923
924
        public XdmAtomicValue(String str)
925
        {
926
            this.value = new JStringValue(str);
927
        }
928
929
        /// <summary>
930
        /// Construct an atomic value of type <c>xs:integer</c> from a supplied <c>long</c>
931
        /// </summary>
932
        /// <param name="i">The integer value</param>
933
934
        public XdmAtomicValue(long i)
935
        {
936
            this.value = JInt64Value.makeDerived(i, (JAtomicType)XdmAtomicType.LONG.Unwrap().getUnderlyingItemType());
937
        }
938
939
940
        /// <summary>
941
        /// Construct an atomic value of type <c>xs:integer</c> from a supplied <c>long</c>
942
        /// </summary>
943
        /// <param name="i">The integer value</param>
944
945
        public XdmAtomicValue(int i)
946
        {
947
            this.value = JInt64Value.makeDerived(i, (JAtomicType)XdmAtomicType.INT.Unwrap().getUnderlyingItemType());
948
        }
949
950
        /// <summary>
951
        /// Construct an atomic value of type <c>xs:integer</c> from a supplied <c>byte</c>
952
        /// </summary>
953
        /// <param name="i">The integer value, in the range -128 to +127</param>
954
        public XdmAtomicValue(byte i)
955
        {
956
            this.value = JInt64Value.makeDerived(i, (JAtomicType)XdmAtomicType.BYTE.Unwrap().getUnderlyingItemType());
957
        }
958
959
        /// <summary>
960
        /// Construct an atomic value of type <c>xs:decimal</c>
961
        /// </summary>
962
        /// <param name="d">The decimal value</param>
963
964
        public XdmAtomicValue(decimal d)
965
        {
966 aac4a1be O'Neil Delpratt
            this.value = new JBigDecimalValue(new JBigDecimal(d.ToString( System.Globalization.CultureInfo.InvariantCulture)));
967 b64b1e89 O'Neil Delpratt
        }
968
969
        /// <summary>
970
        /// Construct an atomic value of type <c>xs:float</c>
971
        /// </summary>
972
        /// <param name="f">The float value</param>        
973
974
        public XdmAtomicValue(float f)
975
        {
976
            this.value = new JFloatValue(f);
977
        }
978
979
        /// <summary>
980
        /// Construct an atomic value of type <c>xs:dateTime</c> from a .NET DateTime object
981
        /// Here we probe the object for timezone offset information to create the resulting value. 
982
        /// </summary>
983
        /// <param name="dt">The DateTime object value</param>
984
        public XdmAtomicValue(DateTime dt)
985
        {
986
            if (dt.Kind == DateTimeKind.Local)
987
            {
988
                int offsetMinutes = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now).Minutes;
989
                this.value = new net.sf.saxon.value.DateTimeValue(dt.Year, Convert.ToByte(dt.Month), Convert.ToByte(dt.Day), Convert.ToByte(dt.Hour), Convert.ToByte(dt.Minute), Convert.ToByte(dt.Second), Convert.ToByte(dt.Ticks * (1000000000 / TimeSpan.TicksPerSecond)), offsetMinutes);
990
            }
991
            else if (dt.Kind == DateTimeKind.Utc)
992
            {
993
                this.value = new net.sf.saxon.value.DateTimeValue(dt.Year, Convert.ToByte(dt.Month), Convert.ToByte(dt.Day), Convert.ToByte(dt.Hour), Convert.ToByte(dt.Minute), Convert.ToByte(dt.Second), Convert.ToByte(dt.Ticks * (1000000000 / TimeSpan.TicksPerSecond)), 0);
994
995
            }
996
            else if (dt.Kind == DateTimeKind.Unspecified)
997
            {
998
                int offsetMinutes = TimeZoneInfo.Local.GetUtcOffset(DateTime.Now).Minutes;
999
                this.value = new net.sf.saxon.value.DateTimeValue(dt.Year, Convert.ToByte(dt.Month), Convert.ToByte(dt.Day), Convert.ToByte(dt.Hour), Convert.ToByte(dt.Minute), Convert.ToByte(dt.Second), Convert.ToByte(dt.Ticks * (1000000000 / TimeSpan.TicksPerSecond)), net.sf.saxon.value.CalendarValue.NO_TIMEZONE);
1000
            }
1001
        }
1002
1003
        /// <summary>
1004
        /// Construct an atomic value of type <c>xs:dateTime</c> with a specific timezone offset from a DateTimeOffset object.
1005
        /// </summary>
1006
        /// <param name="offset">The DateTimeOffset value</param>
1007
        public XdmAtomicValue(DateTimeOffset offset)
1008
        {
1009
            int offsetMinutes = offset.Offset.Minutes;
1010
            DateTime dt = offset.DateTime;
1011
            this.value = new net.sf.saxon.value.DateTimeValue(dt.Year, Convert.ToByte(dt.Month), Convert.ToByte(dt.Day), Convert.ToByte(dt.Hour), Convert.ToByte(dt.Minute), Convert.ToByte(dt.Second), Convert.ToByte(dt.Ticks * (1000000000 / TimeSpan.TicksPerSecond)), offsetMinutes);
1012
        }
1013
1014
1015
1016
        /// <summary>
1017
        /// Construct an atomic value of type <c>xs:double</c>
1018
        /// </summary>
1019
        /// <param name="d">The double value</param>
1020
1021
        public XdmAtomicValue(double d)
1022
        {
1023
            this.value = new JDoubleValue(d);
1024
        }
1025
1026
        /// <summary>
1027
        /// Construct an atomic value of type <c>xs:boolean</c>
1028
        /// </summary>
1029
        /// <param name="b">The boolean value</param>
1030
1031
        public XdmAtomicValue(bool b)
1032
        {
1033
            this.value = JBooleanValue.get(b);
1034
        }
1035
1036
        /// <summary>
1037
        /// Construct an atomic value of type <c>xs:anyURI</c>
1038
        /// </summary>
1039
        /// <param name="u">The uri value</param>
1040
1041
        public XdmAtomicValue(Uri u)
1042
        {
1043
            this.value = new JAnyURIValue(u.ToString());
1044
        }
1045
1046
        /// <summary>
1047
        /// Construct an atomic value of type <c>xs:QName</c>
1048
        /// </summary>
1049
        /// <param name="q">The QName value</param>                
1050
1051
        public XdmAtomicValue(QName q)
1052
        {
1053
            this.value = new JQNameValue(
1054
                q.Prefix, q.Uri, q.LocalName);
1055
        }
1056
1057
        /// <summary>
1058
        /// Construct an atomic value of a given type
1059
        /// </summary>
1060
        /// <param name="lexicalForm">The string representation of the value (any value that is acceptable
1061
        /// in the lexical space, as defined by XML Schema Part 2). Whitespace normalization as defined by
1062
        /// the target type will be applied to the value.</param>
1063
        /// <param name="type">The type given as an <c>XdmAtomicType</c></param>
1064
1065
        public XdmAtomicValue(String lexicalForm, XdmAtomicType type)
1066
        {
1067
            net.sf.saxon.type.ItemType it = type.Unwrap().getUnderlyingItemType();
1068
            if (!it.isPlainType())
1069
            {
1070
                throw new StaticError(new net.sf.saxon.s9api.SaxonApiException("Requested type is not atomic"));
1071
            }
1072
            if (((JAtomicType)it).isAbstract())
1073
            {
1074
                throw new StaticError(new net.sf.saxon.s9api.SaxonApiException("Requested type is not namespace-sensitive"));
1075
1076
            }
1077
            try
1078
            {
1079
                net.sf.saxon.type.StringConverter Converter = ((JAtomicType)it).getStringConverter(type.Unwrap().getConversionRules());
1080
                this.value = Converter.convertString(lexicalForm).asAtomic();
1081
            }
1082
            catch (Exception ex) {
1083
                throw new DynamicError(ex.Message);
1084
            }
1085
1086
        }
1087
1088
        /// <summary>
1089
        /// Construct an atomic value of a given built-in or user-defined type
1090
        /// </summary>
1091
        /// <example>
1092
        ///   <code>XdmAtomicValue("abcd", QName.XDT_UNTYPED_ATOMIC, processor)</code>
1093
        ///   <para>creates an untyped atomic value containing the string "abcd"</para>
1094
        /// </example>
1095
        /// <param name="lexicalForm">The string representation of the value (any value that is acceptable
1096
        /// in the lexical space, as defined by XML Schema Part 2). Whitespace normalization as defined by
1097
        /// the target type will be applied to the value.</param>
1098
        /// <param name="type">The QName giving the name of the target type. This must be an atomic
1099
        /// type, and it must not be a type that is namespace-sensitive (QName, NOTATION, or types derived
1100
        /// from these). If the type is a user-defined type then its definition must be present
1101
        /// in the schema cache maintained by the <c>SchemaManager</c>.</param> 
1102
        /// <param name="processor">The <c>Processor</c> object. This is needed for looking up user-defined
1103
        /// types, and also because some conversions are context-sensitive, for example they depend on the
1104
        /// implicit timezone or the choice of XML 1.0 versus XML 1.1 for validating names.</param>
1105
        /// <exception cref="ArgumentException">Thrown if the type is unknown or unsuitable, or if the supplied string is not
1106
        /// a valid lexical representation of a value of the given type.</exception>
1107
1108
        public XdmAtomicValue(String lexicalForm, QName type, Processor processor)
1109
        {
1110
            JConfiguration jconfig = processor.Implementation;
1111
            int fp = jconfig.getNamePool().getFingerprint(type.Uri, type.LocalName);
1112
            if (fp == -1)
1113
            {
1114
                throw new ArgumentException("Unknown name " + type);
1115
            }
1116
            JSchemaType st = jconfig.getSchemaType(new JStructuredQName("", type.Uri.ToString(), type.LocalName));
1117
            if (st == null)
1118
            {
1119
                throw new ArgumentException("Unknown type " + type);
1120
            }
1121
            if (!(st is JAtomicType))
1122
            {
1123
                throw new ArgumentException("Specified type " + type + " is not atomic");
1124
            }
1125
            if (((net.sf.saxon.type.SimpleType)st).isNamespaceSensitive())
1126
            {
1127
                throw new ArgumentException("Specified type " + type + " is namespace-sensitive");
1128
            }
1129
            JConversionResult result = ((JAtomicType)st).getStringConverter(jconfig.getConversionRules()).convertString((JCharSequence)lexicalForm);
1130
1131
            if (result is JValidationFailure)
1132
            {
1133
                throw new ArgumentException(((JValidationFailure)result).getMessage());
1134
            }
1135
            this.value = (JAtomicValue)result;
1136
        }
1137
1138
1139
1140
        /// <summary>
1141
        /// Create an atomic value of a type appropriate to the supplied value. 
1142
        /// </summary>
1143
        /// <remarks>
1144
        /// The supplied value must be one of the following:
1145
        /// <list>
1146
        /// <item>An instance of the Saxon Java class <c>net.sf.saxon.value.AtomicValue</c></item>
1147
        /// <item>A <c>Boolean</c> - returns an instance of <c>xs:boolean</c></item>
1148
        /// <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>
1149
        /// <item>A <c>Char</c> - TODO ???????</item>
1150
        /// <item>A <c>String</c> - returns an instance of <c>xs:string</c></item>
1151
        /// <item>A <c>Double</c> - returns an instance of <c>xs:double</c></item>
1152
        /// <item>A <c>Float</c> - returns an instance of <c>xs:float</c></item>
1153
        /// <item>A <c>decimal</c> - returns an instance of <c>xs:decimal</c></item>
1154
        /// <item>A <c>URI</c> - returns an instance of <c>xs:anyURI</c></item>
1155
        /// <item>A <c>QName</c> - returns an instance of <c>xs:QName</c></item>
1156
        /// </list>
1157
        /// </remarks>
1158
        /// <param name="value">The value to be converted.</param>
1159
        /// <returns>The converted value</returns>
1160
1161
        public static XdmAtomicValue MakeAtomicValue(object value)
1162
        {
1163
            if (value is JAtomicValue)
1164
            {
1165
                return (XdmAtomicValue)XdmValue.Wrap((JAtomicValue)value);
1166
            }
1167
            else if (value is Boolean)
1168
            {
1169
                return new XdmAtomicValue((Boolean)value);
1170
            }
1171
            else if (value is int)
1172
            {
1173
                return new XdmAtomicValue((int)value);
1174
            }
1175
            else if (value is long)
1176
            {
1177
                return new XdmAtomicValue((long)value);
1178
            }
1179
            else if (value is short)
1180
            {
1181
                return new XdmAtomicValue((short)value);
1182
            }
1183
            else if (value is Char)
1184
            {
1185
                return new XdmAtomicValue((long)value);
1186
            }
1187
            else if (value is Byte)
1188
            {
1189
                return new XdmAtomicValue((Byte)value);
1190
            }
1191
            else if (value is String)
1192
            {
1193
                return new XdmAtomicValue((String)value);
1194
            }
1195
            else if (value is Double)
1196
            {
1197
                return new XdmAtomicValue((Double)value);
1198
            }
1199
            else if (value is float)
1200
            {
1201
                return new XdmAtomicValue((float)value);
1202
            }
1203
            else if (value is decimal)
1204
            {
1205
                return new XdmAtomicValue((decimal)value);
1206
            }
1207
            else if (value is Uri)
1208
            {
1209
                return new XdmAtomicValue((Uri)value);
1210
            }
1211
            else if (value is QName)
1212
            {
1213
                return new XdmAtomicValue((QName)value);
1214
            }
1215
            if (value is XdmAtomicValue)
1216
            {
1217
                return (XdmAtomicValue)value;
1218
            }
1219
            else
1220
            {
1221
                throw new ArgumentException(value.ToString());
1222
            }
1223
        }
1224
1225
1226
        /// <summary>
1227
        /// Get the value converted to a boolean using the XPath casting rules.
1228
        /// </summary>
1229
        /// <returns>The result of converting to a boolean (Note: this is not the same as the
1230
        /// effective boolean value).</returns> 
1231
1232
        public bool GetBooleanValue()
1233
        {
1234
            JAtomicValue av = (JAtomicValue)this.value;
1235
            if (av is JBooleanValue)
1236
            {
1237
                return ((JBooleanValue)av).getBooleanValue();
1238
            }
1239
            else if (av is JNumericValue)
1240
            {
1241
                return !av.isNaN() && ((JNumericValue)av).signum() != 0;
1242
            }
1243
            else if (av is JStringValue)
1244
            {
1245
                String s = av.getStringValue().Trim();
1246
                return "1".Equals(s) || "true".Equals(s);
1247
            }
1248
            else
1249
            {
1250
                throw new ArgumentException("Cannot cast item to a boolean");
1251
            }
1252
        }
1253
1254
1255
        /// <summary>
1256
        /// Get the value converted to a long using the XPath casting rules.
1257
        /// </summary>
1258
        /// <returns>The result of converting to a long</returns>
1259
1260
        public long GetLongValue()
1261
        {
1262
            JAtomicValue av = (JAtomicValue)this.value;
1263
            if (av is JBooleanValue)
1264
            {
1265
                return ((JBooleanValue)av).getBooleanValue() ? 0L : 1L;
1266
            }
1267
            else if (av is JNumericValue)
1268
            {
1269
                try
1270
                {
1271
                    return ((JNumericValue)av).longValue();
1272
                }
1273
                catch (Exception)
1274
                {
1275
                    throw new ArgumentException("Cannot cast item to an integer");
1276
                }
1277
            }
1278
            else if (av is JStringValue)
1279
            {
1280
                JStringToDouble converter = JStringToDouble.getInstance();
1281
                return (long)converter.stringToNumber(av.getStringValueCS());
1282
            }
1283
            else
1284
            {
1285
                throw new ArgumentException("Cannot cast item to an integer");
1286
            }
1287
        }
1288
1289
1290
        /// <summary>
1291
		/// Get the value converted to a double using the XPath casting rules.
1292
		/// </summary>
1293
        /// <remarks>If the value is a string, the XSD 1.1 rules are used, which means that the string
1294
		/// "+INF" is recognised.</remarks>
1295
        /// <returns>The result of converting to a double</returns>
1296
1297
        public double GetDoubleValue()
1298
        {
1299
            JAtomicValue av = (JAtomicValue)this.value;
1300
            if (av is JBooleanValue)
1301
            {
1302
                return ((JBooleanValue)av).getBooleanValue() ? 0.0 : 1.0;
1303
            }
1304
            else if (av is JNumericValue)
1305
            {
1306
                return ((JNumericValue)av).getDoubleValue();
1307
            }
1308
            else if (av is JStringValue)
1309
            {
1310
                try
1311
                {
1312
                    JStringToDouble converter = JStringToDouble11.getInstance();
1313
                    return converter.stringToNumber(av.getStringValueCS());
1314
                }
1315
                catch (Exception e)
1316
                {
1317
                    throw new ArgumentException(e.Message);
1318
                }
1319
            }
1320
            else
1321
            {
1322
                throw new ArgumentException("Cannot cast item to a double");
1323
            }
1324
        }
1325
1326
1327
        /// <summary>
1328
        /// Get the value converted to a decimal using the XPath casting rules.
1329
        /// </summary>
1330
        /// <returns>The result of converting to a decimal</returns>
1331
1332
        public Decimal GetDecimalValue()
1333
        {
1334
            JAtomicValue av = (JAtomicValue)this.value;
1335
            if (av is JBooleanValue)
1336
            {
1337
                return ((JBooleanValue)av).getBooleanValue() ? 0 : 1;
1338
            }
1339
            else if (av is JNumericValue)
1340
            {
1341
                try
1342
                {
1343
                    return Convert.ToDecimal(((JNumericValue)av).getDecimalValue().toString());
1344
                }
1345
                catch (Exception)
1346
                {
1347
                    throw new ArgumentException("Cannot cast item to a decimal");
1348
                }
1349
            }
1350
            else if (av is JStringValue)
1351
            {
1352
                return Convert.ToDecimal(av.getStringValueCS().toString());
1353
            }
1354
            else
1355
            {
1356
                throw new ArgumentException("Cannot cast item to a decimal");
1357
            }
1358
        }
1359
1360
1361
1362
        /// <summary>
1363
        /// Convert the atomic value to a string
1364
        /// </summary>
1365
        /// <returns>The value converted to a string, according to the rules
1366
        /// of the XPath cast expression</returns>        
1367
1368
        public override String ToString()
1369
        {
1370
            return ((JAtomicValue)value).getStringValue();
1371
        }
1372
1373
        /// <summary>
1374
        /// Compare two atomic values for equality
1375
		/// </summary>
1376
		/// <param name="other">The object to be compared</param>
1377
        /// <returns>The result of the equality comparison, using the rules of the
1378
        /// <c>op:is-same-key()</c> comparison used for comparing key values in maps.</returns>
1379
1380
        public override Boolean Equals(object other)
1381
        {
1382
            if (other is XdmAtomicValue)
1383
            {
1384
                return ((JAtomicValue)value).asMapKey().Equals(((JAtomicValue)((XdmAtomicValue)other).value).asMapKey());
1385
1386
            }
1387
            else
1388
            {
1389
                return false;
1390
            }
1391
        }
1392
1393
        /// <summary>
1394
        /// Get a hash code to support equality comparison
1395
        /// </summary>
1396
        /// <returns>A suitable hash code</returns>
1397
1398
        public override int GetHashCode()
1399
        {
1400
            return ((JAtomicValue)value).asMapKey().GetHashCode();
1401
        }
1402
1403
        /// <summary>
1404
        /// Get the name of the value's XDM type
1405
        /// </summary>
1406
        /// <returns>The type of the value, as a QName.</returns>
1407
1408
1409
        public QName GetTypeName()
1410
        {
1411
            JStructuredQName sqname = ((JAtomicValue)value).getItemType().getStructuredQName();
1412
            return new QName(sqname.getPrefix(),
1413
                             sqname.getURI(),
1414
                             sqname.getLocalPart());
1415
        }
1416
1417
        /// <summary>
1418
        /// Get the name of the value's XDM type
1419
        /// </summary>
1420
        /// <param name="processor">The <code>Processor</code> object. 
1421
        /// This parameter is no longer used, but is accepted for backwards compatibility.</param>
1422
        /// <returns>The type of the value, as a QName.</returns>
1423
1424
1425
        public QName GetTypeName(Processor processor)
1426
        {
1427
            return GetTypeName();
1428
        }
1429
1430
        /// <summary>
1431
        /// Get the name of the primitive type of the value
1432
        /// </summary>
1433
        /// <returns>The primitive type of the value, as a QName. This will be the name of
1434
        /// one of the primitive types defined in XML Schema Part 2, or the XPath-defined
1435
        /// type <c>xs:untypedAtomic</c>. For the purposes of this method, <c>xs:integer</c> is considered
1436
        /// to be a primitive type.
1437
        /// </returns>
1438
1439
1440
        public QName GetPrimitiveTypeName()
1441
        {
1442
            int fp = ((JAtomicValue)value).getItemType().getPrimitiveType();
1443
            return new QName(JStandardNames.getPrefix(fp),
1444
                             JStandardNames.getURI(fp),
1445
                             JStandardNames.getLocalName(fp));
1446
        }
1447
1448
        /// <summary>Get the value as a CLI object of the nearest equivalent type.</summary>
1449
        /// <remarks>
1450
        /// <para>The return type is as follows:</para>
1451
        /// <list>
1452
		/// <item><c>xs:string</c> - String</item>
1453
		/// <item><c>xs:integer</c> - Long</item>
1454
		/// <item><c>xs:decimal</c> - Decimal</item>
1455
		/// <item><c>xs:double</c> - Double</item>
1456
		/// <item><c>xs:float</c> - Float</item>
1457
		/// <item><c>xs:boolean</c> - Bool</item>
1458
		/// <item><c>xs:QName</c> - QName</item>
1459
		/// <item><c>xs:anyURI</c> - Uri</item>
1460
		/// <item><c>xs:untypedAtomic</c> - String</item>
1461
        /// <item>wrapped external object - the original external object</item>
1462
        /// <item>Other types - currently String, but this may change in the future</item>
1463
        /// </list>
1464
        /// </remarks>
1465
        /// <returns>The value converted to the most appropriate CLI type</returns>
1466
1467
        public Object Value
1468
        {
1469
            get
1470
            {
1471
                if (value is JIntegerValue)
1472
                {
1473
                    return ((JIntegerValue)value).longValue();
1474
                }
1475
                else if (value is JDoubleValue)
1476
                {
1477
                    return ((JDoubleValue)value).getDoubleValue();
1478
                }
1479
                else if (value is JFloatValue)
1480
                {
1481
                    return ((JFloatValue)value).getFloatValue();
1482
                }
1483
                else if (value is JDecimalValue)
1484
                {
1485
                    return Decimal.Parse(((JDecimalValue)value).getStringValue());
1486
                }
1487
                else if (value is JBooleanValue)
1488
                {
1489
                    return ((JBooleanValue)value).getBooleanValue();
1490
                }
1491
                else if (value is JAnyURIValue)
1492
                {
1493
                    return new Uri(((JAnyURIValue)value).getStringValue());
1494
                }
1495
                else if (value is JQNameValue)
1496
                {
1497
                    return new QName((JQNameValue)value);
1498
                }
1499
                else if (value is JDotNetObjectValue) // TODO: can't happen?
1500
                {
1501
                    return ((JDotNetObjectValue)value).getObject();
1502
                }
1503
                else
1504
                {
1505
                    return ((JAtomicValue)value).getStringValue();
1506
                }
1507
            }
1508
        }
1509
1510
1511
    }
1512
1513
    /// <summary inherits="XdmItem">
1514
    /// The class <c>XdmFunctionItem</c> represents an item in an XDM sequence
1515
    /// that holds a function.
1516
    /// </summary>
1517
    /// <remarks>
1518
    /// <para>Note that there is no guarantee that every <c>XdmValue</c> comprising a single
1519
    /// function item will be an instance of this class. To force this, use the <c>Simplify</c>
1520
    /// property of the <c>XdmValue</c>.</para>
1521
    /// <para>At present the only way of creating an instance of this class is as the result of
1522
    /// an XPath or XQuery expression that returns a function item.</para>
1523
    /// </remarks>
1524
1525
    [Serializable]
1526
    public class XdmFunctionItem : XdmItem
1527
    {
1528
        /// <summary>
1529
        /// The name of the function, as a QName
1530
        /// </summary>
1531
        /// <returns>The name of the function. The result will be null if the function is anonymous.</returns>
1532
1533
        public QName FunctionName
1534
        {
1535
            get
1536
            {
1537
                JStructuredQName sqname = ((JFunction)value).getFunctionName();
1538
                return (sqname == null ? null : QName.FromStructuredQName(sqname));
1539
            }
1540
        }
1541
1542
        /// <summary>
1543
        /// The arity of the function, that is, the number of arguments it expects
1544
        /// </summary>
1545
		/// <returns>The number of arguments that the function takes</returns>
1546
1547
        public int Arity
1548
        {
1549
            get
1550
            {
1551
                return ((JFunction)value).getArity();
1552
            }
1553
        }
1554
1555
        /// <summary>
1556
        /// Determine whether the item is an atomic value
1557
        /// </summary>
1558
        /// <returns>
1559
        /// false (a function item is not an atomic value)
1560
        /// </returns>
1561
1562
        public override bool IsAtomic()
1563
        {
1564
            return false;
1565
        }
1566
1567
1568
        /// <summary>
1569
        /// Invoke the function
1570
        /// </summary>
1571
        /// <param name="arguments">The arguments to the function</param>
1572
        /// <param name="processor">The Saxon processor, used to provide context information</param>
1573
        /// <returns>The result of calling the function</returns>
1574
        /// 
1575
        public XdmValue Invoke(XdmValue[] arguments, Processor processor)
1576
        {
1577
            JXdmValue[] args = new JXdmValue[arguments.Length];
1578
            for (int i = 0; i < arguments.Length; i++)
1579
            {
1580
                args[i] = FromGroundedValueToJXdmValue(arguments[i].value);
1581
            }
1582
            JFunction function = (JFunction)value;
1583
            net.sf.saxon.s9api.XdmFunctionItem functionItem = new net.sf.saxon.s9api.XdmFunctionItem(function);
1584
            JXdmValue result = functionItem.call(processor.JProcessor, args);
1585
1586
            return XdmValue.Wrap(result.getUnderlyingValue());
1587
        }
1588
    }
1589
1590
    /// <summary inherits="XdmFunctionItem">
1591
    /// The class <c>XdmArray</c> represents an array item in an XDM 3.1 sequence:
1592
    /// this is a new kind of item in the XDM data model. An array is a list of zero or 
1593
    /// more members, each of which is an arbitrary XDM value. An array is also a function:
1594
    /// it maps a positive integer to the array member found at that position in the array.
1595
    /// </summary>
1596
    [Serializable]
1597
    public class XdmArray : XdmFunctionItem
1598
    {
1599
1600
1601
        ///<summary> Constructor to create an empty <c>XdmArray</c></summary>
1602
        public XdmArray()
1603
        {
1604
            this.value = JSimpleArrayItem.EMPTY_ARRAY;
1605
        }
1606
1607
        ///<summary>Create an <c>XdmArray</c> whose members are single items, corresponding
1608
        ///one-to-one with the items making up a supplied sequence.</summary>
1609
        ///<param name="value">A sequence of items; each item becomes a member of the array.</param>
1610
        public XdmArray(XdmValue value)
1611
        {
1612
            int length = value.Count;
1613
            JArrayList list = new JArrayList(length);
1614
            foreach (XdmItem item in value.GetList())
1615
            {
1616
                list.add(item.Unwrap());
1617
            }
1618
            this.value = new JSimpleArrayItem(list);
1619
        }
1620
1621
        ///<summary> Create an <c>XdmArray</c> supplying the members as an array of <c>XdmValue</c> objects.</summary>
1622
        /// <param name="members">An array of <c>XdmValue</c> objects. Note that subsequent changes 
1623
        /// to the array will have no effect on the <c>XdmArray</c>.</param>
1624
1625
1626
        public XdmArray(XdmValue[] members)
1627
        {
1628
            JArrayList list = new JArrayList(members.Length);
1629
            for (int i = 0; i < members.Length; i++)
1630
            {
1631
                list.add(members[i].Unwrap());
1632
            }
1633
            this.value = new JSimpleArrayItem(list);
1634
        }
1635
1636
        // Internal constructor
1637
1638
        internal XdmArray(JArrayList list)
1639
        {
1640
            this.value = new JSimpleArrayItem(list);
1641
        }
1642
1643
        // Internal constructor
1644
1645
        internal XdmArray(JArrayItem array)
1646
        {
1647
            this.value = array;
1648
        }
1649
1650
1651
        /// <summary>Create an <c>XdmArray</c> supplying the members as a list of <c>XdmValue</c> objects</summary>
1652
        /// <param name="members">A sequence of <c>XdmValue</c> objects. Note that if this is supplied as 
1653
        /// a list or similar collection, subsequent changes to the list/collection will have no effect on 
1654
        /// the <c>XdmValue</c>.</param>
1655
        /// <remarks>Note that the argument can be a single <c>XdmValue</c> representing a sequence, in which case the
1656
        ///  constructed array will have one member for each item in the supplied sequence.</remarks>
1657
1658
        public XdmArray(List<XdmValue> members)
1659
        {
1660
            JArrayList list = new JArrayList(members.Count);
1661
            for (int i = 0; i < members.Count; i++)
1662
            {
1663
                list.add(members[i].Unwrap());
1664
            }
1665
            this.value = new JSimpleArrayItem(list);
1666
        }
1667
1668
        /// <summary>
1669
        /// Get the number of members in the array
1670
        /// </summary>
1671
        /// <returns>the number of members in the array.</returns> 
1672
		/// <remarks>(Note that the <see cref="XdmValue.Count"/> property returns 1 (one),
1673
        /// because an XDM array is an item.)</remarks>
1674
        public int ArrayLength()
1675
        {
1676
            return ((JArrayItem)value).arrayLength();
1677
        }
1678
1679
        /// <summary>
1680
        /// Get the n'th member in the array, counting from zero.
1681
        /// </summary>
1682
		/// <param name="n">the position of the member that is required, counting the first member in 
1683
		/// the array as member zero</param>
1684
        /// <returns>the n'th member in the sequence making up the array, counting from zero</returns>
1685
        public XdmValue Get(int n)
1686
        {
1687
            try
1688
            {
1689
                JSequence member = ((JArrayItem)value).get(n);
1690
                return XdmValue.Wrap(member);
1691
            }
1692
            catch (Exception)
1693
            {
1694
                throw new IndexOutOfRangeException();
1695
            }
1696
        }
1697
1698
1699
        /// <summary>
1700
        /// Create a new array in which one member is replaced with a new value.
1701
        /// </summary>
1702
        /// <param name="n">the position of the member that is to be replaced, counting the first member
1703
        /// in the array as member zero</param>
1704
        /// <param name="valuei">the new value</param>
1705
        /// <returns>the new array</returns>
1706
        public XdmArray Put(int n, XdmValue valuei)
1707
        {
1708
            try
1709
            {
1710
                return (XdmArray)XdmValue.Wrap(((JArrayItem)this.value).put(n, valuei.value));
1711
            }
1712
            catch (Exception)
1713
            {
1714
                throw new IndexOutOfRangeException();
1715
            }
1716
        }
1717
1718
1719
        /// <summary>
1720
        /// Append a new member to an array
1721
        /// </summary>
1722
        /// <param name="value">the new member</param>
1723
        /// <returns>a new array, one item longer than the original</returns>
1724
        public XdmArray AppendMember(XdmValue value)
1725
        {
1726
            try
1727
            {
1728
                JGroundedValue member = value.value;
1729
                JArrayItem newArray = net.sf.saxon.ma.arrays.ArrayFunctionSet.ArrayAppend.append((JArrayItem)this.value, member);
1730
                return (XdmArray)Wrap(newArray);
1731
            }
1732
            catch (net.sf.saxon.trans.XPathException e)
1733
            {
1734
                throw new StaticError(e);
1735
            }
1736
        }
1737
1738
        /// <summary>
1739
        /// Concatenate another array
1740
        /// </summary>
1741
        /// <param name="value">the other array</param>
1742
        /// <returns>a new array, containing the members of this array followed by the members 
1743
        /// of the other array</returns>
1744
        public XdmArray Concat(XdmArray value)
1745
        {
1746
            try
1747
            {
1748
                JArrayItem other = (JArrayItem)value.value;
1749
                JArrayItem newArray = ((JArrayItem)this.value).concat(other);
1750
                return (XdmArray)Wrap(newArray);
1751
            }
1752
            catch (net.sf.saxon.trans.XPathException e)
1753
            {
1754
                throw new StaticError(e);
1755
            }
1756
        }
1757
1758
1759
        /// <summary>
1760
        /// Get the members of the array in the form of a list.
1761
        /// </summary>
1762
        /// <returns>A list of the members of this array.</returns>
1763
        public List<XdmValue> AsList()
1764
        {
1765
1766
            JArrayItem val = ((JArrayItem)value);
1767
            java.util.Iterator iter = val.members().iterator();
1768
            List<XdmValue> result = new List<XdmValue>(val.getLength());
1769
            while (iter.hasNext())
1770
            {
1771
                result.Add(XdmValue.Wrap((JSequence)iter.next()));
1772
1773
            }
1774
            return result;
1775
        }
1776
1777
        /// <summary>
1778
        /// Make an XDM array from an object array. Each member of the supplied array
1779
        /// is converted to a single member in the result array using the method
1780
        /// <see cref="XdmValue.MakeValue(Object)"/>        
1781
        /// </summary>
1782
        /// <param name="o">the array of objects</param>
1783
        /// <returns>the result of the conversion if successful</returns>
1784
1785
        public static XdmArray MakeArray(object[] o)
1786
        {
1787
            JArrayList list = new JArrayList(o.Length);
1788
            for (int i = 0; i < o.Length; i++)
1789
            {
1790
                list.add(XdmValue.MakeValue(o[i]).Unwrap());
1791
            }
1792
            return new XdmArray(list);
1793
        }
1794
1795
        /// <summary>
1796
        /// Make an <c>XdmArray</c> whose members are <c>xs:boolean</c> values       
1797
        /// </summary>
1798
        /// <param name="o">the input array of booleans</param>
1799
        /// <returns>an <c>XdmArray</c> whose members are <c>xs:boolean</c> values corresponding one-to-one with the input</returns>
1800
1801
        public static XdmArray MakeArray(bool[] o)
1802
        {
1803
            JArrayList list = new JArrayList(o.Length);
1804
            for (int i = 0; i < o.Length; i++)
1805
            {
1806
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1807
            }
1808
            return new XdmArray(list);
1809
        }
1810
1811
1812
        /// <summary>
1813
        /// Make an <c>XdmArray</c> whose members are <c>xs:integer</c> values      
1814
        /// </summary>
1815
        /// <param name="o">the input array of long values</param>
1816
        /// <returns>an <c>XdmArray</c> whose members are <c>xs:integer</c> values corresponding one-to-one with the input</returns>
1817
1818
        public static XdmArray MakeArray(long[] o)
1819
        {
1820
            JArrayList list = new JArrayList(o.Length);
1821
            for (int i = 0; i < o.Length; i++)
1822
            {
1823
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1824
            }
1825
            return new XdmArray(list);
1826
        }
1827
1828
1829
        /// <summary>
1830
        /// Make an <c>XdmArray</c> whose members are <c>xs:integer</c> values      
1831
        /// </summary>
1832
        /// <param name="o">the input array of int values</param>
1833
        /// <returns>an <c>XdmArray</c> whose members are <c>xs:integer</c> values corresponding one-to-one with the input</returns>
1834
1835
        public static XdmArray MakeArray(int[] o)
1836
        {
1837
            JArrayList list = new JArrayList(o.Length);
1838
            for (int i = 0; i < o.Length; i++)
1839
            {
1840
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1841
            }
1842
            return new XdmArray(list);
1843
        }
1844
1845
        /// <summary>
1846
        /// Make an <c>XdmArray</c> whose members are <c>xs:integer</c> values      
1847
        /// </summary>
1848
        /// <param name="o">the input array of byte values</param>
1849
        /// <returns>an <c>XdmArray</c> whose members are <c>xs:integer</c> values corresponding one-to-one with the input</returns>
1850
1851
        public static XdmArray MakeArray(byte[] o)
1852
        {
1853
            JArrayList list = new JArrayList(o.Length);
1854
            for (int i = 0; i < o.Length; i++)
1855
            {
1856
                list.add(new XdmAtomicValue(o[i]).Unwrap());
1857
            }
1858
            return new XdmArray(list);
1859
        }
1860
    }
1861
1862
    /// <summary inherits="XdmFunctionItem">
1863
    /// The class <c>XdmMap</c> represents a map item in an XPath 3.1 sequence:
1864
	/// 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
1865
    /// is a pair comprising a key (which is an atomic value) and a value (which is an arbitrary value).
1866
    /// </summary>
1867
1868
1869
    [Serializable]
1870
    public class XdmMap : XdmFunctionItem
1871
    {
1872
1873
1874
        /// <summary>
1875
        /// Create an empty <c>XdmMap</c>
1876
        /// </summary>
1877
        public XdmMap()
1878
        {
1879
            this.value = new JHashTrieMap();
1880
        }
1881
1882
        // Internal constructor
1883
1884
        internal XdmMap(JHashTrieMap map)
1885
        {
1886
            this.value = map;
1887
        }
1888
1889
1890
        /// <summary>
1891
        /// Get the number of entries in the map
1892
        /// </summary>
1893
        /// <remarks>(Note that the <see cref="XdmValue.Count"/> method returns 1 (one),
1894
        /// because an XDM map is an item.)</remarks>
1895
1896
        public int Size
1897
        {
1898
            get
1899
            {
1900
                return ((JMapItem)value).size();
1901
            }
1902
        }
1903
1904
1905
        /// <summary>
1906
        /// Ask whether the <c>XdmMap</c> is empty
1907
        /// </summary>
1908
        /// <returns>Returns <code>true</code> if this map contains no key-value pairs, that is
1909
        /// if the <c>Size</c> property is zero.</returns>
1910
1911
        public bool IsEmpty()
1912
        {
1913
            return ((JMapItem)value).isEmpty();
1914
        }
1915
1916
        /// <summary>
1917
        /// Create a new map containing an additional (key, value) pair.
1918
        /// If there is an existing entry with the same key, it is removed.
1919
        /// </summary>
1920
        /// <param name="key">The key of the new entry.</param>
1921
        /// <param name="value">The value part of the new entry.</param>
1922
        /// <returns>A new map containing the additional entry (or replaced entry). The original map is unchanged.</returns>
1923
1924
        public XdmMap Put(XdmAtomicValue key, XdmValue value)
1925
        {
1926
            XdmMap map2 = new XdmMap();
1927
            map2.value = ((JMapItem)this.value).addEntry((JAtomicValue)key.Unwrap(), value.value);
1928
            return map2;
1929
        }
1930
1931
1932
        /// <summary>
1933
        /// Create a new map in which the entry for a given key has been removed.
1934
        /// If there is no entry with the same key, the new map has the same content as the old (it may or may not
1935
        /// be the same .NET object)
1936
        /// </summary>
1937
        /// <param name="key">The key of the entry that is to be removed</param>
1938
        /// <returns>A map without the specified entry. The original map is unchanged.</returns>
1939
1940
        public XdmMap Remove(XdmAtomicValue key)
1941
        {
1942
            XdmMap map2 = new XdmMap();
1943
            map2.value = ((JMapItem)this.value).remove((JAtomicValue)key.Unwrap());
1944
            return map2;
1945
        }
1946
1947
1948
        /// <summary>
1949
        /// Return a corresponding .NET Dictionary collection of keys and values.
1950
        /// </summary>
1951
        /// <returns>A mutable Dictionary from atomic values to (sequence) values, containing the
1952
        /// same entries as this map</returns>
1953
1954
        public Dictionary<XdmAtomicValue, XdmValue> AsDictionary()
1955
        {
1956
            Dictionary<XdmAtomicValue, XdmValue> map = new Dictionary<XdmAtomicValue, XdmValue>();
1957
            JMapItem jmap = (JMapItem)value;
1958
            java.util.Iterator iter = jmap.keyValuePairs().iterator();
1959
            JKeyValuePair pair = null;
1960
            while (iter.hasNext())
1961
            {
1962
                pair = (JKeyValuePair)iter.next();
1963
                map.Add((XdmAtomicValue)XdmValue.Wrap(pair.key), XdmValue.Wrap(pair.value));
1964
            }
1965
            return map;
1966
        }
1967
1968
1969
        /// <summary>
1970
        /// Get the keys present in the map in the form of a set.
1971
        /// </summary>
1972
        /// <returns>a set of the keys present in this map, with no defined ordering.</returns>
1973
        public HashSet<XdmAtomicValue> KeySet()
1974
        {
1975
            HashSet<XdmAtomicValue> result = new HashSet<XdmAtomicValue>();
1976
            JMapItem jmap = (JMapItem)value;
1977
            net.sf.saxon.tree.iter.AtomicIterator iter = jmap.keys();
1978
            JAtomicValue key = null;
1979
            while ((key = iter.next()) != null)
1980
            {
1981
                result.Add((XdmAtomicValue)XdmValue.Wrap(key));
1982
            }
1983
            return result;
1984
        }
1985
1986
1987
        /// <summary>
1988
        /// Returns <code>true</code> if this map contains a mapping for the specified
1989
        /// key. More formally, returns <code>true</code> if and only if
1990
        /// this map contains a mapping for a key <code>k</code> such that
1991
        /// <code>(key==null ? k==null : key.Equals(k))</code>.  (There can be
1992
        /// at most one such mapping.)
1993
        /// </summary>
1994
        /// <param name="key">the key whose presence in this map is to be tested</param>
1995
        /// <returns><c>true</c> if this map contains a mapping for the specified key</returns>
1996
1997
        public bool ContainsKey(XdmAtomicValue key)
1998
        {
1999
            JAtomicValue k = (JAtomicValue)key.value;
2000
            return ((JMapItem)value).get(k) != null;
2001
        }
2002
2003
2004
        /// <summary>
2005
        /// Returns the value to which the specified key is mapped,
2006
        /// or <c>null</c> if this map contains no mapping for the key.
2007
        /// </summary>
2008
        /// <param name="key">the key whose associated value is to be returned. If this is
2009
        /// not an <c>XdmAtomicValue</c>, the method attempts to construct an
2010
        /// <c>XdmAtomicValue</c> using the method <see cref="XdmAtomicValue.MakeAtomicValue(Object)"/>;
2011
        /// it is therefore possible to pass a simple key such as a string or integer.</param>
2012
        /// <returns>the value to which the specified key is mapped, or
2013
        /// <c>null</c> if this map contains no mapping for the key</returns>
2014
2015
        public XdmValue Get(XdmAtomicValue key)
2016
        {
2017
            if (key == null)
2018
            {
2019
                throw new ArgumentNullException();
2020
            }
2021
2022
            JAtomicValue k = (JAtomicValue)(key).value;
2023
            JSequence v = ((JMapItem)value).get(k);
2024
            return v == null ? null : XdmValue.Wrap(v);
2025
        }
2026
2027
        /// <summary>
2028
        /// Returns the value to which the specified key is mapped,
2029
        /// or <c>null</c> if this map contains no mapping for the key.
2030
        /// </summary>
2031
        /// <param name="key">the key whose associated value is to be returned.</param>
2032
        /// <returns>the value to which the specified key is mapped, or
2033
        /// <c>null</c> if this map contains no mapping for the key</returns>
2034
2035
        public XdmValue Get(String key)
2036
        {
2037
            if (key == null)
2038
            {
2039
                throw new ArgumentNullException();
2040
            }
2041
2042
            JAtomicValue k = (JAtomicValue)(new XdmAtomicValue(key)).value;
2043
            JSequence v = ((JMapItem)value).get(k);
2044
            return v == null ? null : XdmValue.Wrap(v);
2045
        }
2046
2047
2048
        /// <summary>
2049
        /// Returns the value to which the specified key is mapped,
2050
        /// or <c>null</c> if this map contains no mapping for the key.
2051
        /// </summary>
2052
        /// <param name="key">the key whose associated value is to be returned.</param>
2053
        /// <returns>the value to which the specified key is mapped, or
2054
        /// <c>null</c> if this map contains no mapping for the key</returns>
2055
2056
        public XdmValue Get(long key)
2057
        {
2058
2059
            JAtomicValue k = (JAtomicValue)(new XdmAtomicValue(key)).value;
2060
            JSequence v = ((JMapItem)value).get(k);
2061
            return v == null ? null : XdmValue.Wrap(v);
2062
        }
2063
2064
        /// <summary>
2065
        /// Returns a <c>Collection</c> containing the values found in this map.
2066
        /// </summary>
2067
        /// <returns>A collection of the values found in this map, that is, the value
2068
        /// parts of the key-value pairs. The result may contain duplicates, and the
2069
        /// order of results is unpredictable.</returns>
2070
        public ICollection Values()
2071
        {
2072
            List<XdmValue> result = new List<XdmValue>();
2073
2074
            JMapItem jmap = (JMapItem)value;
2075
            java.util.Iterator iter = jmap.keyValuePairs().iterator();
2076
            JKeyValuePair pair = null;
2077
            while ((pair = (JKeyValuePair)iter.next()) != null)
2078
            {
2079
                result.Add((XdmAtomicValue)XdmValue.Wrap(pair.value));
2080
            }
2081
2082
            return result;
2083
        }
2084
2085
2086
        /// <summary>
2087
		/// Returns a <c>HashSet</c> view of the mappings contained in this map.
2088
        /// </summary>
2089
        /// <returns>a set view of the mappings contained in this map</returns>
2090
        public HashSet<DictionaryEntry> EntrySet()
2091
        {
2092
            HashSet<DictionaryEntry> result = new HashSet<DictionaryEntry>();
2093
            JMapItem jmap = (JMapItem)value;
2094
            java.util.Iterator iter = jmap.keyValuePairs().iterator();
2095
            JKeyValuePair pair = null;
2096
            while ((pair = (JKeyValuePair)iter.next()) != null)
2097
            {
2098
                result.Add(new DictionaryEntry(pair.key, pair.value));
2099
            }
2100
            return result;
2101
        }
2102
2103
2104
        /// <summary>
2105
        /// Static factory method to construct an XDM map by converting each entry
2106
        /// in a supplied generic collection of key/value pairs; <code>IDictionary</code>. The keys in the 
2107
        /// Dictionary must be convertible to XDM atomic values using the 
2108
		/// <see cref="XdmAtomicValue.MakeAtomicValue(Object)"/> method. The associated values 
2109
        /// must be convertible to XDM sequences
2110
		/// using the <see cref="XdmValue.MakeValue(Object)"/> method.
2111
        /// </summary>
2112
        /// <param name="input">the supplied map</param>
2113
		/// <returns>the resulting <c>XdmMap</c></returns>
2114
        public static XdmMap MakeMap(IDictionary input)
2115
        {
2116
            JHashTrieMap result = new JHashTrieMap();
2117
            XdmAtomicValue key;
2118
            XdmValue value;
2119
2120
            foreach (object keyi in input.Keys)
2121
            {
2122
                key = XdmAtomicValue.MakeAtomicValue(keyi);
2123
                value = XdmValue.MakeValue(input[keyi]);
2124
                result.initialPut((JAtomicValue)key.Unwrap(), value.value);
2125
            }
2126
2127
            return new XdmMap(result);
2128
        }
2129
2130
2131
2132
2133
    }
2134
2135
    /// <summary inherits="XdmItem">
2136
    /// The class <c>XdmNode</c> represents a Node in the XDM Data Model. A Node
2137
    /// is an <c>XdmItem</c>, and is therefore an <c>XdmValue</c> in its own right, and may also participate
2138
    /// as one item within a sequence value.
2139
    /// </summary>
2140
    /// <remarks>
2141
    /// <para>An <c>XdmNode</c> is implemented as a wrapper around an object
2142
    /// of type <c>net.sf.saxon.NodeInfo</c>. Because this is a key interface
2143
    /// within Saxon, it is exposed via this API, even though it is a Java
2144
    /// interface that is not part of the API proper.</para>
2145
    /// <para>The <c>XdmNode</c> interface exposes basic properties of the node, such
2146
    /// as its name, its string value, and its typed value. Navigation to other nodes
2147
    /// is supported through a single method, <c>EnumerateAxis</c>, which allows
2148
    /// other nodes to be retrieved by following any of the XPath axes.</para>
2149
    /// </remarks>
2150
2151
    [Serializable]
2152
    public class XdmNode : XdmItem
2153
    {
2154
2155
        /// <summary>
2156
        /// Determine whether the item is an atomic value
2157
        /// </summary>
2158
        /// <returns>
2159
        /// false (the item is not an atomic value)
2160
        /// </returns>
2161
2162
        public override bool IsAtomic()
2163
        {
2164
            return false;
2165
        }
2166
2167
        /// <summary>
2168
        /// The name of the node, as a <c>QName</c>. Returns null in the case of unnamed nodes.
2169
        /// </summary>
2170
2171
        public QName NodeName
2172
        {
2173
            get
2174
            {
2175
                JNodeInfo node = (JNodeInfo)value;
2176
                String local = node.getLocalPart();
2177
                if (local == "")
2178
                {
2179
                    return null;
2180
                }
2181
                String prefix = node.getPrefix();
2182
                String uri = node.getURI();
2183
                return new QName(prefix, uri, local);
2184
            }
2185
        }
2186
2187
        /// <summary>
2188
        /// The kind of node, as an instance of <c>System.Xml.XmlNodeType</c>.
2189
        /// </summary>
2190
		/// <remarks>For a namespace node in the XDM model, the value <c>XmlNodeType.None</c> 
2191
        /// is returned.
2192
        /// </remarks>
2193
2194
        public XmlNodeType NodeKind
2195
        {
2196
            get
2197
            {
2198
                JNodeInfo node = (JNodeInfo)value;
2199
                int kind = node.getNodeKind();
2200
                switch (kind)
2201
                {
2202
                    case JType.DOCUMENT:
2203
                        return XmlNodeType.Document;
2204
                    case JType.ELEMENT:
2205
                        return XmlNodeType.Element;
2206
                    case JType.ATTRIBUTE:
2207
                        return XmlNodeType.Attribute;
2208
                    case JType.TEXT:
2209
                        return XmlNodeType.Text;
2210
                    case JType.COMMENT:
2211
                        return XmlNodeType.Comment;
2212
                    case JType.PROCESSING_INSTRUCTION:
2213
                        return XmlNodeType.ProcessingInstruction;
2214
                    case JType.NAMESPACE:
2215
                        return XmlNodeType.None;
2216
                    default:
2217
                        throw new ArgumentException("Unknown node kind");
2218
                }
2219
            }
2220
        }
2221
2222
        /// <summary>
2223
        /// Get the line number of the node in a source document. 
2224
        /// </summary>
2225
        /// <remarks>
2226
        /// For a document constructed using the document
2227
        /// builder, this is available only if the line numbering option was set when the document was built (and
2228
        /// then only for element nodes). If the line number is not available, the value -1 is returned.
2229
        /// Line numbers will typically be as reported by a SAX parser; this means that the line number for an element
2230
        /// node is the line number containing the closing ">" of the start tag.
2231
        /// </remarks>
2232
2233
        public int LineNumber
2234
        {
2235
            get { return ((JNodeInfo)value).getLineNumber(); }
2236
        }
2237
2238
2239
2240
        /// <summary>
2241
        /// Get the column number of the node in a source document. 
2242
        /// </summary>
2243
        /// <remarks>
2244
        /// For a document constructed using the document
2245
        /// builder, this is available only if the line numbering option was set when the document was built (and
2246
        /// then only for element nodes). If the column number is not available, the value -1 is returned.
2247
        /// Line numbers will typically be as reported by a SAX parser; this means that the column number for an element
2248
        /// node is the column number containing the closing ">" of the start tag.
2249
        /// </remarks>
2250
2251
        public int ColumnNumber
2252
        {
2253
            get { return ((JNodeInfo)value).getColumnNumber(); }
2254
        }
2255
2256
        /// <summary>
2257
        /// The typed value of the node, as an instance of <c>XdmValue</c>.
2258
        /// </summary>
2259
        /// <remarks>
2260
		/// A <c>DynamicError</c> is thrown if the node has no typed value, as will be the case for
2261
        /// an element with element-only content.
2262
		/// </remarks>
2263
2264
        public XdmValue TypedValue
2265
        {
2266
            get { return XdmValue.Wrap(((JNodeInfo)value).atomize()); }
2267
        }
2268
2269
        /// <summary>
2270
		/// Get a <see cref="Processor"/> suitable for use with this <see cref="XdmNode"/>.
2271
        /// </summary>
2272
        /// <remarks>
2273
		/// <para>In most cases this will be the original <see cref="Processor"/>
2274
		/// object used to create the <see cref="DocumentBuilder"/> that built the document that 
2275
		/// contains this node. If that <see cref="Processor"/> is not available, it will be a 
2276
		/// compatible <c>Processor</c>, one that shares the same underlying <see cref="net.sf.saxon.Configuration"/>, 
2277
        /// and hence is initialized with the same configuration settings, schema components, license features,
2278
        /// and so on.</para>
2279
		/// <para><i>Note: the only case where the original <c>Processor</c> is not available is when
2280
		/// the same <c>Configuration</c> is used with multiple APIs, for example mixing s9api
2281
        /// and JAXP or XQJ in the same application.</i></para>
2282
        /// </remarks>
2283
		/// <returns>Returns a <c>Processor</c> suitable for performing further operations on this node, for example
2284
		/// for creating a <see cref="Serializer"/> or an <see cref="XPathCompiler"/>.</returns>
2285
        public Processor Processor
2286
        {
2287
            get
2288
            {
2289
                JConfiguration config = Implementation.getConfiguration();
2290
                object originator = config.getProcessor();
2291
                if (originator is Processor)
2292
                {
2293
                    return (Processor)originator;
2294
                }
2295
                else
2296
                {
2297
                    return new Processor(new net.sf.saxon.s9api.Processor(config));
2298
                }
2299
            }
2300
        }
2301
2302
2303
        /// <summary>
2304
		/// Unwraps the underlying <c>XmlNode</c> object from the <c>XdmValue</c>.
2305
		/// If the method does not wrap a <c>XmlNode</c> then a null is returned
2306
        /// </summary>
2307
		/// <returns>The underlying <c>XmlNode</c></returns>
2308
        public XmlNode getUnderlyingXmlNode()
2309
        {
2310
2311
            if (value is net.sf.saxon.dotnet.DotNetNodeWrapper)
2312
            {
2313
2314
                return (XmlNode)((net.sf.saxon.dotnet.DotNetNodeWrapper)value).getRealNode();
2315
            }
2316
            return null;
2317
        }
2318
2319
        /// <summary>
2320
        /// Get the string value of the node.
2321
        /// </summary>
2322
2323
        public String StringValue
2324
        {
2325
            get { return ((JNodeInfo)value).getStringValue(); }
2326
        }
2327
2328
        /// <summary>
2329
        /// Get the parent of this node.
2330
        /// </summary>
2331
        /// <remarks>
2332
        /// Returns either a document node, an element node, or null in the case where
2333
        /// this node has no parent. 
2334
        /// </remarks>
2335
2336
        public XdmNode Parent
2337
        {
2338
            get
2339
            {
2340
                JNodeInfo parent = ((JNodeInfo)value).getParent();
2341
                return (parent == null ? null : (XdmNode)XdmValue.Wrap(parent));
2342
            }
2343
        }
2344
2345
        /// <summary>
2346
        /// Get the root of the tree containing this node.
2347
        /// </summary>
2348
        /// <remarks>
2349
        /// Returns the root of the tree containing this node (which might be this node itself).
2350
        /// </remarks>
2351
2352
        public XdmNode Root
2353
        {
2354
            get
2355
            {
2356
                XdmNode parent = Parent;
2357
                if (parent == null)
2358
                {
2359
                    return this;
2360
                }
2361
                else
2362
                {
2363
                    return parent.Root;
2364
                }
2365
            }
2366
        }
2367
2368
        /// <summary>
2369
        /// Get a the string value of a named attribute of this element. 
2370
        /// </summary>
2371
        /// <remarks>
2372
        /// Returns null if this node is not an element, or if this element has no
2373
        /// attribute with the specified name.
2374
        /// </remarks>
2375
        /// <param name="name">The name of the attribute whose value is required</param>
2376
2377
        public String GetAttributeValue(QName name)
2378
        {
2379
            return ((JNodeInfo)value).getAttributeValue(name.Uri, name.LocalName);
2380
        }
2381
2382
2383
        /// <summary>
2384
        /// Get a the string value of a named attribute (in no namespace) of this element. 
2385
        /// </summary>
2386
        /// <remarks>
2387
        /// Returns null if this node is not an element, or if this element has no
2388
        /// attribute with the specified name.
2389
        /// </remarks>
2390
        /// <param name="name">The name of the attribute whose value is required, interpreted as no-namespace name</param>
2391
2392
        public String GetAttributeValue(String name)
2393
        {
2394
            return ((JNodeInfo)value).getAttributeValue("", name);
2395
        }
2396
2397
        /// <summary>
2398
        /// Get a IEnumerable of XdmNodes by applying a <c>Step</c> to this
2399
        /// XdmNode value.
2400
        /// </summary>
2401
        /// <param name="step">the <c>Step</c> to be applied to this node</param>
2402
        /// <returns>an IEnumerable of nodes obtained by applying the <c>Step</c> function to this node</returns>
2403
        
2404
        public IEnumerable<XdmNode> Select(Step<XdmNode, XdmNode> step) {
2405
            return step.Invoke(this);
2406
        }
2407
2408
		/// <summary>
2409
		/// Get the nodes found on the child axis that satisfy a supplied <c>Predicate</c>.
2410
		/// </summary>
2411
		/// <param name="filter">the predicate to be applied</param>
2412
		/// <returns> an <c>Iterable</c> containing those nodes found on the child axis that satisfy the supplied predicate.</returns>
2413
2414
        public IEnumerable<XdmNode> Children(IPredicate<XdmNode> filter)
2415
        {
2416
            IEnumerable<XdmNode> enumerable = Children();
2417
            foreach (XdmNode node in enumerable)
2418
                if (filter.Func(node))
2419
                {
2420
                    yield return node;
2421
                }
2422
        }
2423
2424
		/// <summary>
2425
		/// Get the element children of this node
2426
		/// </summary>
2427
		/// <returns> an <c>Iterable</c> containing all nodes on the child axis.</returns>
2428
2429
        public IEnumerable<XdmNode> Children()
2430
        {
2431
            return new SequenceEnumerable<XdmNode>(JSequenceXdmIterator.ofNodes(((JNodeInfo)value).iterateAxis(GetAxisNumber(XdmAxis.Child))));
2432
        }
2433
2434
		/// <summary>
2435
		/// Get the element children of this node having a specified local name, irrespective of the namespace
2436
		/// </summary>
2437
		/// <param name="localName">the local name of the child elements to be selected, or "*" to select all children that are element nodes</param>
2438
		/// <returns> an <c>Iterable</c> containing the element children of this node that have the required local name.</returns>
2439
2440
        public IEnumerable<XdmNode> Children(String localName)
2441
        {
2442
            Step<XdmNode, XdmNode> localNameStep = Steps.Child(localName);
2443
            return localNameStep.Invoke(this);
2444
		}
2445
2446
		/// <summary>
2447
		/// Get the element children having a specified namespace URI and local name
2448
		/// </summary>
2449
		/// <param name="uri">the namespace URI of the child elements to be selected: 
2450
		/// supply a zero-length string to indicate the null namespace</param>
2451
		/// <param name="localName">the local name of the child elements to be selected</param>
2452
		/// <returns> an <c>Iterable</c> containing the element children of this node that have the required local name and namespace URI.</returns>
2453
2454
        public IEnumerable<XdmNode> Children(String uri, String localName)
2455
        {
2456
            return Children().SelectMany(Steps.Child(uri, localName).Func);
2457
        }
2458
2459
        /// <summary>
2460
        /// Get an enumerable that supplies all the nodes on one of the XPath
2461
        /// axes, starting with this node.
2462
        /// </summary>
2463
        /// <param name="axis">
2464
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child axis.
2465
        /// </param>
2466
        /// <remarks>
2467
        /// The nodes are returned in axis order: that is, document order for a forwards
2468
        /// axis, reverse document order for a reverse axis.
2469
        /// </remarks>
2470
2471
        public IEnumerable<XdmNode> EnumerableOverAxis(XdmAxis axis)
2472
        {
2473
            return (new SequenceEnumerable<XdmNode>(JSequenceXdmIterator.ofNodes(((JNodeInfo)value).iterateAxis(GetAxisNumber(axis)))));
2474
        }
2475
2476
2477
2478
        /// <summary>
2479
        /// Get an enumerator that supplies all the nodes on one of the XPath
2480
        /// axes, starting with this node.
2481
        /// </summary>
2482
        /// <param name="axis">
2483
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child axis.
2484
        /// </param>
2485
        /// <remarks>
2486
        /// The nodes are returned in axis order: that is, document order for a forwards
2487
        /// axis, reverse document order for a reverse axis.
2488
        /// </remarks>
2489
2490
        public IEnumerator<XdmNode> EnumerateAxis(XdmAxis axis)
2491
        {
2492
            return (new SequenceEnumerator<XdmNode>(JSequenceXdmIterator.ofNodes(((JNodeInfo)value).iterateAxis(GetAxisNumber(axis)))));
2493
        }
2494
2495
        /// <summary>
2496
        /// Get an enumerator that selects all the nodes on one of the XPath
2497
        /// axes, provided they have a given name. The nodes selected are those of the principal
2498
        /// node kind (elements for most axes, attributes for the attribute axis, namespace nodes
2499
        /// for the namespace axis) whose name matches the name given in the second argument.
2500
        /// </summary>
2501
        /// <param name="axis">
2502
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child axis.
2503
        /// </param>
2504
        /// <param name="nodeName">
2505
        /// The name of the required nodes, for example <c>new QName("", "item")</c> to select
2506
        /// nodes with local name "item", in no namespace.
2507
        /// </param>
2508
        /// <remarks>
2509
        /// The nodes are returned in axis order: that is, document order for a forwards
2510
        /// axis, reverse document order for a reverse axis.
2511
        /// </remarks>
2512
2513
        public IEnumerator<XdmNode> EnumerateAxis(XdmAxis axis, QName nodeName)
2514
        {
2515
            int kind;
2516
            switch (axis)
2517
            {
2518
                case XdmAxis.Attribute:
2519
                    kind = net.sf.saxon.type.Type.ATTRIBUTE;
2520
                    break;
2521
                case XdmAxis.Namespace:
2522
                    kind = net.sf.saxon.type.Type.NAMESPACE;
2523
                    break;
2524
                default:
2525
                    kind = net.sf.saxon.type.Type.ELEMENT;
2526
                    break;
2527
            }
2528
            JNamePool pool = ((JNodeInfo)value).getConfiguration().getNamePool();
2529
            JNameTest test = new JNameTest(kind, nodeName.Uri, nodeName.LocalName, pool);
2530
            return new SequenceEnumerator<XdmNode>(JSequenceXdmIterator.ofNodes(((JNodeInfo)value).iterateAxis(GetAxisNumber(axis), test)));
2531
        }
2532
2533
        private static byte GetAxisNumber(XdmAxis axis)
2534
        {
2535
            switch (axis)
2536
            {
2537
                case XdmAxis.Ancestor: return JAxisInfo.ANCESTOR;
2538
                case XdmAxis.AncestorOrSelf: return JAxisInfo.ANCESTOR_OR_SELF;
2539
                case XdmAxis.Attribute: return JAxisInfo.ATTRIBUTE;
2540
                case XdmAxis.Child: return JAxisInfo.CHILD;
2541
                case XdmAxis.Descendant: return JAxisInfo.DESCENDANT;
2542
                case XdmAxis.DescendantOrSelf: return JAxisInfo.DESCENDANT_OR_SELF;
2543
                case XdmAxis.Following: return JAxisInfo.FOLLOWING;
2544
                case XdmAxis.FollowingSibling: return JAxisInfo.FOLLOWING_SIBLING;
2545
                case XdmAxis.Namespace: return JAxisInfo.NAMESPACE;
2546
                case XdmAxis.Parent: return JAxisInfo.PARENT;
2547
                case XdmAxis.Preceding: return JAxisInfo.PRECEDING;
2548
                case XdmAxis.PrecedingSibling: return JAxisInfo.PRECEDING_SIBLING;
2549
                case XdmAxis.Self: return JAxisInfo.SELF;
2550
            }
2551
            return 0;
2552
        }
2553
2554
        /// <summary>
2555
        /// Get the base URI of the node.
2556
        /// </summary>
2557
2558
        public Uri BaseUri
2559
        {
2560
            get
2561
            {
2562
                string baseUriStr = ((JNodeInfo)value).getBaseURI();
2563
                if (baseUriStr == null || baseUriStr.Equals(""))
2564
                {
2565
                    return null;
2566
                }
2567
                return new Uri(baseUriStr);
2568
            }
2569
        }
2570
2571
        /// <summary>
2572
        /// Get the document URI of the node.
2573
        /// </summary>
2574
2575
        public Uri DocumentUri
2576
        {
2577
            get
2578
            {
2579
                String s = ((JNodeInfo)value).getSystemId();
2580
                if (s == null || s.Length == 0)
2581
                {
2582
                    return null;
2583
                }
2584
                return new Uri(s);
2585
            }
2586
        }
2587
2588
        /// <summary>
2589
        /// Send the node (that is, the subtree rooted at this node) to an <c>XmlWriter</c>
2590
        /// </summary>
2591
        /// <remarks>
2592
        /// Note that an <c>XmlWriter</c> can only handle a well-formed XML document. This method
2593
        /// will therefore signal an exception if the node is a document node with no children, or with
2594
        /// more than one element child.
2595
        /// </remarks>
2596
        /// <param name="writer">
2597
        /// The <c>XmlWriter</c> to which the node is to be written
2598
        /// </param>
2599
2600
        public void WriteTo(XmlWriter writer)
2601
        {
2602
            JNodeInfo node = ((JNodeInfo)value);
2603
            JDotNetReceiver receiver = new JDotNetReceiver(writer);
2604
            receiver.setPipelineConfiguration(node.getConfiguration().makePipelineConfiguration());
2605
            receiver.open();
2606
            node.copy(receiver, net.sf.saxon.om.CopyOptions.ALL_NAMESPACES, JLoc.NONE);
2607
            receiver.close();
2608
        }
2609
2610
        /// <summary>
2611
        /// Return a serialization of this node as lexical XML
2612
        /// </summary>
2613
        /// <remarks>
2614
        /// <para>In the case of an element node, the result will be a well-formed
2615
        /// XML document serialized as defined in the W3C XSLT/XQuery serialization specification,
2616
		/// using options <c>method="xml"</c>, <c>indent="yes"</c>, <c>omit-xml-declaration="yes"</c>.</para>
2617
        /// <para>In the case of a document node, the result will be a well-formed
2618
        /// XML document provided that the document node contains exactly one element child,
2619
        /// and no text node children. In other cases it will be a well-formed external
2620
        /// general parsed entity.</para>
2621
        /// <para>In the case of an attribute node, the output is a string in the form
2622
        /// <c>name="value"</c>. The name will use the original namespace prefix.</para>
2623
        /// <para>Other nodes, such as text nodes, comments, and processing instructions, are
2624
        /// represented as they would appear in lexical XML.</para>
2625
        /// </remarks>
2626
2627
        public String OuterXml
2628
        {
2629
            get
2630
            {
2631
                JNodeInfo node = ((JNodeInfo)value);
2632
2633
                if (node.getNodeKind() == JType.ATTRIBUTE)
2634
                {
2635
                    String val = node.getStringValue().Replace("\"", "&quot;");
2636
                    val = val.Replace("<", "&lt;");
2637
                    val = val.Replace("&", "&amp;");
2638
                    return node.getDisplayName() + "=\"" + val + '"';
2639
                }
2640
                else if (node.getNodeKind() == JType.NAMESPACE)
2641
                {
2642
                    String val = node.getStringValue().Replace("\"", "&quot;");
2643
                    val = val.Replace("<", "&lt;");
2644
                    val = val.Replace("&", "&amp;");
2645
                    String name = node.getDisplayName();
2646
                    name = (name.Equals("") ? "xmlns" : "xmlns:" + name);
2647
                    return name + "=\"" + val + '"';
2648
                }
2649
                return net.sf.saxon.query.QueryResult.serialize(node).Trim();
2650
2651
            }
2652
        }
2653
2654
        /// <summary>
2655
        /// Two instances of <c>XdmNode</c> are equal if they represent the same node. That is, the <c>Equals()</c>
2656
        /// method returns the same result as the XPath "is" operator.
2657
        /// </summary>
2658
        /// <param name="obj">The object node to be compared</param>
2659
2660
        public override bool Equals(object obj)
2661
        {
2662
            return obj is XdmNode && ((JNodeInfo)value).equals((JNodeInfo)((XdmNode)obj).value);
2663
        }
2664
2665
        /// <summary>
2666
		/// The hash code of a node reflects the equality relationship: if two <c>XdmNode</c> instances
2667
        /// represent the same node, then they have the same hash code
2668
        /// </summary>
2669
2670
        public override int GetHashCode()
2671
        {
2672
            return ((JNodeInfo)value).hashCode();
2673
        }
2674
2675
        /// <summary>
2676
        /// Return a string representation of the node.
2677
        /// </summary>
2678
        /// <remarks>
2679
		/// This method returns the value of the <see cref="OuterXml"/> property.
2680
		/// To get the string value of a node as defined in XPath, use the <see cref="StringValue"/> property.
2681
        /// </remarks>
2682
2683
        public override String ToString()
2684
        {
2685
            return OuterXml;
2686
        }
2687
2688
        internal void SetProcessor(Processor processor)
2689
        {
2690
            Implementation.getConfiguration().setProcessor(processor.JProcessor);
2691
        }
2692
2693
        /// <summary>
2694
        /// Escape hatch to the underlying class in the Java implementation
2695
        /// </summary>
2696
2697
        public JNodeInfo Implementation
2698
        {
2699
            get { return ((JNodeInfo)value); }
2700
        }
2701
2702
2703
    }
2704
2705
2706
2707
    /// <summary inherits="XdmValue">
2708
    /// The class <c>XdmEmptySequence</c> represents an empty sequence in the XDM Data Model.
2709
    /// </summary>
2710
    /// <remarks>
2711
    /// <para>An empty sequence <i>may</i> also be represented by an <c>XdmValue</c> whose length
2712
    /// happens to be zero. Applications should therefore not test to see whether an object
2713
    /// is an instance of this class in order to decide whether it is empty.</para>
2714
    /// <para>In interfaces that expect an <c>XdmItem</c>, an empty sequence is represented
2715
    /// by a CLI <c>null</c> value.</para> 
2716
    /// </remarks>
2717
2718
    [Serializable]
2719
    public sealed class XdmEmptySequence : XdmValue
2720
    {
2721
2722
        ///<summary>The singular instance of this class</summary>
2723
2724
        public static XdmEmptySequence INSTANCE = new XdmEmptySequence();
2725
2726
        private XdmEmptySequence()
2727
        {
2728
            this.value = JEmptySequence.getInstance();
2729
        }
2730
    }
2731
2732
2733
    /// <summary>
2734
	/// The <c>QName</c> class represents an instance of <c>xs:QName</c>, as defined in the XPath 2.0
2735
    /// data model. Internally, it has three components, a namespace URI, a local name, and
2736
    /// a prefix. The prefix is intended to be used only when converting the value back to 
2737
    /// a string.
2738
    /// </summary>
2739
    /// <remarks>
2740
	/// Note that a <c>QName</c> is not itself an <c>XdmItem</c> in this model; however it can
2741
    /// be converted to an <c>XdmAtomicValue</c>.
2742
    /// </remarks>    
2743
2744
    [Serializable]
2745
    public sealed class QName
2746
    {
2747
2748
        private JQName sqName;
2749
        //private String prefix;
2750
        //private String uri;
2751
        //private String local;
2752
        //int hashcode = -1;      // evaluated lazily
2753
2754
2755
        private static String XS = NamespaceConstant.SCHEMA;
2756
2757
        /// <summary>QName constant for the name xs:string</summary>
2758
        public static readonly QName XS_STRING = new QName(XS, "xs:string");
2759
2760
        /// <summary>QName constant for the name xs:integer</summary>
2761
        public static readonly QName XS_INTEGER = new QName(XS, "xs:integer");
2762
2763
        /// <summary>QName constant for the name xs:double</summary>
2764
        public static readonly QName XS_DOUBLE = new QName(XS, "xs:double");
2765
2766
        /// <summary>QName constant for the name xs:float</summary>
2767
        public static readonly QName XS_FLOAT = new QName(XS, "xs:float");
2768
2769
        /// <summary>QName constant for the name xs:decimal</summary>
2770
        public static readonly QName XS_DECIMAL = new QName(XS, "xs:decimal");
2771
2772
        /// <summary>QName constant for the name xs:boolean</summary>
2773
        public static readonly QName XS_BOOLEAN = new QName(XS, "xs:boolean");
2774
2775
        /// <summary>QName constant for the name xs:anyURI</summary>
2776
        public static readonly QName XS_ANYURI = new QName(XS, "xs:anyURI");
2777
2778
        /// <summary>QName constant for the name xs:QName</summary>
2779
        public static readonly QName XS_QNAME = new QName(XS, "xs:QName");
2780
2781
        /// <summary>QName constant for the name xs:untypedAtomic</summary>
2782
        public static readonly QName XS_UNTYPED_ATOMIC = new QName(XS, "xs:untypedAtomic");
2783
2784
        /// <summary>QName constant for the name xs:untypedAtomic (for backwards compatibility)</summary>
2785
        public static readonly QName XDT_UNTYPED_ATOMIC = new QName(XS, "xs:untypedAtomic");
2786
2787
        /// <summary>
2788
		/// Construct a <c>QName</c> representing a name in no namespace
2789
        /// </summary>
2790
        /// <remarks>
2791
        /// This constructor does not check that the components of the QName are
2792
        /// lexically valid.
2793
        /// </remarks>
2794
        /// <param name="local">The local part of the name
2795
        /// </param>
2796
2797
        public QName(String local)
2798
        {
2799
            // TODO: check for validity
2800
            int colon = local.IndexOf(':');
2801
            if (colon < 0)
2802
            {
2803
                sqName = new JQName("", "", local);
2804
            }
2805
            else
2806
            {
2807
2808
                throw new ArgumentException("Local name contains a colon");
2809
            }
2810
        }
2811
2812
        /// <summary>
2813
		/// Construct a <c>QName</c> using a namespace URI and a lexical representation.
2814
        /// The lexical representation may be a local name on its own, or it may 
2815
        /// be in the form <c>prefix:local-name</c>
2816
        /// </summary>
2817
        /// <remarks>
2818
        /// This constructor does not check that the components of the QName are
2819
        /// lexically valid.
2820
        /// </remarks>
2821
        /// <param name="uri">The namespace URI. Use either the string "" or null
2822
        /// for names that are not in any namespace.
2823
        /// </param>
2824
        /// <param name="lexical">Either the local part of the name, or the prefix
2825
        /// and local part in the format <c>prefix:local</c>
2826
        /// </param>
2827
2828
        public QName(String uri, String lexical)
2829
        {
2830
            // TODO: check for validity
2831
            uri = (uri == null ? "" : uri);
2832
            int colon = lexical.IndexOf(':');
2833
            if (colon < 0)
2834
            {
2835
                sqName = new JQName("", uri, lexical);
2836
            }
2837
            else
2838
            {
2839
2840
                string prefix = lexical.Substring(0, colon);
2841
                string local = lexical.Substring(colon + 1);
2842
                sqName = new JQName(prefix, uri, local);
2843
            }
2844
        }
2845
2846
        /// <summary>
2847
		/// Construct a <c>QName</c> using a namespace prefix, a namespace URI, and a local name
2848
        /// (in that order).
2849
        /// </summary>
2850
        /// <remarks>
2851
        /// This constructor does not check that the components of the QName are
2852
        /// lexically valid.
2853
        /// </remarks>
2854
        /// <param name="prefix">The prefix of the name. Use either the string ""
2855
        /// or null for names that have no prefix (that is, they are in the default
2856
        /// namespace)</param>
2857
        /// <param name="uri">The namespace URI. Use either the string "" or null
2858
        /// for names that are not in any namespace.
2859
        /// </param>
2860
        /// <param name="local">The local part of the name</param>
2861
2862
        public QName(String prefix, String uri, String local)
2863
        {
2864
            sqName = new JQName(prefix, uri, local);
2865
        }
2866
2867
        /// <summary>
2868
		/// Construct a <c>QName</c> from a lexical QName, supplying an element node whose
2869
        /// in-scope namespaces are to be used to resolve any prefix contained in the QName.
2870
        /// </summary>
2871
        /// <remarks>
2872
        /// <para>This constructor checks that the components of the QName are
2873
        /// lexically valid.</para>
2874
        /// <para>If the lexical QName has no prefix, the name is considered to be in the
2875
        /// default namespace, as defined by <c>xmlns="..."</c>.</para>
2876
        /// </remarks>
2877
        /// <param name="lexicalQName">The lexical QName, in the form <code>prefix:local</code>
2878
        /// or simply <c>local</c>.</param>
2879
        /// <param name="element">The element node whose in-scope namespaces are to be used
2880
        /// to resolve the prefix part of the lexical QName.</param>
2881
        /// <exception cref="ArgumentException">If the prefix of the lexical QName is not in scope</exception>
2882
        /// <exception cref="ArgumentException">If the lexical QName is invalid 
2883
        /// (for example, if it contains invalid characters)</exception>
2884
        /// 
2885
2886
        public QName(String lexicalQName, XdmNode element)
2887
        {
2888
            try
2889
            {
2890
                JNodeInfo node = (JNodeInfo)element.value;
2891
                sqName = new JQName(JStructuredQName.fromLexicalQName(lexicalQName, true, true, node.getAllNamespaces()));
2892
2893
            }
2894
            catch (net.sf.saxon.trans.XPathException err)
2895
            {
2896
                throw new ArgumentException(err.getMessage());
2897
            }
2898
        }
2899
2900
        /// <summary>
2901
        /// Construct a <c>QName</c> from an <c>XmlQualifiedName</c> (as defined in the
2902
        /// <c>System.Xml</c> package).
2903
        /// </summary>
2904
        /// <remarks>
2905
        /// Note that an <c>XmlQualifiedName</c> does not contain any prefix, so the result
2906
        /// will always have a prefix of ""
2907
        /// </remarks>
2908
		/// <param name="qualifiedName">The <c>XmlQualifiedName</c></param>
2909
2910
        public QName(XmlQualifiedName qualifiedName)
2911
        {
2912
            string uri = qualifiedName.Namespace;
2913
            string local = qualifiedName.Name;
2914
            string prefix = String.Empty;
2915
            sqName = new JQName(prefix, uri, prefix);
2916
        }
2917
2918
        //  internal constructor from a QNameValue
2919
2920
        internal QName(JQNameValue q)
2921
        {
2922
            sqName = new JQName(q.getPrefix(), q.getNamespaceURI(), q.getLocalName());
2923
        }
2924
2925
        //  internal constructor with JQName object as argument
2926
2927
        internal QName(JQName q)
2928
        {
2929
            sqName = q;
2930
        }
2931
2932
        /// <summary>
2933
		/// Factory method to construct a <c>QName</c> from a string containing the expanded
2934
        /// QName in Clark notation, that is, <c>{uri}local</c>
2935
        /// </summary>
2936
        /// <remarks>
2937
        /// The prefix part of the <c>QName</c> will be set to an empty string.
2938
        /// </remarks>
2939
        /// <param name="expandedName">The URI in Clark notation: <c>{uri}local</c> if the
2940
        /// name is in a namespace, or simply <c>local</c> if not.</param> 
2941
2942
        public static QName FromClarkName(String expandedName)
2943
        {
2944
            String namespaceURI;
2945
            String localName;
2946
            if (expandedName[0] == '{')
2947
            {
2948
                int closeBrace = expandedName.IndexOf('}');
2949
                if (closeBrace < 0)
2950
                {
2951
                    throw new ArgumentException("No closing '}' in Clark name");
2952
                }
2953
                namespaceURI = expandedName.Substring(1, closeBrace - 1);
2954
                if (closeBrace == expandedName.Length)
2955
                {
2956
                    throw new ArgumentException("Missing local part in Clark name");
2957
                }
2958
                localName = expandedName.Substring(closeBrace + 1);
2959
            }
2960
            else
2961
            {
2962
                namespaceURI = "";
2963
                localName = expandedName;
2964
            }
2965
2966
            return new QName("", namespaceURI, localName);
2967
        }
2968
2969
2970
        /// <summary>
2971
        /// Factory method to construct a <c>QName</c> from a string containing the expanded
2972
        /// QName in EQName notation, that is, <c>Q{uri}local</c>
2973
        /// </summary>
2974
        /// <remarks>
2975
        /// The prefix part of the <c>QName</c> will be set to an empty string.
2976
        /// </remarks>
2977
        /// <param name="expandedName">The QName in EQName notation: <c>Q{uri}local</c>. 
2978
        /// For a name in no namespace, either of the
2979
        /// forms <c>Q{}local</c> or simply <c>local</c> are accepted.</param>
2980
        /// <returns> the QName corresponding to the supplied name in EQName notation. This will always
2981
        /// have an empty prefix.</returns>
2982
2983
        public static QName FromEQName(String expandedName)
2984
        {
2985
            String namespaceURI;
2986
            String localName;
2987
            if (expandedName[0] == 'Q' && expandedName[1] == '{')
2988
            {
2989
                int closeBrace = expandedName.IndexOf('}');
2990
                if (closeBrace < 0)
2991
                {
2992
                    throw new ArgumentException("No closing '}' in EQName");
2993
                }
2994
                namespaceURI = expandedName.Substring(2, closeBrace);
2995
                if (closeBrace == expandedName.Length)
2996
                {
2997
                    throw new ArgumentException("Missing local part in EQName");
2998
                }
2999
                localName = expandedName.Substring(closeBrace + 1);
3000
            }
3001
            else
3002
            {
3003
                namespaceURI = "";
3004
                localName = expandedName;
3005
            }
3006
3007
            return new QName("", namespaceURI, localName);
3008
        }
3009
3010
        // internal method: Factory method to construct a QName from Saxon's internal <c>StructuredQName</c>
3011
        // representation.
3012
3013
        internal static QName FromStructuredQName(JStructuredQName sqn)
3014
        {
3015
            return new QName(sqn.getPrefix(), sqn.getURI(), sqn.getLocalPart());
3016
        }
3017
3018
        /// <summary>
3019
		/// Register a <c>QName</c> with the <c>Processor</c>. This makes comparison faster
3020
        /// when the QName is compared with others that are also registered with the <c>Processor</c>.
3021
        /// Depreacted method.
3022
        /// </summary>
3023
        /// <remarks>
3024
        /// A given <c>QName</c> object can only be registered with one <c>Processor</c>.
3025
        /// </remarks>
3026
		/// <param name="processor">The <c>Processor</c> in which the name is to be registered.</param>
3027
        [System.Obsolete("This method is no longer in use")]
3028
        public void Register(Processor processor)
3029
        { }
3030
3031
        /// <summary>
3032
		/// Validate the <c>QName</c> against the XML 1.0 or XML 1.1 rules for valid names.
3033
        /// </summary>
3034
        /// <param name="processor">This argument is no longer used (at one time it was used
3035
        /// to establish whether XML 1.0 or XML 1.1 rules should be used for validation, but the
3036
        /// two versions of the XML specification have since been aligned).</param>
3037
        /// <returns>true if the name is valid, false if not</returns>
3038
3039
        public bool IsValid(Processor processor)
3040
        {
3041
            return IsValid();
3042
        }
3043
3044
        /// <summary>
3045
        /// Validate the <c>QName</c> against the XML rules for valid names.
3046
        /// </summary>
3047
        /// <returns>true if the name is valid, false if not</returns>
3048
3049
        public bool IsValid()
3050
        {
3051
            if (this.Prefix != String.Empty)
3052
            {
3053
                if (!JNameChecker.isValidNCName(Prefix))
3054
                {
3055
                    return false;
3056
                }
3057
            }
3058
            if (!JNameChecker.isValidNCName(this.LocalName))
3059
            {
3060
                return false;
3061
            }
3062
            return true;
3063
        }
3064
3065
        /// <summary>Get the prefix of the <c>QName</c>. This plays no role in operations such as comparison
3066
        /// of QNames for equality, but is retained (as specified in XPath) so that a string representation
3067
        /// can be reconstructed.
3068
        /// </summary>
3069
        /// <remarks>
3070
        /// Returns the zero-length string in the case of a QName that has no prefix.
3071
        /// </remarks>
3072
3073
        public String Prefix
3074
        {
3075
            get { return sqName.getPrefix(); }
3076
        }
3077
3078
        /// <summary>Get the namespace URI of the <c>QName</c>. Returns "" (the zero-length string) if the
3079
        /// QName is not in a namespace.
3080
        /// </summary>
3081
3082
        public String Uri
3083
        {
3084
            get { return sqName.getNamespaceURI(); }
3085
        }
3086
3087
        /// <summary>Get the local part of the <c>QName</c></summary>
3088
3089
        public String LocalName
3090
        {
3091
            get { return sqName.getLocalName(); }
3092
        }
3093
3094
        /// <summary>Get the expanded name, as a string using the notation devised by James Clark.
3095
        /// If the name is in a namespace, the resulting string takes the form <c>{uri}local</c>.
3096
        /// Otherwise, the value is the local part of the name.
3097
        /// </summary>
3098
3099
        public String ClarkName
3100
        {
3101
            get
3102
            {
3103
                string uri = Uri;
3104
                if (uri.Equals(""))
3105
                {
3106
                    return LocalName;
3107
                }
3108
                else
3109
                {
3110
                    return "{" + uri + "}" + LocalName;
3111
                }
3112
            }
3113
        }
3114
3115
        /// <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>.
3116
        /// </summary>
3117
        public String EQName
3118
        {
3119
            get
3120
            {
3121
                return "Q{" + Uri + "}" + LocalName;
3122
            }
3123
        }
3124
3125
        /// <summary>
3126
        /// Convert the value to a string. The resulting string is the lexical form of the QName,
3127
        /// using the original prefix if there was one.
3128
        /// </summary>
3129
3130
        public override String ToString()
3131
        {
3132
3133
            if (Prefix.Equals(""))
3134
            {
3135
                return LocalName;
3136
            }
3137
            else
3138
            {
3139
                return Prefix + ":" + LocalName;
3140
            }
3141
        }
3142
3143
        /// <summary>
3144
		/// Get a hash code for the <c>QName</c>, to support equality matching. This supports the
3145
        /// semantics of equality, which considers only the namespace URI and local name, and
3146
        /// not the prefix.
3147
        /// </summary>
3148
        /// <remarks>
3149
        /// The algorithm for allocating a hash code does not depend on registering the QName 
3150
        /// with the <c>Processor</c>.
3151
        /// </remarks>
3152
3153
        public override int GetHashCode()
3154
        {
3155
            return sqName.hashCode();
3156
        }
3157
3158
        /// <summary>
3159
        /// Test whether two QNames are equal. This supports the
3160
        /// semantics of equality, which considers only the namespace URI and local name, and
3161
        /// not the prefix.
3162
        /// </summary>
3163
		/// <param name="other">The value to be compared with this <c>QName</c>. If this value is not a <c>QName</c>, the
3164
        /// result is always false. Otherwise, it is true if the namespace URI and local name both match.</param>
3165
3166
        public override bool Equals(Object other)
3167
        {
3168
            if (!(other is QName))
3169
            {
3170
                return false;
3171
            }
3172
            return sqName.equals(((QName)other).sqName);
3173
        }
3174
3175
        /// <summary>
3176
        /// Convert the value to an <c>XmlQualifiedName</c> (as defined in the
3177
        /// <c>System.Xml</c> package)
3178
        /// </summary>
3179
        /// <remarks>
3180
        /// Note that this loses the prefix.
3181
        /// </remarks>
3182
3183
        public XmlQualifiedName ToXmlQualifiedName()
3184
        {
3185
            return new XmlQualifiedName(LocalName, Uri);
3186
        }
3187
3188
        // internal method: Convert to a net.sf.saxon.value.QNameValue
3189
3190
        internal JQNameValue ToQNameValue()
3191
        {
3192
            return new JQNameValue(sqName.getPrefix(), sqName.getNamespaceURI(), sqName.getLocalName(), null);
3193
        }
3194
3195
        // internal method
3196
3197
        internal JStructuredQName ToStructuredQName()
3198
        {
3199
            return new JStructuredQName(Prefix, Uri, LocalName);
3200
        }
3201
3202
        // internal method
3203
3204
        internal JQName UnderlyingQName()
3205
        {
3206
            return sqName;
3207
        }
3208
3209
3210
3211
3212
    }
3213
3214
    /// <summary>
3215
	/// Interface that represents a predicate (boolean-valued <c>Func</c>) of one argument.
3216
    /// </summary>
3217
	/// <remarks>This is a functional interface whose functional method is <c>Invoke(object)</c>.</remarks>
3218
    /// <typeparam name="XdmItem">The type of the input to the predicate.</typeparam>
3219
    public interface IPredicate<in XdmItem>
3220
    {
3221
3222
        /// <summary>
3223
        /// Returns a composed predicate that represents a short-circuiting logical
3224
        /// OR of this predicate and another. When evaluating the composed
3225
        /// predicate, if this predicate is <c>true</c>, then the <c>other</c>
3226
        /// predicate is not evaluated.
3227
        /// </summary>
3228
        /// <typeparam name="T">The type of the input argument</typeparam>
3229
        /// <param name="other">A predicate that will be logically-ORed with this predicate</param>
3230
		/// <returns>A composed predicate that represents the short-circuiting logical OR of this predicate and the <c>other</c>
3231
		/// predicate.</returns>
3232
		/**public**/ IPredicate<T> Or<T>(IPredicate<T> other) where T : XdmItem;
3233
3234
        /// <summary>
3235
        /// Returns a composed predicate that represents a short-circuiting logical
3236
        /// AND of this predicate and another. When evaluating the composed
3237
        /// predicate, if this predicate is <c>false</c>, then the <c>other</c>
3238
        /// predicate is not evaluated.
3239
        /// </summary>
3240
        /// <typeparam name="T">The type of the input argument</typeparam>
3241
        /// <param name="other">A predicate that will be logically-ANDed with this predicate</param>
3242
		/// <returns>A composed predicate that represents the short-circuiting logical AND of this predicate the <c>other</c>
3243
		/// predicate.</returns>
3244
		/**public**/ IPredicate<T> And<T>(IPredicate<T> other) where T : XdmItem;
3245
3246
        /// <summary>
3247
        /// Returns a predicate that represents the logical negation of this predicate.
3248
        /// </summary>
3249
        /// <returns>A predicate that represents the logical negation of this predicate.</returns>
3250
		/**public**/ IPredicate<XdmItem> Negate();
3251
3252
        /// <summary>
3253
        /// Evaluates this predicate on the given argument.
3254
        /// </summary>
3255
        /// <typeparam name="T">The type of the input argument</typeparam>
3256
        /// <param name="item">The input item</param>
3257
        /// <returns><c>true</c> if the input argument matches the predicate, otherwise <c>false</c>.</returns>
3258
		/**public**/ bool Invoke<T>(T item) where T : XdmItem;
3259
3260
        /// <summary>
3261
        /// Unwrapped Func property which evaluates to boolean.
3262
        /// </summary>
3263
		/**public**/ Func<XdmItem, bool> Func { get; }
3264
    }
3265
3266
3267
    /// <summary>
3268
	/// This class implements the <c>IPredicate</c> interface which represents a predicate (boolean-valued <c>Func</c>) of one argument.
3269
    /// </summary>
3270
	/// <typeparam name="T">The type of the input to the predicate, which must be of type <c>XdmItem</c> or one of its subclasses.</typeparam>
3271
    public class Predicate<T> : IPredicate<T>
3272
      where T : XdmItem
3273
    {
3274
3275
        private Func<T, bool> function;
3276
3277
        /// <summary>
3278
		/// Predicate constructor method to wrap the <c>Func</c> object.
3279
        /// </summary>
3280
		/// <param name="f">boolean-valued <c>Func</c> object</param>
3281
        public Predicate(Func<T, bool> f)
3282
        {
3283
            function = f;
3284
        }
3285
3286
        /// <summary>
3287
        /// Evaluates this predicate on the given argument.
3288
        /// </summary>
3289
        /// <typeparam name="T1">The type of the input argument</typeparam>
3290
        /// <param name="item">The input item</param>
3291
        /// <returns><c>true</c> if the input argument matches the predicate, otherwise <c>false</c>.</returns>
3292
        public bool Invoke<T1>(T1 item) where T1 : T
3293
        {
3294
            return function(item);
3295
        }
3296
3297
3298
        /// <summary>
3299
        /// Returns a compose predicate that represents a short-circuiting logical
3300
        /// AND of this predicate and another. When evaluating the composed predicate,
3301
        /// if this predicate is <c>false</c>, then the other predicate is not evaluated.
3302
        /// </summary>
3303
        /// <param name="other">A predicate that will be logically-ANDed with this predicate</param>
3304
        /// <returns>A composed predicate that represents the short-circuiting logical 
3305
		/// AND of this predicate and the <c>other</c> predicate.</returns>
3306
		/**public**/ IPredicate<T1> IPredicate<T>.And<T1>(IPredicate<T1> other)
3307
        {
3308
            return new Predicate<T1>(item => function(item) && other.Func(item));
3309
        }
3310
3311
        /// <summary>
3312
        /// Returns a composed predicate that represents a short-circuiting logical
3313
        /// OR of this predicate and another. When evaluating the composed
3314
        /// predicate, if this predicate is <c>true</c>, then the <c>other</c>
3315
        /// predicate is not evaluated.
3316
        /// </summary>
3317
        /// <param name="other">A predicate that will be logically-ORed with this predicate.</param>
3318
        /// <returns>A composed predicate that represents the short-circuiting logical
3319
        /// OR of this predicate and the <c>other</c> predicate.</returns>
3320
		/**public**/ IPredicate<T1> IPredicate<T>.Or<T1>(IPredicate<T1> other)
3321
        {
3322
            return new Predicate<T1>(item => function(item) || other.Func(item));
3323
        }
3324
3325
        /// <summary>
3326
        /// Return a predicate that represents the logical negation of this predicate.
3327
        /// </summary>
3328
        /// <returns>A predicate that represents the logical negation of this predicate.</returns>
3329
		/**public**/ IPredicate<T> IPredicate<T>.Negate()
3330
        {
3331
            return new Predicate<T>(item => !function(item));
3332
        }
3333
3334
3335
        /// <summary>
3336
		/// The <c>Func</c> Property represents the wrapped delegate method which can be invoked.
3337
        /// </summary>
3338
        public Func<T, bool> Func
3339
        {
3340
            get
3341
            {
3342
                return function;
3343
            }
3344
        }
3345
3346
    }
3347
3348
3349
    /// <summary>
3350
    /// This non-instantiable class provides a number of useful implementations of the <c>Predicate</c>
3351
    /// interface, designed for use when navigating streams of XDM items.
3352
    /// </summary>
3353
    public class Predicates
3354
    {
3355
3356
        /// <summary>
3357
        /// A predicate to test whether an item is an attribute node.
3358
        /// </summary>
3359
        /// <returns>A predicate that returns true if given an item that is an attribute node.</returns>
3360
        public static IPredicate<XdmItem> IsAttribute()
3361
        {
3362
            return NodeKindPredicate(XmlNodeType.Attribute);
3363
        }
3364
3365
        /// <summary>
3366
        /// A predicate to test whether an item is a node.
3367
        /// </summary>
3368
        /// <returns>A predicate that returns true if given an item that is a node.</returns>
3369
        public static IPredicate<XdmItem> IsNode()
3370
        {
3371
            return new Predicate<XdmItem>(item => item is XdmNode);
3372
        }
3373
3374
        /// <summary>
3375
        /// A predicate to test whether an item is an element node.
3376
        /// </summary>
3377
        /// <returns>A predicate that returns true if given an item that is an element node.</returns>
3378
        public static IPredicate<XdmItem> IsElement()
3379
        {
3380
            return NodeKindPredicate(XmlNodeType.Element);
3381
        }
3382
3383
        /// <summary>
3384
        /// A predicate to test whether an item is a text node.
3385
        /// </summary>
3386
        /// <returns>A predicate that returns true if given an item that is a text node.</returns>
3387
        public static IPredicate<XdmItem> IsText()
3388
        {
3389
            return NodeKindPredicate(XmlNodeType.Text);
3390
        }
3391
3392
        /// <summary>
3393
        /// A predicate to test whether an item is a comment node.
3394
        /// </summary>
3395
        /// <returns>A predicate that returns true if given an item that is a comment node.</returns>
3396
        public static IPredicate<XdmItem> IsComment()
3397
        {
3398
            return NodeKindPredicate(XmlNodeType.Comment);
3399
        }
3400
3401
        /// <summary>
3402
        /// A predicate to test whether an item is a processing instruction node.
3403
        /// </summary>
3404
        /// <returns>A predicate that returns true if given an item that is a processing instruction node.</returns>
3405
        public static IPredicate<XdmItem> IsProcessingInstruction()
3406
        {
3407
            return NodeKindPredicate(XmlNodeType.ProcessingInstruction);
3408
        }
3409
3410
        /// <summary>
3411
        /// A predicate to test whether an item is a document node.
3412
        /// </summary>
3413
        /// <returns>A predicate that returns true if given an item that is a document node.</returns>
3414
        public static IPredicate<XdmItem> IsDocument()
3415
        {
3416
            return NodeKindPredicate(XmlNodeType.Document);
3417
        }
3418
3419
        /// <summary>
3420
        /// A predicate to test whether an item is a namespace node.
3421
        /// </summary>
3422
        /// <returns>A predicate that returns true if given an item that is a namespace node.</returns>
3423
        public static IPredicate<XdmItem> IsNamespace()
3424
        {
3425
            return NodeKindPredicate(XmlNodeType.None);
3426
        }
3427
3428
        /// <summary>
3429
        /// A predicate to test whether an item is an atomic value.
3430
        /// </summary>
3431
        /// <returns>A predicate that returns true if given an item that is an atomic value.</returns>
3432
        public static IPredicate<XdmItem> IsAtomic()
3433
        {
3434
            return new Predicate<XdmItem>(item => item is XdmAtomicValue);
3435
        }
3436
3437
        /// <summary>
3438
        /// A predicate to test whether an item is a function value (this includes maps and arrays).
3439
        /// </summary>
3440
        /// <returns>A predicate that returns true if given an item that is a function, including
3441
        /// maps and arrays.</returns>
3442
        public static IPredicate<XdmItem> IsFunction()
3443
        {
3444
3445
            return new Predicate<XdmItem>(item => item is XdmFunctionItem);
3446
3447
        }
3448
3449
3450
        /// <summary>
3451
        /// A predicate to test whether an item is an XDM map.
3452
        /// </summary>
3453
        /// <returns>A predicate that returns true if given an item that is a map.</returns>
3454
        public static IPredicate<XdmItem> IsMap()
3455
        {
3456
3457
            return new Predicate<XdmItem>(item => item is XdmMap);
3458
3459
        }
3460
3461
        /// <summary>
3462
        /// A predicate to test whether an item is an XDM array.
3463
        /// </summary>
3464
        /// <returns>A predicate that returns true if given an item that is an array.</returns>
3465
        public static IPredicate<XdmItem> IsArray()
3466
        {
3467
3468
            return new Predicate<XdmItem>(item => item is XdmArray);
3469
3470
        }
3471
3472
        /// <summary>
3473
        /// Obtain a predicate that tests whether a supplied <c>Step</c> delivers an empty result.
3474
        /// </summary>
3475
        /// <param name="step">A step to be applied to the item being tested</param>
3476
        /// <returns>A predicate that returns true if the supplied step returns an empty result.</returns>
3477
        public static IPredicate<TInput> Empty<TInput, TResult>(Step<TInput, TResult> step)
3478
            where TInput: XdmItem
3479
            where TResult: XdmItem
3480
        {
3481
            return new Predicate<TInput>(item => step.Invoke(item).Count() == 0);
3482
3483
        }
3484
3485
3486
        /// <summary>
3487
        /// Return an <c>IPredicate</c> that is the negation of a supplied <c>IPredicate</c>.
3488
        /// </summary>
3489
        /// <typeparam name="TInput">The type of object to which the predicate is applicable</typeparam>
3490
        /// <param name="condition">The supplied predicate</param>
3491
        /// <returns>A predicate that matches an item if and only if the supplied predicate does not match the item.</returns>
3492
        public static IPredicate<TInput> Not<TInput>(IPredicate<TInput> condition)
3493
            where TInput: XdmItem
3494
        {
3495
3496
            return condition.Negate();
3497
        }
3498
3499
3500
        /// <summary>
3501
        /// Obtain a predicate that tests whether a supplied <c>Step</c> delivers a non-empty result.
3502
        /// </summary>
3503
        /// <param name="step">A step to be applied to the item being tested</param>
3504
        /// <returns>A predicate that returns true if the step returns a non-empty result.</returns>
3505
        public static IPredicate<XdmItem> Exists(Step<XdmItem, XdmItem> step)
3506
        {
3507
            return new Predicate<XdmItem>(item => step.Invoke(item).Count() > 0);
3508
3509
        }
3510
3511
3512
3513
3514
        /// <summary>
3515
        /// Obtain a predicate that tests whether an item is a node with a given namespace URI and local name.
3516
        /// </summary>
3517
        /// <param name="uri">The required namespace URI: supply a zero-length string to indicate the null namespace</param>
3518
        /// <param name="localName">The required local name</param>
3519
        /// <returns>A predicate that returns true if and only if the supplied item is a node with the given namespace URI and local name.</returns>
3520
        public static IPredicate<XdmNode> HasName(String uri, String localName)
3521
        {
3522
3523
            return new Predicate<XdmNode>(item =>
3524
            {
3525
                QName name = item.NodeName;
3526
                return item != null && name.LocalName.Equals(localName) && name.Uri.Equals(uri);
3527
            });
3528
        }
3529
3530
3531
3532
        internal static IPredicate<XdmNode> ExpandedNamePredicate(String ns, String local)
3533
        {
3534
            return new Predicate<XdmNode>(item =>
3535
            {
3536
                if (!(item is XdmNode)) { return false; }
3537
                XdmNode node = (XdmNode)item;
3538
                return node.NodeKind == XmlNodeType.Element
3539
                        && node.NodeName.LocalName.Equals(local) && node.NodeName.Uri.Equals(ns);
3540
            });
3541
3542
        }
3543
3544
       internal static IPredicate<XdmNode> LocalNamePredicate(String given)
3545
        {
3546
            if ("*".Equals(given))
3547
            {
3548
                return IsElement();
3549
            }
3550
            return new Predicate<XdmNode>(item =>
3551
            {
3552
3553
                XdmNode node = (XdmNode)item;
3554
                return node.NodeKind == XmlNodeType.Element
3555
                            && node.NodeName.LocalName.Equals(given);
3556
3557
3558
            });
3559
3560
        }
3561
3562
3563
        /// <summary>
3564
        /// Obtain a predicate that tests whether an item is a node with a given local name, irrespective of the namespace.
3565
        /// </summary>
3566
        /// <param name="localName">The required local name</param>
3567
        /// <returns>A predicate that returns true if and only if the supplied item is a node with the given namespace URI and local name.</returns>
3568
        public static IPredicate<XdmNode> HasLocalName(String localName)
3569
        {
3570
3571
3572
            return new Predicate<XdmNode>(item =>
3573
            {
3574
                QName name = item.NodeName;
3575
                return name != null &&
3576
                        name.LocalName.Equals(localName);
3577
            });
3578
3579
        }
3580
3581
        /// <summary>
3582
        /// Obtain a predicate that tests whether an item is a node with a given namespace URI.
3583
        /// </summary>
3584
        /// <param name="uri">The required namespace URI: supply a zero-length string to identify the null namespace</param>
3585
        /// <returns>A predicate that returns true if and only if the supplied item is a node with the given
3586
        /// namespace URI. If a zero-length string is supplied, the predicate will also match nodes having no name,
3587
        /// such as text and comment nodes, and nodes having a local name only, such as namespace and processing-instruction
3588
        /// nodes.</returns>
3589
        public static IPredicate<XdmNode> HasNamespace(String uri)
3590
        {
3591
3592
            return new Predicate<XdmNode>(item => {
3593
                QName name = item.NodeName;
3594
                return name != null && name.Uri.Equals(uri);
3595
            });
3596
        }
3597
3598
3599
        /// <summary>
3600