Project

Profile

Help

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

he / src / main / csharp / api / Saxon.Api / Model.cs @ 2699858e

1
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
            this.value = new JBigDecimalValue(new JBigDecimal(d.ToString( System.Globalization.CultureInfo.InvariantCulture)));
967
        }
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
        /// Obtain a predicate that tests whether an item is an element node with a given attribute (whose name is in no namespace).
3601
        /// </summary>
3602
        /// <param name="local">The required attribute name</param>
3603
        /// <returns>A predicate that returns true if and only if the supplied item is an element having an attribute
3604
        /// with the given local name, in no namespace.</returns>
3605
        public static IPredicate<XdmNode> HasAttribute(String local)
3606
        {
3607

    
3608
            return new Predicate<XdmNode>(item => (item).GetAttributeValue(local) != null);
3609

    
3610
        }
3611

    
3612
        /// <summary>
3613
        /// Obtain a predicate that tests whether an item is an element node with a given attribute (whose
3614
        /// name is in no namespace) whose string value is equal to a given value.
3615
        /// </summary>
3616
        /// <param name="local">The required attribute name</param>
3617
        /// <param name="value">The required attribute value</param>
3618
        /// <returns>A predicate that returns true if and only if the supplied item is an element having an attribute
3619
        /// with the given local name, in no namespace, whose string value is equal to the given value.</returns>
3620
        public static IPredicate<XdmNode> AttributeEq(String local, String value)
3621
        {
3622

    
3623
            return new Predicate<XdmNode>(item => value.Equals(item.GetAttributeValue(local)));
3624

    
3625
        }
3626

    
3627

    
3628
        /// <summary>
3629
        /// Obtain a predicate that tests whether an atomic value compares equal to a supplied atomic value of
3630
        /// a comparable type.
3631
        /// </summary>
3632
        /// <param name="value2">The atomic value to be compared with</param>
3633
        /// <returns>A predicate which returns true when applied to a value that is equal to the supplied
3634
        /// value under the "is-same-key" comparison rules. (These are the rules used to compare key values
3635
        /// in an XDM map. The rules are chosen to be context-free, error-free, and transitive.)</returns>
3636
        public static IPredicate<XdmAtomicValue> Eq(XdmAtomicValue value2)
3637
        {
3638
            return new Predicate<XdmAtomicValue>(value1 => value1.Equals(value2));
3639
        }
3640

    
3641
        /// <summary>
3642
		/// Obtain a predicate that tests whether the result of applying the XPath <c>string()</c> function to an item
3643
        /// is equal to a given string.
3644
        /// </summary>
3645
        /// <param name="value">The string being tested</param>
3646
        /// <returns>A predicate which returns true if the string value of the item being tested
3647
        /// is equal to the given string under Java comparison rules for comparing strings.</returns>
3648
        public static IPredicate<XdmItem> Eq(string value)
3649
        {
3650
            return new Predicate<XdmItem>(item => item.GetStringValue().Equals(value));
3651
        }
3652

    
3653
        /// <summary>
3654
        /// Obtain a predicate that tests whether there is some item in the result of applying a step,
3655
        /// whose string value is equal to a given string. For example, <c>Eq(attribute("id"), "foo")</c>
3656
        /// matches an element if it has an "id" attribute whose value is "foo".
3657
        /// </summary>
3658
		/// <typeparam name="TInput">The type of the input object to the <c>Step</c> function</typeparam>
3659
        /// <typeparam name="TResult">The result type after invoking the function</typeparam>
3660
        /// <param name="step">The step to be evaluated</param>
3661
        /// <param name="value">The string to be compared against the items returned by the step</param>
3662
        /// <returns>A predicate which returns true if some item selected by the step has as string value
3663
        /// equal to the given string.</returns>
3664
        public static IPredicate<TInput> Eq<TInput, TResult>(Step<TInput, TResult> step, string value)
3665
            where TInput : XdmItem
3666
            where TResult : XdmItem
3667
        {
3668
            return Some(step, Eq(value));
3669
        }
3670

    
3671
        /// <summary>
3672
		/// Obtain a predicate that tests whether the result of applying the XPath <c>string()</c> function to an item
3673
        /// matches a given regular expression.
3674
        /// </summary>
3675
        /// <param name="regex">The regular expression (this is a Java regular expression, not an XPath regular expression)</param>
3676
        /// <returns>A predicate which returns true if the string value of the item being tested
3677
        /// contains a substring that matches the given regular expression. To test the string in its entirety,
3678
        /// use anchors "^" and "$" in the regular expression.</returns>
3679
        public static Predicate<XdmItem> MatchesRegex(String regex)
3680
        {
3681
            return new Predicate<XdmItem>(item1 =>
3682
            {
3683
                return System.Text.RegularExpressions.Regex.Match(item1.GetStringValue(), regex).Success;
3684
            });
3685
        }
3686

    
3687
        /// <summary>
3688
        /// Obtain a predicate that tests whether there is some item in the result of applying a step that
3689
        /// satisfies the supplied condition.
3690
        /// </summary>
3691
		/// <remarks><para>For example, <c>some(CHILD, exists(attribute("foo"))</c> matches an element if it has a child
3692
        /// element with an attribute whose local name is "foo".</para>
3693
        /// <para>If the step returns an empty sequence the result will always be false.</para></remarks>
3694
		/// <typeparam name="TInput">The type of the input object to the <c>Step</c> function</typeparam>
3695
        /// <typeparam name="TResult">The expected result type after invoking the function. The predicate must also be of this type.</typeparam>
3696
        /// <param name="step">The step to be evaluated</param>
3697
        /// <param name="condition">The predicate to be applied to the items returned by the step</param>
3698
		/// <returns>A predicate which returns true if some item selected by the step satisfies the supplied condition.</returns>
3699
        public static IPredicate<TInput> Some<TInput, TResult>(Step<TInput, TResult> step, IPredicate<TResult> condition)
3700
            where TInput : XdmItem
3701
            where TResult : XdmItem
3702
        {
3703
            return new Predicate<TInput>(item => step.Invoke(item).Any(condition.Func));
3704

    
3705
        }
3706

    
3707

    
3708
        /// <summary>
3709
        /// Obtain a predicate that tests whether every item in the result of applying a step
3710
        /// satisfies the supplied condition.
3711
        /// </summary>
3712
		/// <remarks> <para>For example, <c>every(CHILD, exists(attribute("foo"))</c> matches an element if each of its child
3713
        /// elements has an attribute whose local name is "foo".</para>
3714
        /// <para>If the step returns an empty sequence the result will always be true.</para></remarks>
3715
		/// <typeparam name="TInput">the type of the input object to the <c>Step</c> function</typeparam>
3716
        /// <typeparam name="TResult">The expected result type after invoking the function. The predicate must also be of this type.</typeparam>
3717
		/// <param name="step">The step to be evaluated</param>
3718
		/// <param name="condition">The predicate to be applied to the items returned by the step</param>
3719
		/// <returns>A predicate which returns true if every item selected by the step satisfies the supplied condition.</returns>
3720
        public static IPredicate<TInput> Every<TInput, TResult>(Step<TInput, TResult> step, IPredicate<TResult> condition)
3721
            where TInput : XdmItem
3722
            where TResult : XdmItem
3723
        {
3724
            return new Predicate<TInput>(item => step.Invoke(item).All(condition.Func));
3725

    
3726
        }
3727

    
3728

    
3729
        internal static IPredicate<XdmItem> NodeKindPredicate(XmlNodeType kind)
3730
        {
3731
            return new Predicate<XdmItem>(node => node.IsNode() && ((XdmNode)node).NodeKind == kind);
3732

    
3733
        }
3734

    
3735

    
3736

    
3737
    }
3738

    
3739

    
3740

    
3741

    
3742
    /// <summary>
3743
    /// A <c>Step</c> class wraps a delegate method that can be applied to an item
3744
    /// to return a <c>XdmValue</c> of items.
3745
    /// </summary>
3746
    public class Step<TInput, TResult>
3747
    where TInput : XdmItem
3748
    where TResult : XdmItem
3749
    {
3750
        private Func<TInput, IEnumerable<TResult>> function;
3751

    
3752
        /// <summary>
3753
        /// Constructor method to wrap a delegate method.
3754
        /// </summary>
3755
		/// <param name="f">Passes a delegate as a <c>Func</c> with encapsulated type <c>XdmItem</c> and the return value <c>IEnumerable</c> of items.</param>
3756
        public Step(Func<TInput, IEnumerable<TResult>> f)
3757
        {
3758
            function = f;
3759

    
3760
        }
3761

    
3762

    
3763
        /// <summary>
3764
		/// Obtain a <c>Step</c> that filters the results of this <c>Step</c> using a supplied <c>Func</c> predicate.
3765
        /// <p>For example, <c>Child.Where(Predicate.IsText())</c>
3766
        /// returns a <c>Step</c> whose effect is to select the text node children 
3767
        /// of a supplied element or document node.</p>
3768
        /// </summary>
3769
		/// <param name="predicate">The predicate is a <c>Func</c> delegate enapsulating the filter which will be applied to the results of this <c>Step</c></param>
3770
        /// <returns>A new <c>Step</c> (that is, a wrapped delegate from one <c>Step</c> of items to another) that
3771
        /// filters the results of this step by selecting only the items that satisfy the predicate.</returns>
3772
        public Step<TInput, TResult> Where(IPredicate<TResult> predicate)
3773
        {
3774
            return new Step<TInput, TResult>(item => {
3775
                return function.Invoke(item).Where(predicate.Func);
3776
            });
3777
        }
3778

    
3779

    
3780
        /// <summary>
3781
		/// Obtain a <c>Step</c> that combines the results of this step with the results of another step.
3782
        /// </summary>
3783
        /// <param name="next">The step which will be applied to the results of this step</param>
3784
		/// <returns>A new <c>Step</c> (that is, a function from one <c>IEnumerable</c> of items to another) that
3785
		/// performs this step and the next step in turn. The result is equivalent to the <c>IEnumerable</c> method <c>SelectMany()</c>
3786
        /// function or the XPath <c>!</c> operator: there is no sorting of nodes into document order, and
3787
        /// no elimination of duplicates.</returns>
3788
        public Step<TInput, TResult> Then(Step<TResult, TResult> next)
3789
        {
3790

    
3791
            return new Step<TInput, TResult>(item => { return function.Invoke(item).SelectMany(next.Func); });
3792
        }
3793

    
3794
        /// <summary>
3795
		/// Obtain a <c>Step</c> that selects the Nth item in the results of this step.
3796
        /// </summary>
3797
        /// <param name="index">The zero-based index of the item to be selected</param>
3798
		/// <returns>A new <c>Step</c> (that is, a function from one <c>IEnumerable</c> of items to another) that
3799
        /// filters the results of this step by selecting only the items that satisfy the predicate.</returns>
3800
        public Step<TInput, TResult> At(int index)
3801
        {
3802

    
3803
            return new Step<TInput, TResult>(item => {
3804
                List<TResult> list = new List<TResult>(1);
3805
                list.Add(function.Invoke(item).ElementAt(index));
3806
                return list;
3807
            });
3808
        }
3809

    
3810

    
3811
        /// <summary>
3812
		/// Obtain a <c>Step</c> that concatenates the results of this <c>Step</c> with the result of another
3813
		/// <c>Step</c> applied to the same input item.
3814
        /// </summary>
3815
        /// <remarks><p>For example, <c>Attribute().Cat(Child())</c> returns a step whose effect is
3816
		/// to select the attributes of a supplied element followed by its children.</p></remarks>
3817
        /// <param name="other">The step whose results will be concatenated with the results of this step</param>
3818
		/// <returns>A new <c>Step</c> (that is, a function from one <c>IEnumerable</c> of items to another) that
3819
        /// concatenates the results of applying this step to the input item, followed by the
3820
        /// results of applying the other step to the input item.</returns>
3821
        public Step<TInput, TResult> Cat(Step<TInput, TResult> other)
3822
        {
3823

    
3824
            return new Step<TInput, TResult>(item => {
3825
                return function.Invoke(item).Concat(other.Invoke(item));
3826
            });
3827
        }
3828

    
3829

    
3830
        /// <summary>
3831
		/// The <c>Func</c> property that represents the wrapped delegate method which can be invoked.
3832
        /// </summary>
3833
        public Func<TInput, IEnumerable<TResult>> Func
3834
        {
3835
            get
3836
            {
3837
                return function;
3838
            }
3839
        }
3840

    
3841

    
3842
        /// <summary>
3843
        /// Invokes this function to the given argument.
3844
        /// </summary>
3845
        /// <param name="item">The function argument</param>
3846
        /// <returns>The function result.</returns>
3847
        public IEnumerable<TResult> Invoke(TInput item)
3848
        {
3849
            return function.Invoke(item);
3850
        }
3851

    
3852

    
3853
    }
3854

    
3855

    
3856
    /// <summary>
3857
    /// This non-instantiable class provides a number of useful implementations of the <c>Step</c>
3858
	/// class which wraps a <c>Func</c> object, used to navigate XDM trees, typically getting the <c>Func</c> property 
3859
    /// and used as an argument to <c>XdmValue#Select</c> and <c>XdmValue#SelectMany</c>.
3860
    /// </summary>
3861
    public class Steps
3862
    {
3863

    
3864

    
3865

    
3866
        /// <summary>
3867
        /// Obtain a <c>Step</c> that selects the root node of the containing document (which may or may not
3868
        /// be a document node). If not a node a wrapped empty sequence is returned.
3869
        /// </summary>
3870
		/// <returns>A <c>Step</c> that selects the root node of the containing document.</returns>
3871
        public static Step<XdmNode, XdmNode> Root()
3872
        {
3873
            return new Step<XdmNode, XdmNode>(origin =>
3874
            { IList<XdmNode> list = new List<XdmNode>(1);
3875
                list.Add(origin.Root);
3876
                return list;
3877

    
3878
            });
3879

    
3880
        }
3881

    
3882
        internal static Step<XdmNode, XdmNode> AxisStep(XdmAxis axis)
3883
        {
3884
            return new Step<XdmNode, XdmNode>(item => {
3885
                return item.EnumerableOverAxis(axis);
3886

    
3887

    
3888
            });
3889

    
3890

    
3891
		}
3892

    
3893

    
3894
		/// <summary>
3895
		/// Obtain a <c>Step</c> to navigate from a node to its ancestors, in reverse document
3896
		/// order (that is, nearest ancestor first, root node last).
3897
		/// </summary>
3898
		/// <returns>A <c>Step</c> that selects all nodes on the ancestor axis.</returns>
3899
		public static Step<XdmNode, XdmNode> Ancestor()
3900
		{
3901
			return AxisStep(XdmAxis.Ancestor);
3902
		}
3903

    
3904

    
3905
		/// <summary>
3906
		/// Obtain a <c>Step</c> that navigates from a node to its ancestor elements having a specified
3907
		/// local name, irrespective of the namespace. The nodes are returned in reverse document
3908
		/// order (that is, nearest ancestor first, root node last).
3909
		/// </summary>
3910
		/// <param name="localName">The local name of the ancestors to be selected by the <c>Step</c>,
3911
		/// or "*" to select all ancestors that are element nodes</param>
3912
		/// <returns>A <c>Step</c>, which selects the ancestors of a supplied node that have the
3913
		/// required local name.</returns>
3914
		public static Step<XdmNode, XdmNode> Ancestor(String localName)
3915
		{
3916
			return Ancestor().Where(Predicates.HasLocalName(localName));
3917
		}
3918

    
3919

    
3920
		/// <summary>
3921
		/// Return a <c>Step</c> that navigates from a node to its ancestors having a specified
3922
		/// namespace URI and local name, in reverse document order (that is, nearest ancestor first,
3923
		/// root node last).
3924
		/// </summary>
3925
		/// <param name="uri">The namespace URI of the ancestors to be selected by the <c>Step</c></param>
3926
		/// <param name="localName">The local name of the ancestors to be selected by the <c>Step</c></param>
3927
		/// <returns>A <c>Step</c>, which selects the ancestors (at most one) of a supplied node that have the
3928
		/// required local name and namespace URI.</returns>
3929
		public static Step<XdmNode, XdmNode> Ancestor(String uri, String localName)
3930
		{
3931
			return Ancestor().Where(Predicates.HasName(uri, localName));
3932
		}
3933

    
3934

    
3935
		/// <summary>
3936
		/// Obtain a <c>Step</c> that filters the nodes found on the ancestor axis using a supplied <c>Predicate</c>.
3937
		/// Nodes are returned in reverse document order (that is, nearest ancestor first, root node last).
3938
		/// </summary>
3939
		/// <remarks>The function call <c>Ancestor(predicate)</c> is equivalent to <c>Ancestor.Where(predicate)</c>.</remarks>
3940
		/// <param name="filter">The predicate to be applied</param>
3941
		/// <returns>A <c>Step</c> that filters the nodes found on the ancestor-or-self axis using the supplied predicate.</returns>
3942
		public static Step<XdmNode, XdmNode> Ancestor(Predicate<XdmItem> filter)
3943
		{
3944
			return Ancestor().Where(filter);
3945
		}
3946

    
3947
		/// <summary>
3948
		/// Obtain a <c>Step</c> to navigate from a node to its ancestors, in reverse document
3949
		/// order, with the node itself returned at the start of the sequence (that is, origin node first,
3950
		/// root node last).
3951
		/// </summary>
3952
		/// <returns>A <c>Step</c> that selects all nodes on the ancestor-or-self axis.</returns>
3953
		public static Step<XdmNode, XdmNode> AncestorOrSelf()
3954
		{
3955
			return AxisStep(XdmAxis.AncestorOrSelf);
3956
		}
3957

    
3958

    
3959
		/// <summary>
3960
		/// Obtain a <c>Step</c> that navigates from a node to its ancestor elements having a specified
3961
		/// local name, irrespective of the namespace. The nodes are returned in reverse document
3962
		/// order (that is, nearest ancestor first, root node last), and include the node itself.
3963
		/// </summary>
3964
		/// <param name="localName">The local name of the ancestors to be selected by the <c>Step</c>,
3965
		/// or "*" to select all ancestor-or-self nodes that are element nodes</param>
3966
		/// <returns>A <c>Step</c>, which selects the ancestors-or-self of a supplied node that have 
3967
		/// the required local name.</returns>
3968
		public static Step<XdmNode, XdmNode> AncestorOrSelf(String localName)
3969
		{
3970
			return AncestorOrSelf().Where(Predicates.HasLocalName(localName));
3971
		}
3972

    
3973

    
3974
		/// <summary>
3975
		/// Obtain a <c>Step</c> that navigates from a node to its ancestors-or-self having a specified
3976
		/// namespace URI and local name, in reverse document order (that is, nearest ancestor first, root node last).
3977
		/// </summary>
3978
		/// <param name="uri">The namespace URI of the ancestors to be selected by the <c>Step</c>:
3979
		/// supply a zero-length string to indicate the null namespace</param>
3980
		/// <param name="localName">The local name of the ancestors to be selected by the <c>Step</c></param>
3981
		/// <returns>A <c>Step</c>, which selects the ancestors-or-self of a supplied node that have the
3982
		/// required local name and namespace URI.</returns>
3983
		public static Step<XdmNode, XdmNode> AncestorOrSelf(String uri, String localName)
3984
		{
3985
			return Ancestor().Where(Predicates.HasName(uri, localName));
3986
		}
3987

    
3988

    
3989
		/// <summary>
3990
		/// Obtain a <c>Step</c> that filters the nodes found on the ancestor-or-self axis using a supplied <c>Predicate</c>.
3991
		/// Nodes are returned in reverse document order (that is, origin node first, root node last).
3992
		/// </summary>
3993
		/// <remarks>The function call <c>AncestorOrSelf(predicate)</c> is equivalent to <c>AncestorOrSelf.Where(predicate)</c>.</remarks>
3994
		/// <param name="filter">The predicate to be applied</param>
3995
		/// <returns>A <c>Step</c> that filters the nodes found on the ancestor-or-self axis using a supplied predicate.</returns>
3996
		public static Step<XdmNode, XdmNode> AncestorOrSelf(Predicate<XdmItem> filter)
3997
		{
3998
			return AncestorOrSelf().Where(filter);
3999
		}
4000

    
4001

    
4002
        /// <summary>
4003
        /// Obtain a <c>Step</c> to navigate from a node to its attributes.
4004
        /// </summary>
4005
		/// <returns>A <c>Step</c> that selects all attribute nodes.</returns>
4006
        public static Step<XdmNode, XdmNode> Attribute()
4007
        {
4008
            return AxisStep(XdmAxis.Attribute);
4009
        }
4010

    
4011

    
4012
        /// <summary>
4013
        /// Obtain a <c>Step</c> that navigates from a node to its attributes having a specified
4014
        /// local name, irrespective of the namespace.
4015
        /// </summary>
4016
        /// <param name="localName">The local name of the attributes to be selected by the <c>Step</c>, or
4017
        /// "*" to select all attributes</param>
4018
        /// <returns>A <c>Step</c>, which selects the attributes of a supplied node that have the
4019
        /// required local name.</returns>
4020
        public static Step<XdmNode, XdmNode> Attribute(String localName)
4021
        {
4022
            if (localName.Equals("*"))
4023
            {
4024
                return AxisStep(XdmAxis.Attribute);
4025
            }
4026
            else
4027
            {
4028
                return AxisStep(XdmAxis.Attribute).Where(Predicates.HasLocalName(localName));
4029
            }
4030
        }
4031

    
4032

    
4033
        /// <summary>
4034
        /// Return a <c>Step</c> that navigates from a node to its attribute having a specified
4035
        /// namespace URI and local name.
4036
        /// </summary>
4037
        /// <param name="uri">The namespace URI of the attributes to be selected by the <c>Step</c>:
4038
        /// supply a zero-length string to indicate the null namespace</param>
4039
        /// <param name="localName">The local name of the attributes to be selected by the <c>Step</c></param>
4040
        /// <returns>A <c>Step</c>, which selects the attributes (at most one) of a supplied node that have the
4041
        /// required local name and namespace URI.</returns>
4042
        public static Step<XdmNode, XdmNode> Attribute(String uri, String localName)
4043
        {
4044
            return AxisStep(XdmAxis.Attribute).Where(Predicates.HasName(uri, localName));
4045

    
4046
        }
4047

    
4048

    
4049
        /// <summary>
4050
        /// Obtain a <c>Step</c> that filters the nodes found on the attribute axis using a supplied <c>Predicate</c>.
4051
        /// The function call <c>Attribute(predicate)</c> is equivalent to <c>Attribute.Where(predicate)</c>.
4052
        /// </summary>
4053
		/// <param name="filter">The predicate to be applied</param>
4054
		/// <returns>A <c>Step</c> that filters the nodes found on the attribute axis using the supplied predicate.</returns>
4055
        public static Step<XdmNode, XdmNode> Attribute(IPredicate<XdmNode> filter)
4056
        {
4057
            return AxisStep(XdmAxis.Attribute).Where(filter);
4058

    
4059
        }
4060

    
4061
        /// <summary>
4062
        /// Obtain a <c>Step</c> to navigate from a node to its children
4063
        /// </summary>
4064
		/// <returns>A <c>Step</c> that selects all nodes on the child axis</returns>
4065
        public static Step<XdmNode, XdmNode> Child()
4066
        {
4067
            return AxisStep(XdmAxis.Child);
4068
        }
4069

    
4070

    
4071
        /// <summary>
4072
        /// Obtain a <c>Step</c> that navigates from a node to the element children having a specified
4073
        /// local name, irrespective of the namespace.
4074
        /// </summary>
4075
		/// <param name="localName">The local name of the child elements to be selected by the <c>Step</c>,
4076
        /// or "*" to select all children that are element nodes</param>
4077
        /// <returns>A <c>Step</c>, which selects the element children of a supplied node that have the required local name.</returns>
4078
        public static Step<XdmNode, XdmNode> Child(String localName)
4079
        {
4080
            return AxisStep(XdmAxis.Child).Where(Predicates.LocalNamePredicate(localName));
4081
        }
4082

    
4083
        /// <summary>
4084
        /// Obtain a <c>Step</c> that navigates from a node to the element children having a specified
4085
        /// namespace URI and local name.
4086
        /// </summary>
4087
        /// <param name="uri">The namespace URI of the child elements to be selected by the <c>Step</c>:
4088
        /// supply a zero-length string to indicate the null namespace</param>
4089
        /// <param name="localName">The local name of the child elements to be selected by the <c>Step</c></param>
4090
        /// <returns>A <c>Step</c>, which selects the element children of a supplied node that have the
4091
        /// required local name and namespace URI.</returns>
4092
        public static Step<XdmNode, XdmNode> Child(String uri, String localName)
4093
        {
4094
            return AxisStep(XdmAxis.Child).Where(Predicates.ExpandedNamePredicate(uri, localName));
4095
		}
4096

    
4097
		/// <summary>
4098
		/// Obtain a <c>Step</c> that filters the nodes found on the child axis using a supplied <c>Predicate</c>.
4099
		/// The function call <c>Child(predicate)</c> is equivalent to <c>Child.Where(predicate)</c>.
4100
		/// For example, <c>Child(IsElement())</c> returns a <c>Step</c> that selects the element node children
4101
		/// of a given node.
4102
		/// </summary>
4103
		/// <param name="filter">The predicate to be applied</param>
4104
		/// <returns>A <c>Step</c> that filters the nodes found on the child axis using the supplied predicate.</returns>
4105
		public static Step<XdmNode, XdmNode> Child(IPredicate<XdmNode> filter)
4106
		{
4107
			return AxisStep(XdmAxis.Child).Where(filter);
4108
		}
4109

    
4110

    
4111
		/// <summary>
4112
		/// Obtain a <c>Step</c> to navigate from a node to its descendants, which are returned in document order.
4113
		/// </summary>
4114
		/// <returns>A <c>Step</c> that selects all nodes on the descendant axis.</returns>
4115
		public static Step<XdmNode, XdmNode> Descendant()
4116
		{
4117
			return AxisStep(XdmAxis.Descendant);
4118
		}
4119

    
4120
		/// <summary>
4121
		/// Obtain a <c>Step</c> that navigates from a node to the descendant elements having a specified
4122
		/// local name, irrespective of the namespace. These are returned in document order.
4123
		/// </summary>
4124
		/// <param name="localname">The local name of the descendant elements to be selected by the <c>Step</c>,
4125
		/// or "*" to select all descendants that are element nodes</param>
4126
		/// <returns>A <c>Step</c>, which selects the element descendants of a supplied node that have the
4127
		/// required local name.</returns>
4128
		public static Step<XdmNode, XdmNode> Descendant(String localname)
4129
		{
4130

    
4131
			return Descendant().Where(Predicates.HasLocalName(localname));
4132

    
4133
		}
4134

    
4135
		/// <summary>
4136
		/// Obtain a <c>Step</c> that navigates from a node to the descendant elements having a specified
4137
		/// namespace URI and local name.
4138
		/// </summary>
4139
		/// <param name="uri">The namespace URI of the elements to be selected by the <c>Step</c>:
4140
		/// supply a zero-length string to indicate the null namespace</param>
4141
		/// <param name="localName">The local name of the elements to be selected by the <c>Step</c></param>
4142
		/// <returns>A <c>Step</c>, which selects the element descendants of a supplied node that have the required
4143
		/// local name and namespace URI.</returns>
4144
		public static Step<XdmNode, XdmNode> Descendant(String uri, String localName)
4145
		{
4146
			return Descendant().Where(Predicates.HasName(uri, localName));
4147
		}
4148

    
4149
		/// <summary>
4150
		/// Obtain a <c>Step</c> that filters the nodes found on the descendant axis using a supplied <c>Predicate</c>.
4151
		/// The function call <c>Descendant(predicate)</c> is equivalent to <c>Descendant.Where(predicate)</c>.
4152
		/// For example, <c>Steps.Descendant(Predicates.IsElement())</c>
4153
		/// returns a <c>Step</c> that selects the element node descendants
4154
		/// of a given node, while <c>Descendant(Predicate.Exists(attribute("id")))</c> selects those that have an attribute
4155
		/// named "id". These are returned in document order.
4156
		/// </summary>
4157
		/// <param name="filter">The predicate to be applied</param>
4158
		/// <returns>A <c>Step</c> that filters the nodes found on the descendant axis using the supplied predicate.</returns>
4159
		public static Step<XdmNode, XdmNode> Descendant(IPredicate<XdmNode> filter)
4160
		{
4161
			return Descendant().Where(filter);
4162
		}
4163

    
4164

    
4165
        /// <summary>
4166
        /// Obtain a <c>Step</c> to navigate from a node to its descendants, which are returned in document order,
4167
        /// preceded by the origin node itself.
4168
        /// </summary>
4169
		/// <returns>A <c>Step</c> that selects all nodes on the descendant-or-self axis.</returns>
4170
        public static Step<XdmNode, XdmNode> DescendantOrSelf()
4171
        {
4172
            return AxisStep(XdmAxis.DescendantOrSelf);
4173
		}
4174

    
4175
		/// <summary>
4176
		/// Obtain a <c>Step</c> that navigates from a node to the descendant-or-self elements having a specified
4177
		/// local name, irrespective of the namespace. These are returned in document order.
4178
		/// </summary>
4179
		/// <param name="localname">The local name of the descendant-or-self elements to be selected by the <c>Step</c>,
4180
		/// or "*" to select all descendant-or-self that are element nodes</param>
4181
		/// <returns>A <c>Step</c>, which selects the descendant-or-self elements of a supplied node that have the
4182
		/// required local name.</returns>
4183
		public static Step<XdmNode, XdmNode> DescendantOrSelf(String localname)
4184
		{
4185

    
4186
			return DescendantOrSelf().Where(Predicates.HasLocalName(localname));
4187

    
4188
		}
4189

    
4190
		/// <summary>
4191
		/// Obtain a <c>Step</c> that navigates from a node to the descendant-or-self elements having a specified
4192
		/// namespace URI and local name.
4193
		/// </summary>
4194
		/// <param name="uri">The namespace URI of the elements to be selected by the <c>Step</c>:
4195
		/// supply a zero-length string to indicate the null namespace</param>
4196
		/// <param name="localName">The local name of the elements to be selected by the <c>Step</c></param>
4197
		/// <returns>A <c>Step</c>, which selects the descendant-or-self elements of a supplied node that have the required
4198
		/// local name and namespace URI.</returns>
4199
		public static Step<XdmNode, XdmNode> DescendantOrSelf(String uri, String localName)
4200
		{
4201
			return DescendantOrSelf().Where(Predicates.HasName(uri, localName));
4202
		}
4203

    
4204
		/// <summary>
4205
		/// Obtain a <c>Step</c> that filters the nodes found on the descendant-or-self axis using a supplied <c>Predicate</c>.
4206
		/// The function call <c>DescendantOrSelf(predicate)</c> is equivalent to <c>DescendantOrSelf.Where(predicate)</c>.
4207
		/// For example, <c>Steps.DescendantOrSelf(Predicates.IsElement())</c>
4208
		/// returns a <c>Step</c> that selects the descendant-or-self element nodes
4209
		/// of a given node, while <c>DescendantOrSelf(Predicate.Exists(attribute("id")))</c> selects those that have an attribute
4210
		/// named "id". These are returned in document order.
4211
		/// </summary>
4212
		/// <param name="filter">The predicate to be applied</param>
4213
		/// <returns>A <c>Step</c> that filters the nodes found on the descendant-or-self axis using the supplied predicate.</returns>
4214
		public static Step<XdmNode, XdmNode> DescendantOrSelf(IPredicate<XdmNode> filter)
4215
		{
4216
			return DescendantOrSelf().Where(filter);
4217
		}
4218

    
4219

    
4220
        /// <summary>
4221
        /// Obtain a <c>Step</c> to navigate from a node to its following nodes
4222
        /// (excluding descendants), which are returned in document order.
4223
        /// </summary>
4224
		/// <returns>A <c>Step</c> that selects all nodes on the following axis.</returns>
4225
        public static Step<XdmNode, XdmNode> Following()
4226
        {
4227
            return AxisStep(XdmAxis.Following);
4228
        }
4229

    
4230

    
4231
        /// <summary>
4232
        /// Obtain a <c>Step</c> that navigates from a node to the following elements having a specified
4233
        /// local name, irrespective of the namespace. These are returned in document order.
4234
        /// </summary>
4235
        /// <param name="localName">The local name of the following elements to be selected by the <c>Step</c>,
4236
        /// or "*" to select all following nodes that are elements</param>
4237
        /// <returns>A <c>Step</c>, which selects the following elements of a supplied node that have the
4238
        /// required local name.</returns>
4239
        public static Step<XdmNode, XdmNode> Following(String localName)
4240
        {
4241
            return AxisStep(XdmAxis.Following).Where(Predicates.HasLocalName(localName));
4242
        }
4243

    
4244

    
4245
        /// <summary>
4246
        /// Obtain a <c>Step</c> that navigates from a node to the following elements having a specified
4247
        /// namespace URI and local name. These are returned in document order.
4248
        /// </summary>
4249
        /// <param name="uri">The namespace URI of the following elements to be selected by the <c>Step</c>:
4250
        /// supply a zero-length string to indicate the null namespace</param>
4251
        /// <param name="localName">The local name of the following elements to be selected by the <c>Step</c></param>
4252
        /// <returns>A <c>Step</c>, which selects the following elements of a supplied node that have the
4253
        /// required local name and namespace URI.</returns>
4254
        public static Step<XdmNode, XdmNode> Following(String uri, String localName)
4255
        {
4256
            return AxisStep(XdmAxis.Following).Where(Predicates.HasName(uri, localName));
4257
        }
4258

    
4259

    
4260
        /// <summary>
4261
		/// Obtain a <c>Step</c> that filters the nodes found on the following axis using a supplied <c>Predicate</c>.
4262
        /// The function call <c>Following(predicate)</c> is equivalent to <c>Following().Where(predicate)</c>.
4263
        /// For example, <c>Following(IsElement())</c> returns a <c>Step</c> that selects the following elements
4264
        /// of a given node, while <c>Following(Exists(Attribute("id")))</c> selects those that have an attribute
4265
        /// named "id". These are returned in document order.
4266
        /// </summary>
4267
		/// <param name="filter">The predicate to be applied</param>
4268
		/// <returns>A <c>Step</c> that filters the nodes found on the following axis using the supplied predicate.</returns>
4269
        public static Step<XdmNode, XdmNode> Following(Predicate<XdmItem> filter)
4270
        {
4271
            return AxisStep(XdmAxis.Following).Where(filter);
4272
        }
4273

    
4274
        /// <summary>
4275
        /// Obtain a <c>Step</c> to navigate from a node to its following siblings, which are returned in document order.
4276
        /// </summary>
4277
		/// <returns>A <c>Step</c> that selects all nodes on the following-sibling axis.</returns>
4278
        public static Step<XdmNode, XdmNode> FollowingSibling()
4279
        {
4280
            return AxisStep(XdmAxis.FollowingSibling);
4281
        }
4282

    
4283
        /// <summary>
4284
        ///  Obtain a <c>Step</c> that navigates from a node to the following sibling elements having a specified
4285
        ///  local name, irrespective of the namespace. These are returned in document order.
4286
        /// </summary>
4287
        /// <param name="localName">The local name of the following sibling elements to be selected by the <c>Step</c>,
4288
        /// or "*" to select all following siblings that are element nodes</param>
4289
        /// <returns>A <c>Step</c>, which selects the following sibling elements of a supplied node that have the
4290
        /// required local name.</returns>
4291
        public static Step<XdmNode, XdmNode> FollowingSibling(String localName)
4292
        {
4293
            return AxisStep(XdmAxis.FollowingSibling).Where(Predicates.HasLocalName(localName));
4294
        }
4295

    
4296

    
4297
        /// <summary>
4298
        /// Obtain a <c>Step</c> that navigates from a node to the following sibling elements having a specified
4299
        /// namespace URI and local name. These are returned in document order.
4300
        /// </summary>
4301
        /// <param name="uri">The namespace URI of the following sibling elements to be selected by the <c>Step</c>:
4302
        /// supply a zero-length string to indicate the null namespace</param>
4303
        /// <param name="localName">The local name of the following sibling elements to be selected by the <c>Step</c></param>
4304
        /// <returns>A <c>Step</c>, which selects the following sibling elements of a supplied node that have the
4305
        /// required local name and namespace URI.</returns>
4306
        public static Step<XdmNode, XdmNode> FollowingSibling(String uri, String localName)
4307
        {
4308
            return AxisStep(XdmAxis.FollowingSibling).Where(Predicates.HasName(uri, localName));
4309
		}
4310

    
4311
		/// <summary>
4312
		/// Obtain a <c>Step</c> that filters the nodes found on the following sibling axis using a supplied <c>Predicate</c>.
4313
		/// The function call <c>FollowingSibling(predicate)</c> is equivalent to <c>FollowingSibling.Where(predicate)</c>.
4314
		/// For example, <c>FollowingSibling(IsElement())</c> returns a <c>Step</c> that selects the following sibling 
4315
		/// elements of a given node, while <c>FollowingSibling(Exists(Attribute("id")))</c> 
4316
		/// selects those that have an attribute named "id". These are returned in document order.
4317
		/// </summary>
4318
		/// <param name="filter">The predicate to be applied</param>
4319
		/// <returns>A <c>Step</c> that filters the nodes found on the following sibling axis using the supplied predicate.</returns>
4320
		public static Step<XdmNode, XdmNode> FollowingSibling(Predicate<XdmItem> filter)
4321
		{
4322
			return AxisStep(XdmAxis.FollowingSibling).Where(filter);
4323
		}
4324

    
4325

    
4326
        /// <summary>
4327
		/// Obtain a <c>Step</c> to navigate from a node to its namespace nodes.
4328
        /// </summary>
4329
		/// <returns>A <c>Step</c> that selects all nodes on the namespace axis.</returns>
4330
        public static Step<XdmNode, XdmNode> Namespace()
4331
        {
4332
            return AxisStep(XdmAxis.Namespace);
4333
        }
4334

    
4335
        /// <summary>
4336
        /// Obtain a <c>Step</c> that navigates from a node to its namespaces having a specified
4337
        /// local name. The local name of a namespace node corresponds to the prefix used in the
4338
        /// namespace binding.
4339
        /// </summary>
4340
        /// <param name="localName">The local name (representing the namespace prefix) of the namespace nodes
4341
        /// to be selected by the <c>Step</c>, or "*" to select all namespaces</param>
4342
        /// <returns>A <c>Step</c>, which selects the namespaces of a supplied node that have a
4343
        /// given local name (prefix).</returns>
4344
        public static Step<XdmNode, XdmNode> Namespace(String localName)
4345
        {
4346
            if (localName.Equals("*"))
4347
            {
4348
                return AxisStep(XdmAxis.Namespace);
4349
            }
4350
            else
4351
            {
4352
                return AxisStep(XdmAxis.Namespace).Where(Predicates.HasLocalName(localName));
4353
            }
4354
        }
4355

    
4356

    
4357
        /// <summary>
4358
        /// Obtain a <c>Step</c> that filters the nodes found on the namespace axis using a supplied <c>Predicate</c>.
4359
        /// The function call <c>Namespace(predicate)</c> is equivalent to <c>Namespace().Where(predicate)</c>.
4360
        /// For example, <c>Namespace(Eq("http://www.w3.org/1999/XSL/Transform")</c>
4361
        /// selects a namespace node that binds a prefix to the XSLT namespace.
4362
        /// </summary>
4363
        /// <param name="filter">The predicate to be applied</param>
4364
        /// <returns>A <c>Step</c> that filters the nodes found on the namespace axis using the supplied predicate.</returns>
4365
        public static Step<XdmNode, XdmNode> Namespace(Predicate<XdmItem> filter)
4366
        {
4367
            return AxisStep(XdmAxis.Namespace).Where(filter);
4368
        }
4369

    
4370

    
4371
        /// <summary>
4372
        /// Obtain a <c>Step</c> to navigate from a node to its parent.
4373
        /// </summary>
4374
        /// <returns>A <c>Step</c> that selects all nodes on the parent axis (of which there is at most one).</returns>
4375
        public static Step<XdmNode, XdmNode> Parent()
4376
        {
4377
            return AxisStep(XdmAxis.Parent);
4378
        }
4379

    
4380
        /// <summary>
4381
        /// Obtain a <c>Step</c> that navigates from a node to the parent element provided it has a specified
4382
        /// local name, irrespective of the namespace.
4383
        /// </summary>
4384
        /// <param name="localName">The local name of the parent element to be selected by the <c>Step</c>,
4385
        ///  or "*" to select the parent node provided it is an element</param>
4386
        /// <returns>A <c>Step</c>, which selects the parent of a supplied node provided it is an element with the
4387
        /// required local name.</returns>
4388
        public static Step<XdmNode, XdmNode> Parent(String localName)
4389
        {
4390
            return AxisStep(XdmAxis.Parent).Where(Predicates.HasLocalName(localName));
4391
        }
4392

    
4393

    
4394
        /// <summary>
4395
        /// Obtain a <c>Step</c> that navigates from a node to the parent element provided it has a specified
4396
        /// namespace URI and local name.
4397
        /// </summary>
4398
        /// <param name="uri">The namespace URI of the parent element to be selected by the <c>Step</c>:
4399
        /// supply a zero-length string to indicate the null namespace</param>
4400
        /// <param name="localName">The local name of the parent element to be selected by the <c>Step</c></param>
4401
		/// <returns>A <c>Step</c>, which selects the parent element of a supplied node provided it is an 
4402
		/// element with the required local name and namespace URI.</returns>
4403
        public static Step<XdmNode, XdmNode> Parent(String uri, String localName)
4404
        {
4405
            return AxisStep(XdmAxis.Parent).Where(Predicates.HasName(uri, localName));
4406
        }
4407

    
4408
        /// <summary>
4409
        /// Obtain a <c>Step</c> that filters the node found on the parent axis using a supplied <c>Predicate</c>.
4410
        /// The function call <c>Parent(filter)</c> is equivalent to <c>Parent(filter).where(Predicate)</c>.
4411
		/// For example, <c>Parent(Predicate.IsElement()).GetFunc</c> returns a <c>Step</c> that selects the parent node provided it is an element
4412
        /// </summary>
4413
		/// <param name="filter">The predicate to be applied</param>
4414
		/// <returns>A <c>Step</c> that filters the nodes found on the parent axis using the supplied predicate.</returns>
4415
        public static Step<XdmNode, XdmNode> Parent(Predicate<XdmItem> filter)
4416
        {
4417
            return AxisStep(XdmAxis.Parent).Where(filter);
4418

    
4419
        }
4420

    
4421
		/// <summary>
4422
		/// Obtain a <c>Step</c> to navigate from a node to its preceding siblings, which are returned
4423
		/// in reverse document order.
4424
		/// </summary>
4425
		/// <returns>A <c>Step</c> that selects all nodes on the preceding-sibling axis.</returns>
4426
        public static Step<XdmNode, XdmNode> PrecedingSibling()
4427
        {
4428
            return AxisStep(XdmAxis.PrecedingSibling);
4429
		}
4430

    
4431

    
4432
		/// <summary>
4433
		/// Obtain a <c>Step</c> that navigates from a node to the preceding sibling elements having a specified
4434
		/// local name. These are returned in reverse document order.
4435
		/// </summary>
4436
		/// <param name="localName">The local name of the preceding sibling elements to be selected by the <c>Step</c>,
4437
		/// or "*" to select all descendants that are element nodes</param>
4438
		/// <returns>A <c>Step</c>, which selects the preceding sibling elements of a supplied node that have the
4439
		/// required local name.</returns>
4440
		public static Step<XdmNode, XdmNode> PrecedingSibling(String localName)
4441
		{
4442
			return PrecedingSibling().Where(Predicates.HasLocalName(localName));
4443
		}
4444

    
4445

    
4446
		/// <summary>
4447
		/// Obtain a <c>Step</c> that navigates from a node to the preceding sibling elements having a specified
4448
		/// namespace URI and local name. These are returned in reverse document order.
4449
		/// </summary>
4450
		/// <param name="uri">The namespace URI of the preceding sibling elements to be selected by the <c>Step</c>:
4451
		/// supply a zero-length string to indicate the null namespace</param>
4452
		/// <param name="localName">The local name of the preceding sibling elements to be selected by the <c>Step</c></param>
4453
		/// <returns>A <c>Step</c>, which selects the preceding sibling elements of a supplied node that have the
4454
		/// required local name and namespace URI.</returns>
4455
		public static Step<XdmNode, XdmNode> PrecedingSibling(String uri, String localName)
4456
		{
4457
			return PrecedingSibling().Where(Predicates.ExpandedNamePredicate(uri, localName));
4458
		}
4459

    
4460

    
4461
		/// <summary>
4462
		/// Obtain a <c>Step</c> that filters the nodes found on the preceding sibling axis using a supplied <c>Predicate</c>.
4463
		/// The function call <c>PrecedingSibling(predicate)</c> is equivalent to <c>PrecedingSibling().Where(predicate)</c>.
4464
		/// For example, <c>PrecedingSibling(isElement())</c> returns a <c>Step</c> that selects the preceding sibling elements 
4465
		/// of a given node, while <c>PrecedingSibling(Predicate.Exists(attribute("id")))</c> selects those that have an attribute named "id". 
4466
		/// These are returned in reverse document order.
4467
		/// </summary>
4468
		/// <param name="filter">The predicate to be applied</param>
4469
		/// <returns>A <c>Step</c> that filters the nodes found on the following sibling axis using the supplied predicate.</returns>
4470
		public static Step<XdmNode, XdmNode> PrecedingSibling(Predicate<XdmItem> filter)
4471
		{
4472
			return PrecedingSibling().Where(filter);
4473
		}
4474

    
4475

    
4476
        /// <summary>
4477
        /// Obtain a <c>Step</c> to navigate from a node to its preceding nodes (excluding ancestors),
4478
        /// which are returned in reverse document order.
4479
        /// </summary>
4480
		/// <returns>A <c>Step</c> that selects all nodes on the preceding axis.</returns>
4481
        public static Step<XdmNode, XdmNode> Preceding()
4482
        {
4483
            return AxisStep(XdmAxis.Preceding);
4484
        }
4485

    
4486

    
4487
        /// <summary>
4488
        /// Obtain a <c>Step</c> that navigates from a node to the preceding elements having a specified
4489
        /// local name. These are returned in reverse document order.
4490
        /// </summary>
4491
        /// <param name="localName">The local name of the preceding elements to be selected by the <c>Step</c>,
4492
        /// or "*" to select all descendants that are element nodes</param>
4493
        /// <returns>A <c>Step</c>, which selects the preceding elements of a supplied node that have the
4494
        /// required local name.</returns>
4495
        public static Step<XdmNode, XdmNode> Preceding(String localName)
4496
        {
4497
            return Preceding().Where(Predicates.HasLocalName(localName));
4498
        }
4499

    
4500

    
4501
        /// <summary>
4502
        /// Obtain a <c>Step</c> that navigates from a node to the preceding elements having a specified
4503
        /// namespace URI and local name. These are returned in reverse document order.
4504
        /// </summary>
4505
        /// <param name="uri">The namespace URI of the preceding elements to be selected by the <c>Step</c>:
4506
        /// supply a zero-length string to indicate the null namespace</param>
4507
        /// <param name="localName">The local name of the preceding elements to be selected by the <c>Step</c></param>
4508
        /// <returns>A <c>Step</c>, which selects the preceding elements of a supplied node that have the
4509
        /// required local name and namespace URI.</returns>
4510
        public static Step<XdmNode, XdmNode> Preceding(String uri, String localName)
4511
        {
4512
            return Preceding().Where(Predicates.ExpandedNamePredicate(uri, localName));
4513
        }
4514

    
4515

    
4516
        /// <summary>
4517
		/// Obtain a Step that filters the nodes found on the preceding axis using a supplied <c>Predicate</c> .
4518
		/// The function call <c>Preceding(predicate)</c> is equivalent to <c>Preceding().Where(predicate)</c>.
4519
		/// For example, <c>Preceding(isElement())</c> returns a <c>Step</c> that selects the preceding elements 
4520
        /// of a given node, while <c>Preceding(Predicate.Exists(attribute("id")))</c> selects those that have an attribute named "id". 
4521
        /// These are returned in reverse document order.
4522
        /// </summary>
4523
        /// <param name="filter">The predicate to be applied</param>
4524
		/// <returns>A <c>Step</c> that filters the nodes found on the following axis using the supplied predicate.</returns>
4525
        public static Step<XdmNode, XdmNode> Preceding(Predicate<XdmItem> filter)
4526
        {
4527
            return Preceding().Where(filter);
4528
        }
4529

    
4530

    
4531

    
4532
        /// <summary>
4533
        /// Obtain a <c>Step</c> to navigate from a node to itself (useful only if applying a predicate).
4534
        /// </summary>
4535
        /// <returns>A <c>Step</c> that selects all nodes on the self axis (that is, the node itself).</returns>
4536
        public static Step<XdmNode, XdmNode> Self()
4537
        {
4538
            return AxisStep(XdmAxis.Self);
4539
        }
4540

    
4541

    
4542
        /// <summary>
4543
		/// Obtain a <c>Step</c> that navigates from a node to itself provided it is an element with a specified
4544
        /// local name, irrespective of the namespace.
4545
        /// </summary>
4546
        /// <param name="localName">The local name of the element to be selected by the <c>Step</c>,
4547
        /// or "*" to select the node provided that it is an element node</param>
4548
        /// <returns>A <c>Step</c>, which selects the supplied node provided it has a given local name.</returns>
4549
        public static Step<XdmNode, XdmNode> Self(String localName)
4550
        {
4551
            return AxisStep(XdmAxis.Self).Where(Predicates.HasLocalName(localName));
4552
        }
4553

    
4554

    
4555
        /// <summary>
4556
        /// Obtain a <c>Step</c> that navigates from a node to itself provided it has a specified
4557
        /// namespace URI and local name.
4558
        /// </summary>
4559
        /// <param name="uri">The namespace URI of the element to be selected by the <c>Step</c>:
4560
        /// supply a zero-length string to indicate the null namespace</param>
4561
        /// <param name="localName">The local name of the element to be selected by the <c>Step</c></param>
4562
        /// <returns>A <c>Step</c>, which selects the supplied node provided it is an element with a given local name and namespace URI.</returns>
4563
        public static Step<XdmNode, XdmNode> Self(String uri, String localName)
4564
        {
4565
            return AxisStep(XdmAxis.Self).Where(Predicates.HasName(uri, localName));
4566
        }
4567

    
4568

    
4569
        /// <summary>
4570
		/// Obtain a <c>Step</c> that filters the node found on the self axis using a supplied <c>Predicate</c> filter.
4571
		/// The function call <c>Self(predicate)</c> is equivalent to <c>Self().Where(predicate)</c>.
4572
		/// For example, <c>self(isElement())</c> returns a <c>Step</c> that selects the supplied node provided it is an element.
4573
        /// </summary>
4574
        /// <param name="filter">The predicate to be applied</param>
4575
		/// <returns>A <c>Step</c> that filters the nodes found on the self axis using the supplied predicate.</returns>
4576
        public static Step<XdmNode, XdmNode> Self(Predicate<XdmNode> filter)
4577
        {
4578
            return AxisStep(XdmAxis.Self).Where(filter);
4579
        }
4580

    
4581

    
4582
        /// <summary>
4583
		/// Obtain an selector that atomizes an item to produce a <c>XdmValue</c> of atomic values. Atomizing a node will
4584
        /// usually produce a single atomic value, but in the case of schema-typed nodes using a list type, there may
4585
        /// be more than one atomic value. Atomizing an array also returns multiple atomic values.
4586
        /// </summary>
4587
        public static Step<XdmItem, XdmAtomicValue> Atomize()
4588
        {
4589
            return new Step<XdmItem, XdmAtomicValue>(
4590
                item =>
4591
                {
4592
                    IList<XdmAtomicValue> list = new List<XdmAtomicValue>();
4593

    
4594
                    if (item is XdmAtomicValue)
4595
                    {
4596
                        list.Add((XdmAtomicValue)item);
4597

    
4598
                    }
4599
                    else if (item is XdmNode)
4600
                    {
4601
                        try
4602
                        {
4603
                            var value = ((XdmNode)item).value;
4604
                            list.Add((XdmAtomicValue)XdmValue.Wrap(((JNodeInfo)value).atomize()).ItemAt(0));
4605

    
4606

    
4607
                        }
4608
                        catch (Exception ex)
4609
                        {
4610
                            throw new Exception("Cannot atomize supplied value");
4611
                        }
4612

    
4613
                    }
4614
                    else if (item is XdmArray)
4615
                    {
4616
                        list.Add((XdmAtomicValue)XdmValue.Wrap(((JArrayItem)((XdmArray)item).value).atomize()));
4617
                    }
4618
                    else
4619
                    {
4620
                        throw new Exception("Cannot atomize supplied value");
4621

    
4622
                    }
4623
                    return list;
4624
                });
4625
        }
4626

    
4627

    
4628
        /// <summary>
4629
		/// Obtain a <c>Step</c> that returns text nodes found on the child axis.
4630
		/// The function call <c>Text()</c> is equivalent to <c>Child().Where(Predicate.IsText)</c>.
4631
        /// </summary>
4632
        /// <returns>A <c>Step</c> that returns the text nodes found on the child axis.</returns>
4633
            public static Step<XdmNode, XdmNode> Text()
4634
            {
4635

    
4636
                return Child().Where(Predicates.IsText());
4637
            }
4638

    
4639

    
4640

    
4641

    
4642
            /// <summary>
4643
            /// Obtain a <c>Step</c> whose effect is to tokenize the supplied item on whitespace
4644
            /// boundaries, returning a sequence of strings as <c>XdmAtomicValue</c> instances.
4645
            /// </summary>
4646
            /// <remarks><p>Note: the tokenize step, when applied to a string with leading and trailing whitespace,
4647
            /// has the effect of removing this whitespace. In addition to its primary role, the function
4648
            /// can therefore be useful for trimming the content of a single string.</p></remarks>
4649
            /// <returns>A <c>Step</c> whose effect is to take a supplied item and split its string
4650
		/// value into a sequence of <c>xs:string</c> instances</returns>
4651
            public static Step<XdmAtomicValue, XdmAtomicValue> Tokenize()
4652
            {
4653
                return new Step<XdmAtomicValue, XdmAtomicValue>(item => {
4654
                    {
4655
                        var iter = new SequenceEnumerable<XdmAtomicValue>(JSequenceXdmIterator.ofAtomicValues(new net.sf.saxon.value.Whitespace.Tokenizer(item.GetStringValue())));
4656

    
4657
                        return iter;
4658

    
4659
                    }
4660

    
4661
                });
4662

    
4663

    
4664
        }
4665
        
4666
        /// <summary>
4667
		/// Obtain a Step whose effect is to interpret the supplied item as an <c>xs:ID</c> value
4668
        /// and return the nodes (in a given document) that have that string as their ID.
4669
        /// </summary>
4670
        /// <param name="doc">The root node (document node) of the document within which the ID
4671
        /// value should be sought</param>
4672
		/// <returns>A <c>Step</c> whose effect is to return the nodes that have the given string as their ID.</returns>
4673
        public static Step<XdmNode, XdmNode> id(XdmNode doc)
4674
        {
4675
                return new Step<XdmNode, XdmNode>(item => {
4676
                        IList<XdmNode> list = new List<XdmNode>();
4677
                        XdmNode doci = (XdmNode)doc;
4678
                        JNodeInfo target = ((JNodeInfo)((XdmNode)doci).value).getTreeInfo().selectID(doci.GetStringValue(), true);
4679

    
4680
                        if (target == null) {
4681
                            XdmNode result = new XdmNode();
4682
                            result.value = (JNodeInfo)target;
4683
                            list.Add(result);
4684
                        }
4685
                        return list;
4686
                });
4687

    
4688

    
4689
            }
4690

    
4691

    
4692
        /// <summary>
4693
        /// Construct a path as a composite <c>Step</c> from a sequence of steps composed together.
4694
        /// </summary>
4695
        /// <param name="steps">The constituent steps in the path</param>
4696
        /// <returns>A composite step.</returns>
4697
        public static Step<XdmNode, XdmNode> Path(params string[] steps) {
4698

    
4699
            IList<Step<XdmNode, XdmNode>> pathSteps = new List<Step<XdmNode, XdmNode>>();
4700

    
4701
            foreach (string step in steps) {
4702
                if (step.Equals("/"))
4703
                {
4704
                    pathSteps.Add(Steps.Root().Where(Predicates.IsDocument()));
4705
                }
4706
                else if (step.Equals(".."))
4707
                {
4708
                    pathSteps.Add(Steps.Parent());
4709
                }
4710
                else if (step.Equals("*"))
4711
                {
4712
                    pathSteps.Add(Steps.Child(Predicates.IsElement()));
4713
                }
4714
                else if (step.Equals("//"))
4715
                {
4716
                    pathSteps.Add(Steps.DescendantOrSelf());
4717
                }
4718
                else if (step.StartsWith("@"))
4719
                {
4720
                    String name = step.Substring(1);
4721
                    if (!net.sf.saxon.om.NameChecker.isValidNCName(name))
4722
                    {
4723
                        throw new System.ArgumentException("Invalid attribute name " + name);
4724
                    }
4725
                    pathSteps.Add(Steps.Attribute(name));
4726
                }
4727
                else
4728
                {
4729
                    if (!net.sf.saxon.om.NameChecker.isValidNCName(step))
4730
                    {
4731
                        throw new System.ArgumentException("Invalid element name "+step);
4732
                    }
4733
                    pathSteps.Add(Steps.Child(step));
4734
                }
4735

    
4736
            }
4737

    
4738
            return PathFromEnumerable(pathSteps);
4739

    
4740
        }
4741

    
4742
       
4743
	internal static Step<XdmNode, XdmNode> PathFromEnumerable(IEnumerable<Step<XdmNode, XdmNode>> steps)
4744
    {
4745

    
4746
        List<Step<XdmNode, XdmNode>> list = steps.ToList();
4747
        return PathFromList(list);
4748

    
4749
    }
4750

    
4751

    
4752
        /// <summary>
4753
        /// Construct a path as a composite <c>Step</c> from a list of steps composed together.
4754
        /// </summary>
4755
        /// <param name="steps">The constituent steps in the path</param>
4756
        /// <returns>A composite step.</returns>
4757
        public static Step<XdmNode, XdmNode> PathFromList(List<Step<XdmNode, XdmNode>> steps)
4758
        {
4759
  
4760
            if (steps.Count == 0)
4761
            {
4762
                return new Step<XdmNode, XdmNode>(item => { return new List<XdmNode>(); });
4763
            }
4764
            else if (steps.Count == 1)
4765
            {
4766
                return steps.ElementAt(0);
4767
            }
4768
            else
4769
            {
4770
                return steps.ElementAt(0).Then(PathFromList(steps.GetRange(1, steps.Count-1)));
4771
            }
4772
        }
4773

    
4774

    
4775
    }
4776

    
4777

    
4778
/// <summary>
4779
/// This class is an implementation of <c>IEnumerator</c> that wraps
4780
/// a (Java) <c>SequenceIterator</c>.
4781
/// </summary>
4782
/// <remarks>
4783
/// Because the underlying value can be evaluated lazily, it is possible
4784
/// for exceptions to occur as the sequence is being read.
4785
/// </remarks>
4786

    
4787
[Serializable]
4788
    internal class SequenceEnumerable<T> : IEnumerable<T>
4789
          where T : XdmItem
4790
    {
4791

    
4792
        private JSequenceXdmIterator iterator;
4793

    
4794
        internal SequenceEnumerable(JSequenceXdmIterator iterator)
4795
        {
4796
            this.iterator = iterator;
4797
        }
4798

    
4799
        public IEnumerator<T> GetEnumerator()
4800
        {
4801
            return (IEnumerator<T>)new SequenceEnumerator<XdmNode>(iterator);
4802
        }
4803

    
4804
        IEnumerator IEnumerable.GetEnumerator()
4805
        {
4806
            return (IEnumerator<T>)new SequenceEnumerator<XdmNode>(iterator);
4807
        }
4808
    }
4809

    
4810

    
4811

    
4812
    /// <summary>
4813
    /// This class is an implementation of <c>IEnumerator</c> that wraps
4814
    /// a (Java) <c>SequenceIterator</c>.
4815
    /// </summary>
4816
    /// <remarks>
4817
    /// Because the underlying value can be evaluated lazily, it is possible
4818
    /// for exceptions to occur as the sequence is being read.
4819
    /// </remarks>
4820

    
4821
    [Serializable]
4822
    internal class SequenceEnumerator<T> : IEnumerator<T>
4823
      where T : XdmItem
4824
    {
4825

    
4826
        private JSequenceXdmIterator iter;
4827
        private JItem current;
4828

    
4829
        internal SequenceEnumerator(JSequenceXdmIterator iter)
4830
        {
4831
            this.iter = iter;
4832
            current = null;
4833
        }
4834

    
4835

    
4836
        /// <summary>Return the current item in the sequence</summary>
4837
        /// <returns>An object which will always be an instance of <c>XdmItem</c></returns>
4838
        /// 
4839
        public XdmItem Current
4840
        {
4841
            get
4842
            {
4843
                return current == null ? null : (XdmItem)XdmValue.Wrap(current);
4844
            }
4845
        }
4846

    
4847
        object IEnumerator.Current
4848
        {
4849
            get
4850
            {
4851
                return Current;
4852
            }
4853
        }
4854

    
4855
        T IEnumerator<T>.Current
4856
        {
4857

    
4858
            get { return (T)Current; }
4859
        }
4860

    
4861
        /// <summary>Move to the next item in the sequence</summary>
4862
        /// <returns>true if there are more items in the sequence</returns>
4863

    
4864
        public bool MoveNext()
4865
        {
4866
            try
4867
            {
4868
                if (!iter.hasNext())
4869
                {
4870
                    return false;
4871
                }
4872
            }
4873
            catch (net.sf.saxon.s9api.SaxonApiUncheckedException)
4874
            {
4875
                return false;
4876
            }
4877
            net.sf.saxon.s9api.XdmItem nextXdmItem = iter.next();
4878
            if (nextXdmItem != null)
4879
            {
4880
                JItem nextItem = nextXdmItem.getUnderlyingValue();
4881
                current = nextItem;
4882
                return (nextItem != null);
4883
            }
4884
            return false;
4885

    
4886
        }
4887

    
4888
        /// <summary>Deprecated. Reset the enumeration so that the next call of
4889
        /// <c>MoveNext</c> will position the enumeration at the
4890
        /// first item in the sequence</summary>
4891
        [System.Obsolete("MethodAccessException no longer used")]
4892
        public void Reset()
4893
        {
4894

    
4895
        }
4896

    
4897
        /// <summary>
4898
        /// The Dispose method does not have any effect on this Enumerator
4899
        /// </summary>
4900
        public void Dispose()
4901
        {
4902

    
4903
        }
4904
    }
4905

    
4906

    
4907

    
4908
    /// <summary>
4909
    /// Enumeration identifying the thirteen XPath axes
4910
    /// </summary>
4911

    
4912
    public enum XdmAxis
4913
    {
4914
        /// <summary>The XPath ancestor axis</summary> 
4915
        Ancestor,
4916
        /// <summary>The XPath ancestor-or-self axis</summary> 
4917
        AncestorOrSelf,
4918
        /// <summary>The XPath attribute axis</summary> 
4919
        Attribute,
4920
        /// <summary>The XPath child axis</summary> 
4921
        Child,
4922
        /// <summary>The XPath descendant axis</summary> 
4923
        Descendant,
4924
        /// <summary>The XPath descandant-or-self axis</summary> 
4925
        DescendantOrSelf,
4926
        /// <summary>The XPath following axis</summary> 
4927
        Following,
4928
        /// <summary>The XPath following-sibling axis</summary> 
4929
        FollowingSibling,
4930
        /// <summary>The XPath namespace axis</summary> 
4931
        Namespace,
4932
        /// <summary>The XPath parent axis</summary> 
4933
        Parent,
4934
        /// <summary>The XPath preceding axis</summary> 
4935
        Preceding,
4936
        /// <summary>The XPath preceding-sibling axis</summary> 
4937
        PrecedingSibling,
4938
        /// <summary>The XPath self axis</summary> 
4939
        Self
4940
    }
4941

    
4942
    /// <summary>
4943
    /// An implementation of <code>IEnumerator</code> that iterates over an empty sequence.
4944
    /// </summary>
4945

    
4946
    public class EmptyEnumerator<T> : IEnumerator<T>
4947
       where T : XdmItem
4948
    {
4949

    
4950
        /// <summary>
4951
		/// Create an instance of the enumerator with the <c>XdmItem</c> as the generic type
4952
        /// </summary>
4953
        public static EmptyEnumerator<XdmItem> INSTANCE = new EmptyEnumerator<XdmItem>();
4954

    
4955
        /// <summary>
4956
		/// Create an instance of the enumerator with the <c>XdmNode</c> as the generic type
4957
        /// </summary>
4958
        public static EmptyEnumerator<XdmNode> NODE_INSTANCE = new EmptyEnumerator<XdmNode>();
4959

    
4960
        private EmptyEnumerator() { }
4961

    
4962
        /// <summary>
4963
        /// Reset the enumerator
4964
        /// </summary>
4965
        public void Reset() { }
4966

    
4967

    
4968

    
4969

    
4970
        object IEnumerator.Current
4971
        {
4972
            get
4973
            {
4974
                return null;
4975
            }
4976
        }
4977

    
4978
        /// <summary>
4979
        /// The current item in the enumerator
4980
        /// </summary>
4981
        T IEnumerator<T>.Current
4982
        {
4983
            get
4984
            {
4985
                return null;
4986
            }
4987
        }
4988

    
4989
        /// <summary>
4990
        /// Move to the next item in the enumerator..
4991
        /// </summary>
4992
        /// <returns>true if successful move, false otherwise.</returns>
4993
        public bool MoveNext()
4994
        {
4995
            return false;
4996
        }
4997

    
4998
        /// <summary>
4999
        /// The Dispose method is not implemented on this Enumerator
5000
        /// </summary>
5001
        public void Dispose()
5002
        {
5003
            throw new NotImplementedException();
5004
        }
5005
    }
5006

    
5007

    
5008
}
5009

    
5010
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
5011
// Copyright (c) 2020 Saxonica Limited.
5012
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
5013
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
5014
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
5015
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(5-5/11)