Project

Profile

Help

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

he / tags / 9.6.0.7 / hen / csource / api / Saxon.Api / Model.cs @ aa733b18

1
using System;
2
using System.IO;
3
using System.Xml;
4
using System.Collections;
5
using JConfiguration = net.sf.saxon.Configuration;
6
using JNamePool = net.sf.saxon.om.NamePool;
7
using JAtomicValue = net.sf.saxon.value.AtomicValue;
8
using JFunctionItem = net.sf.saxon.om.FunctionItem;
9
using JItem = net.sf.saxon.om.Item;
10
using JZeroOrOne = net.sf.saxon.om.ZeroOrOne;
11
using JOne = net.sf.saxon.om.One;
12
using JEmptySequence = net.sf.saxon.value.EmptySequence;
13
using JSequenceExtent = net.sf.saxon.value.SequenceExtent;
14
using JConversionResult = net.sf.saxon.type.ConversionResult;
15
using JValidationFailure = net.sf.saxon.type.ValidationFailure;
16
using JSequenceIterator = net.sf.saxon.om.SequenceIterator;
17
using JStandardNames = net.sf.saxon.om.StandardNames;
18
using JStructuredQName = net.sf.saxon.om.StructuredQName;
19
using JXPathContext = net.sf.saxon.expr.XPathContext;
20
using DotNetReceiver = net.sf.saxon.dotnet.DotNetReceiver;
21
using DotNetObjectValue = net.sf.saxon.dotnet.DotNetObjectValue;
22
using JBigDecimal = java.math.BigDecimal;
23
using JArrayList = java.util.ArrayList;
24
using JCharSequence = java.lang.CharSequence;
25
using net.sf.saxon.lib;
26
using net.sf.saxon.om;
27
using net.sf.saxon.tree.iter;
28
using net.sf.saxon.value;
29
using net.sf.saxon.pattern;
30
using JAtomicType = net.sf.saxon.type.AtomicType;
31
using JSchemaType = net.sf.saxon.type.SchemaType;
32
using JType = net.sf.saxon.type.Type;
33
using JStringToDouble = net.sf.saxon.type.StringToDouble;
34
using JSequenceTool =  net.sf.saxon.om.SequenceTool;
35

    
36

    
37
namespace Saxon.Api
38
{
39

    
40
    /// <summary>
41
    /// An value in the XDM data model. A value is a sequence of zero or more
42
    /// items, each item being either an atomic value or a node.
43
    /// </summary>
44
    /// <remarks>
45
    /// <para>An <c>XdmValue</c> is immutable.</para>
46
    /// <para>A sequence consisting of a single item <i>may</i> be represented
47
    /// as an instance of <c>XdmItem</c>, which is a subtype of <c>XdmValue</c>. However,
48
    /// there is no guarantee that all single-item sequences will be instances of
49
    /// <c>XdmItem</c>: if you want to ensure this, use the <c>Simplify</c> property.</para>
50
    /// <para>There are various ways of creating an <c>XdmValue</c>. To create an atomic
51
    /// value, use one of the constructors on <c>XdmAtomicValue</c> (which is a subtype of <c>XdmValue</c>).
52
    /// To construct an <c>XdmNode</c> (another subtype) by parsing an XML document, or by wrapping a DOM document,
53
    /// use a <c>DocumentBuilder</c>. To create a sequence of values, use the <c>Append</c>
54
    /// method on this class to form a list from individual items or sublists.</para>
55
    /// <para>An <c>dmValue</c> is also returned as the result of evaluating a query
56
    /// using the XQuery and XPath interfaces.</para>
57
    /// <para>The subtype <c>XdmEmptySequence</c> represents an empty sequence: an
58
    /// <c>XdmValue</c> of length zero. Again, there is no guarantee that every empty sequence
59
    /// will be represented as an instance of <c>XdmEmptySequence</c>, unless you use
60
    /// the <c>Simplify</c> property.</para>
61
    /// </remarks>
62

    
63
    [Serializable]
64
    public class XdmValue : IEnumerable
65
    {
66

    
67
        internal Sequence value;
68

    
69
        /// <summary>
70
        /// Internal constructor
71
        /// </summary>
72

    
73
        internal XdmValue() { }
74

    
75
        /// <summary>
76
        /// Create a value from a collection of items
77
        /// </summary>
78
        /// <param name="items">An enumerable collection providing the items to make up the sequence. Every
79
        /// member of this collection must be an instance of <c>XdmItem</c>
80
        /// </param>
81

    
82
        public XdmValue(IEnumerable items)
83
        {
84
            JArrayList list = new JArrayList();
85
            foreach (XdmItem c in items)
86
            {
87
                list.add((Item)c.Unwrap());
88
            }
89
            value = new SequenceExtent(list);
90
        }
91

    
92
        /// <summary>
93
        /// Create a new XdmValue by concatenating the sequences of items in this XdmValue and another XdmValue
94
        /// </summary>
95
        /// <remarks>
96
        /// Neither of the input XdmValue objects is modified by this operation
97
        /// </remarks>
98
        /// <param name="otherValue">
99
        /// The other XdmValue, whose items are to be appended to the items from this XdmValue
100
        /// </param>
101
        
102
        public XdmValue Append(XdmValue otherValue) {
103
            JArrayList list = new JArrayList();
104
            foreach (XdmItem item in this) {
105
                list.add(item.Unwrap());
106
            }
107
            foreach (XdmItem item in otherValue) {
108
                list.add(item.Unwrap());
109
            }
110
            return XdmValue.Wrap(new SequenceExtent(list));
111
        }
112

    
113

    
114
        /// <summary>
115
        /// Create an XdmValue from an underlying Saxon Sequence object.
116
        /// This method is provided for the benefit of applications that need to mix
117
        /// use of the Saxon .NET API with direct use of the underlying objects
118
        /// and methods offered by the Java implementation.
119
        /// </summary>
120
        /// <param name="value">An object representing an XDM value in the
121
        /// underlying Saxon implementation. If the parameter is null,
122
        /// the method returns null.</param>
123
        /// <returns>An XdmValue that wraps the underlying Saxon value
124
        /// representation.</returns>
125

    
126
        public static XdmValue Wrap(Sequence value)
127
        {
128
            XdmValue result;
129
            if (value == null)
130
            {
131
                return null;
132
            }
133
            if (value is JEmptySequence)
134
            {
135
                return XdmEmptySequence.INSTANCE;
136
            }
137
            else if (value is JAtomicValue)
138
            {
139
                result = new XdmAtomicValue();
140
            }
141
            else if (value is NodeInfo)
142
            {
143
                result = new XdmNode();
144
            }
145
            else if (value is JZeroOrOne)
146
            {
147
                return Wrap(((JZeroOrOne)value).head());
148
            }
149
            else if (value is JOne)
150
            {
151
                return Wrap(((JOne)value).head());
152
            }
153
            else
154
            {
155
                result = new XdmValue();
156
            }
157
            result.value = value;
158
            return result;
159
        }
160

    
161

    
162
        /// <summary>
163
        /// Extract the underlying Saxon Sequence object from an XdmValue.
164
        /// This method is provided for the benefit of applications that need to mix
165
        /// use of the Saxon .NET API with direct use of the underlying objects
166
        /// and methods offered by the Java implementation.
167
        /// </summary>
168
        /// <returns>An object representing the XDM value in the
169
        /// underlying Saxon implementation.</returns>
170

    
171

    
172
        public Sequence Unwrap()
173
        {
174
            return value;
175
        }
176

    
177
        /// <summary>
178
        /// Get the sequence of items in the form of an <c>IList</c>
179
        /// </summary>
180
        /// <returns>
181
        /// The list of items making up this value. Each item in the list
182
        /// will be an object of type <c>XdmItem</c>
183
        /// </returns>        
184

    
185
        public IList GetList()
186
        {
187
            if (value == null)
188
            {
189
                return new ArrayList();
190
            }
191
            else if (value is Item)
192
            {
193
                ArrayList list = new ArrayList(1);
194
                list.Add((NodeInfo)value);
195
                return list;
196
            }
197
            else
198
            {
199
                ArrayList list = new ArrayList();
200
                SequenceIterator iter = value.iterate();
201
                while (true)
202
                {
203
                    JItem jitem = iter.next();
204
                    if (jitem == null)
205
                    {
206
                        break;
207
                    }
208
                    list.Add((XdmItem)XdmValue.Wrap(jitem));
209
                }
210
                return list;
211
            }
212
        }
213

    
214
        /// <summary>
215
        /// Get the sequence of items in the form of an <c>IXdmEnumerator</c>
216
        /// </summary>
217
        /// <returns>
218
        /// An enumeration over the list of items making up this value. Each item in the list
219
        /// will be an object of type <c>XdmItem</c>
220
        /// </returns>    
221

    
222
        public IEnumerator GetEnumerator()
223
        {
224
            if (value == null)
225
            {
226
                return EmptyEnumerator.INSTANCE;
227
            }
228
            else if (value is Item)
229
            {
230
                return new SequenceEnumerator(SingletonIterator.makeIterator((Item)value));
231
            }
232
            else
233
            {
234
                return new SequenceEnumerator(value.iterate());
235
            }
236
        }
237

    
238
        /// <summary>
239
        /// Get the number of items in the sequence
240
        /// </summary>
241
        /// <returns>
242
        /// The number of items in the sequence
243
        /// </returns> 
244

    
245
        public int Count
246
        {
247
            get
248
            {
249
                if (value == null)
250
                {
251
                    return 0;
252
                }
253
                else if (value is Item)
254
                {
255
                    return 1;
256
                }
257
                else
258
                {
259
                    return JSequenceTool.toGroundedValue(value).getLength();
260
                }
261
            }
262
        }
263

    
264
        /// <summary>
265
        /// Simplify a value: that is, reduce it to the simplest possible form.
266
        /// If the sequence is empty, the result will be an instance of <c>XdmEmptySequence</c>.
267
        /// If the sequence is a single node, the result will be an instance of <c>XdmNode</c>;
268
        /// if it is a single atomic value, it will be an instance of <c>XdmAtomicValue</c>.
269
        /// </summary>
270

    
271
        public XdmValue Simplify
272
        {
273
            get
274
            {
275
                switch (JSequenceTool.toGroundedValue(value).getLength())
276
                {
277
                    case 0:
278
                        if (this is XdmEmptySequence)
279
                        {
280
                            return this;
281
                        }
282
                        return XdmEmptySequence.INSTANCE;
283

    
284
                    case 1:
285
                        if (this is XdmItem)
286
                        {
287
                            return this;
288
                        }
289
                        return XdmValue.Wrap(value);
290

    
291
                    default:
292
                        return this;
293
                }
294
            }
295
        }
296

    
297
    }
298

    
299
    /// <summary inherits="XdmValue">
300
    /// The class <c>XdmItem</c> represents an item in a sequence, as defined
301
    /// by the XDM data model. An item is either an atomic value or a node.
302
    /// </summary>
303
    /// <remarks>
304
    /// <para>An item is a member of a sequence, but it can also be considered as
305
    /// a sequence (of length one) in its own right. <c>XdmItem</c> is a subtype
306
    /// of <c>XdmValue</c> because every Item in the XDM data model is also a
307
    /// value.</para>
308
    /// <para>It cannot be assumed that every sequence of length one will be 
309
    /// represented by an <c>XdmItem</c>. It is quite possible for an <c>XdmValue</c>
310
    /// that is not an <c>XdmItem</c> to hold a singleton sequence.</para>
311
    /// </remarks> 
312

    
313
    [Serializable]
314
    public abstract class XdmItem : XdmValue
315
    {
316

    
317
        /// <summary>
318
        /// Determine whether the item is an atomic value
319
        /// </summary>
320
        /// <returns>
321
        /// true if the item is an atomic value, false if it is a Node
322
        /// </returns>
323

    
324
        public abstract bool IsAtomic();
325

    
326
    }
327

    
328
    /// <summary inherits="XdmItem">
329
    /// The class <c>XdmAtomicValue</c> represents an item in an XPath 2.0 sequence
330
    /// that is an atomic value. The value may belong to any of the 19 primitive types
331
    /// defined in XML Schema, or to a type derived from these primitive types, or to 
332
    /// the XPath 2.0 type <c>xs:untypedAtomic</c>
333
    /// </summary>
334
    /// <remarks>
335
    /// Note that there is no guarantee that every <c>XdmValue</c> comprising a single
336
    /// atomic value will be an instance of this class. To force this, use the <c>Simplify</c>
337
    /// property of the <c>XdmValue</c>.
338
    /// </remarks>
339

    
340
    [Serializable]
341
    public class XdmAtomicValue : XdmItem
342
    {
343

    
344
        //internal JAtomicValue atomicValue;
345

    
346
        internal XdmAtomicValue() { }
347

    
348
        /// <summary>
349
        /// Determine whether the item is an atomic value
350
        /// </summary>
351
        /// <returns>
352
        /// true (the item is an atomic value)
353
        /// </returns>
354

    
355
        public override bool IsAtomic()
356
        {
357
            return true;
358
        }
359

    
360
        /// <summary>
361
        /// Construct an atomic value of type <c>xs:string</c>
362
        /// </summary>
363
        /// <param name="str">The string value</param>
364

    
365
        public XdmAtomicValue(String str)
366
        {
367
            this.value = new StringValue(str);
368
        }
369

    
370
        /// <summary>
371
        /// Construct an atomic value of type <c>xs:integer</c>
372
        /// </summary>
373
        /// <param name="i">The integer value</param>
374

    
375
        public XdmAtomicValue(long i)
376
        {
377
            this.value = new Int64Value(i);
378
        }
379

    
380
        /// <summary>
381
        /// Construct an atomic value of type <c>xs:decimal</c>
382
        /// </summary>
383
        /// <param name="d">The decimal value</param>
384

    
385
        public XdmAtomicValue(decimal d)
386
        {
387
            this.value = new DecimalValue(new JBigDecimal(d.ToString()));
388
        }
389

    
390
        /// <summary>
391
        /// Construct an atomic value of type <c>xs:float</c>
392
        /// </summary>
393
        /// <param name="f">The float value</param>        
394

    
395
        public XdmAtomicValue(float f)
396
        {
397
            this.value = new FloatValue(f);
398
        }
399

    
400
        /// <summary>
401
        /// Construct an atomic value of type <c>xs:double</c>
402
        /// </summary>
403
        /// <param name="d">The double value</param>
404

    
405
        public XdmAtomicValue(double d)
406
        {
407
            this.value = new DoubleValue(d);
408
        }
409

    
410
        /// <summary>
411
        /// Construct an atomic value of type <c>xs:boolean</c>
412
        /// </summary>
413
        /// <param name="b">The boolean value</param>
414

    
415
        public XdmAtomicValue(bool b)
416
        {
417
            this.value = BooleanValue.get(b);
418
        }
419

    
420
        /// <summary>
421
        /// Construct an atomic value of type <c>xs:anyURI</c>
422
        /// </summary>
423
        /// <param name="u">The uri value</param>
424

    
425
        public XdmAtomicValue(Uri u)
426
        {
427
            this.value = new AnyURIValue(u.ToString());
428
        }
429

    
430
        /// <summary>
431
        /// Construct an atomic value of type <c>xs:QName</c>
432
        /// </summary>
433
        /// <param name="q">The QName value</param>                
434

    
435
        public XdmAtomicValue(QName q)
436
        {
437
            this.value = new QNameValue(
438
                q.Prefix, q.Uri, q.LocalName);
439
        }
440

    
441
        /// <summary>
442
        /// Construct an atomic value of a given built-in or user-defined type
443
        /// </summary>
444
        /// <example>
445
        ///   <code>AtomicValue("abcd", QName.XDT_UNTYPED_ATOMIC)</code>
446
        ///   <para>creates an untyped atomic value containing the string "abcd"</para>
447
        /// </example>
448
        /// <param name="lexicalForm">The string representation of the value (any value that is acceptable
449
        /// in the lexical space, as defined by XML Schema Part 2). Whitespace normalization as defined by
450
        /// the target type will be applied to the value.</param>
451
        /// <param name="type">The QName giving the name of the target type. This must be an atomic
452
        /// type, and it must not be a type that is namespace-sensitive (QName, NOTATION, or types derived
453
        /// from these). If the type is a user-defined type then its definition must be present
454
        /// in the schema cache maintained by the <c>SchemaManager</c>.</param> 
455
        /// <param name="processor">The <c>Processor</c> object. This is needed for looking up user-defined
456
        /// types, and also because some conversions are context-sensitive, for example they depend on the
457
        /// implicit timezone or the choice of XML 1.0 versus XML 1.1 for validating names.</param>
458
        /// <exception name="ArgumentException">Thrown if the type is unknown or unsuitable, or if the supplied string is not
459
        /// a valid lexical representation of a value of the given type.</exception>
460

    
461
        public XdmAtomicValue(String lexicalForm, QName type, Processor processor)
462
        {
463
			JConfiguration jconfig = processor.Implementation;
464
            int fp = jconfig.getNamePool().getFingerprint(type.Uri, type.LocalName);
465
            if (fp == -1)
466
            {
467
                throw new ArgumentException("Unknown name " + type);
468
            }
469
            JSchemaType st = jconfig.getSchemaType(fp);
470
            if (st == null)
471
            {
472
                throw new ArgumentException("Unknown type " + type);
473
            }
474
            if (!(st is JAtomicType))
475
            {
476
                throw new ArgumentException("Specified type " + type + " is not atomic");
477
            }
478
            if (((JAtomicType)st).isNamespaceSensitive())
479
            {
480
                throw new ArgumentException("Specified type " + type + " is namespace-sensitive");
481
            }
482
			JConversionResult result = ((JAtomicType)st).getStringConverter(jconfig.getConversionRules()).convertString((JCharSequence)lexicalForm);
483
 
484
            if (result is JValidationFailure)
485
            {
486
                throw new ArgumentException(((JValidationFailure)result).getMessage());
487
            }
488
            this.value = (JAtomicValue)result;
489
        }
490

    
491
        /// <summary>
492
        /// Create an atomic value that wraps an external object. Such values can be used
493
        /// in conjunction with extension functions.
494
        /// </summary>
495
        /// <remarks>
496
        /// <para>This method should not be used to create simple atomic values representing strings,
497
        /// numbers, booleans, and so on. For that purpose, use the relevant constructor.
498
        /// Wrapped external objects are used only when calling .NET native code external
499
        /// to a query or stylesheet.</para>
500
        /// <para>In releases prior to 9.2, this method also existed with the alternative spelling
501
        /// <code>wrapExternalObject</code> (lower-case "w"). This was retained for backwards compatibility,
502
        /// but caused problems for Visual Basic users, where it is not permitted to have two methods whose
503
        /// names differ only in case. Any applications using <code>wrapExternalObject</code> must
504
        /// therefore be changed to use <code>WrapExternalObject</code>. Apologies for the inconvenience.</para>
505
        /// </remarks>
506
        /// <param name="external">The object to be wrapped.</param>
507
        /// <returns>The wrapped object</returns>
508

    
509
        public static XdmAtomicValue WrapExternalObject(object external)
510
        {
511
            return (XdmAtomicValue)XdmValue.Wrap(new DotNetObjectValue(external));
512
        }
513

    
514

    
515
        /// <summary>
516
        /// Get the value converted to a boolean using the XPath casting rules
517
        /// </summary>
518
        /// <returns>the result of converting to a boolean (Note: this is not the same as the
519
        /// effective boolean value).</returns> 
520

    
521
        public bool GetBooleanValue()
522
        {
523
            JAtomicValue av = (JAtomicValue)this.value;
524
            if (av is BooleanValue) {
525
                return ((BooleanValue)av).getBooleanValue();
526
            } else if (av is NumericValue) {
527
                return !av.isNaN() && ((NumericValue)av).signum() != 0;
528
            } else if (av is StringValue) {
529
                String s = av.getStringValue().Trim();
530
                return "1".Equals(s) || "true".Equals(s);
531
            } else {
532
                throw new ArgumentException("Cannot cast item to a boolean");
533
            }
534
        }
535

    
536

    
537
        /// <summary>
538
        /// Get the value converted to a boolean using the XPath casting rules
539
        /// </summary>
540
        /// <returns>the result of converting to an integer</returns>
541

    
542
        public long GetLongValue()
543
        {
544
            AtomicValue av = (AtomicValue)this.Value;
545
            if (av is BooleanValue) {
546
                return ((BooleanValue)av).getBooleanValue() ? 0L : 1L;
547
            } else if (av is NumericValue) {
548
            try {
549
                return ((NumericValue)av).longValue();
550
            } catch (Exception) {
551
                throw new ArgumentException("Cannot cast item to an integer");
552
            }
553
            } else if (av is StringValue) {
554
                JStringToDouble converter = JStringToDouble.getInstance();
555
                return (long)converter.stringToNumber(av.getStringValueCS());
556
            } else {
557
                throw new ArgumentException("Cannot cast item to an integer");
558
            }
559
        }
560

    
561

    
562
        /// <summary>
563
        /// Get the value converted to a double using the XPath casting rules.
564
        /// <p>If the value is a string, the XSD 1.1 rules are used, which means that the string
565
        /// "+INF" is recognised.</p>
566
        /// </summary>
567
        /// <returns>the result of converting to a double</returns>
568

    
569
        public double GetDoubleValue()
570
        {
571
            AtomicValue av = (AtomicValue)this.value;
572
            if (av is BooleanValue) {
573
                return ((BooleanValue)av).getBooleanValue() ? 0.0 : 1.0;
574
            } else if (av is NumericValue) {
575
                return ((NumericValue)av).getDoubleValue();
576
            } else if (av is StringValue) {
577
            try {
578
                JStringToDouble converter = StringToDouble11.getInstance();
579
                return converter.stringToNumber(av.getStringValueCS());
580
            } catch (Exception e) {
581
                throw new ArgumentException(e.Message);
582
            }
583
            } else {
584
                throw new ArgumentException("Cannot cast item to a double");
585
            }
586
        }
587

    
588

    
589
         /// <summary>
590
        /// Get the value converted to a decimal using the XPath casting rules
591
        /// </summary>
592
        /// <returns>return the result of converting to a decimal</returns>
593

    
594
        public Decimal GetDecimalValue() 
595
        {
596
            AtomicValue av = (AtomicValue)this.value;
597
            if (av is BooleanValue) {
598
                return ((BooleanValue)av).getBooleanValue() ? 0  : 1;
599
            } else if (av is NumericValue) {
600
                try {
601
                    return Convert.ToDecimal(((NumericValue)av).getDecimalValue().toString());
602
                } catch (Exception) {
603
                    throw new ArgumentException("Cannot cast item to a decimal");
604
                }   
605
            } else if (av is StringValue) {
606
                return Convert.ToDecimal(av.getStringValueCS().toString());
607
            } else {
608
                throw new ArgumentException("Cannot cast item to a decimal");
609
            }
610
        }
611

    
612

    
613

    
614
        /// <summary>
615
        /// Convert the atomic value to a string
616
        /// </summary>
617
        /// <returns>The value converted to a string, according to the rules
618
        /// of the XPath 2.0 cast operator</returns>        
619

    
620
        public override String ToString()
621
        {
622
            return ((JAtomicValue)value).getStringValue();
623
        }
624

    
625
        /// <summary>
626
        /// Get the name of the value's XDM type
627
        /// </summary>
628
        /// <param name="processor">The <c>Processor</c> object. 
629
        /// This is needed for access to the NamePool,
630
        /// which maps the internal form of type names to their external form.</param>
631
        /// <returns>The type of the value, as a QName. This may be a built-in type or a user-defined
632
        /// atomic type.
633
        /// </returns>
634

    
635

    
636
        public QName GetTypeName(Processor processor)
637
        {
638
            int fp = ((JAtomicType)((JAtomicValue)value).getItemType()).getFingerprint();
639
			NamePool pool = processor.Implementation.getNamePool();
640
            return new QName(pool.getPrefix(fp),
641
                             pool.getURI(fp),
642
                             pool.getLocalName(fp));
643
        }
644

    
645
        /// <summary>
646
        /// Get the name of the primitive type of the value
647
        /// </summary>
648
        /// <returns>The primitive type of the value, as a QName. This will be the name of
649
        /// one of the primitive types defined in XML Schema Part 2, or the XPath-defined
650
        /// type <c>xs:untypedAtomic</c>. For the purposes of this method, <c>xs:integer</c> is considered
651
        /// to be a primitive type.
652
        /// </returns>
653

    
654

    
655
        public QName GetPrimitiveTypeName()
656
        {
657
            int fp = ((JAtomicValue)value).getItemType().getPrimitiveType();
658
            return new QName(JStandardNames.getPrefix(fp),
659
                             JStandardNames.getURI(fp),
660
                             JStandardNames.getLocalName(fp));
661
        }
662

    
663
        /// <summary>Get the value as a CLI object of the nearest equivalent type.</summary>
664
        /// <remarks>
665
        /// <para>The return type is as follows:</para>
666
        /// <para>xs:string - String</para>
667
        /// <para>xs:integer - Long</para>
668
        /// <para>xs:decimal - Decimal</para>
669
        /// <para>xs:double - Double</para>
670
        /// <para>xs:float - Float</para>
671
        /// <para>xs:boolean - Bool</para>
672
        /// <para>xs:QName - QName</para>
673
        /// <para>xs:anyURI - Uri</para>
674
        /// <para>xs:untypedAtomic - String</para>
675
        /// <para>wrapped external object - the original external object</para>
676
        /// <para>Other types - currently String, but this may change in the future</para>
677
        /// </remarks>
678
        /// <returns>The value converted to the most appropriate CLI type</returns>
679

    
680
        public Object Value
681
        {
682
            get
683
            {
684
                if (value is IntegerValue)
685
                {
686
                    return ((IntegerValue)value).longValue();
687
                }
688
                else if (value is DoubleValue)
689
                {
690
                    return ((DoubleValue)value).getDoubleValue();
691
                }
692
                else if (value is FloatValue)
693
                {
694
                    return ((FloatValue)value).getFloatValue();
695
                }
696
                else if (value is DecimalValue)
697
                {
698
                    return Decimal.Parse(((DecimalValue)value).getStringValue());
699
                }
700
                else if (value is BooleanValue)
701
                {
702
                    return ((BooleanValue)value).getBooleanValue();
703
                }
704
                else if (value is AnyURIValue)
705
                {
706
                    return new Uri(((AnyURIValue)value).getStringValue());
707
                }
708
                else if (value is QNameValue)
709
                {
710
                    return new QName((QNameValue)value);
711
                }
712
                else if (value is DotNetObjectValue)
713
                {
714
                    return ((DotNetObjectValue)value).getObject();
715
                }
716
                else
717
                {
718
                    return ((JAtomicValue)value).getStringValue();
719
                }
720
            }
721
        }
722

    
723

    
724
    }
725

    
726
    /// <summary inherits="XdmItem">
727
    /// The class <c>XdmFunctionItem</c> represents an item in an XPath 3.0 sequence
728
    /// that represents a function.
729
    /// </summary>
730
    /// <remarks>
731
    /// <para>Note that there is no guarantee that every <c>XdmValue</c> comprising a single
732
    /// function item will be an instance of this class. To force this, use the <c>Simplify</c>
733
    /// property of the <c>XdmValue</c>.</para>
734
    /// <para>At present the only way of creating an instance of this class is as the result of
735
    /// an XPath or XQuery expression that returns a function item. Note that this feature requires
736
    /// XPath 3.0 or XQuery 3.0 to be enabled, which in turn requires use of Saxon-EE.</para>
737
    /// </remarks>
738

    
739
    [Serializable]
740
    public class XdmFunctionItem : XdmItem
741
    {
742
        /// <summary>
743
        /// The name of the function, as a QName. The result will be null if the function is anonymous.
744
        /// </summary>
745
        
746
        public QName FunctionName
747
        {
748
            get
749
            {
750
                return QName.FromStructuredQName(((JFunctionItem)value).getFunctionName());
751
            }
752
        }
753

    
754
        /// <summary>
755
        /// The arity of the function, that is, the number of arguments it expects
756
        /// </summary>
757

    
758
        public int Arity
759
        {
760
            get
761
            {
762
                return ((JFunctionItem)value).getArity();
763
            }
764
        }
765

    
766
        /// <summary>
767
        /// Determine whether the item is an atomic value
768
        /// </summary>
769
        /// <returns>
770
        /// false (a function item is not an atomic value)
771
        /// </returns>
772

    
773
        public override bool IsAtomic()
774
        {
775
            return false;
776
        }
777

    
778

    
779
        /// <summary>
780
        /// Invoke the function
781
        /// </summary>
782
        /// <param name="arguments">The arguments to the function</param>
783
        /// <param name="processor">The Saxon processor, used to provide context information</param>
784
        /// <returns>The result of calling the function</returns>
785
        /// 
786
        public XdmValue invoke(XdmValue[] arguments, Processor processor)
787
        {
788
            Sequence[] args = new Sequence[arguments.Length];
789
            for (int i = 0; i < arguments.Length; i++)
790
            {
791
                args[i] = arguments[i].Unwrap();
792
            }
793
			JXPathContext context = processor.Implementation.getConversionContext();
794
            Sequence result = ((JFunctionItem)value).call(context, args);
795
            return XdmValue.Wrap(result);
796
        }
797
    }
798

    
799

    
800
    /// <summary inherits="XdmItem">
801
    /// The class <c>XdmNode</c> represents a Node in the XDM Data Model. A Node
802
    /// is an <c>XdmItem</c>, and is therefore an <c>XdmValue</c> in its own right, and may also participate
803
    /// as one item within a sequence value.
804
    /// </summary>
805
    /// <remarks>
806
    /// <para>An <c>XdmNode</c> is implemented as a wrapper around an object
807
    /// of type <c>net.sf.saxon.NodeInfo</c>. Because this is a key interface
808
    /// within Saxon, it is exposed via this API, even though it is a Java
809
    /// interface that is not part of the API proper.</para>
810
    /// <para>The <c>XdmNode</c> interface exposes basic properties of the node, such
811
    /// as its name, its string value, and its typed value. Navigation to other nodes
812
    /// is supported through a single method, <c>EnumerateAxis</c>, which allows
813
    /// other nodes to be retrieved by following any of the XPath axes.</para>
814
    /// </remarks>
815

    
816
    [Serializable]
817
    public class XdmNode : XdmItem
818
    {
819

    
820
        /// <summary>
821
        /// Determine whether the item is an atomic value
822
        /// </summary>
823
        /// <returns>
824
        /// false (the item is not an atomic value)
825
        /// </returns>
826

    
827
        public override bool IsAtomic()
828
        {
829
            return false;
830
        }
831

    
832
        /// <summary>
833
        /// The name of the node, as a <c>QName</c>. Returns null in the case of unnamed nodes.
834
        /// </summary>
835

    
836
        public QName NodeName
837
        {
838
            get
839
            {
840
                NodeInfo node = (NodeInfo)value;
841
                String local = node.getLocalPart();
842
                if (local == "")
843
                {
844
                    return null;
845
                }
846
                String prefix = node.getPrefix();
847
                String uri = node.getURI();
848
                return new QName(prefix, uri, local);
849
            }
850
        }
851

    
852
        /// <summary>
853
        /// The kind of node, as an instance of <c>System.Xml.XmlNodeType</c>.
854
        /// </summary>
855
        /// <remarks>For a namespace node in the XDM model, the value XmlNodeType.None 
856
        /// is returned.
857
        /// </remarks>
858

    
859
        public XmlNodeType NodeKind
860
        {
861
            get
862
            {
863
                NodeInfo node = (NodeInfo)value;
864
                int kind = node.getNodeKind();
865
                switch (kind)
866
                {
867
                    case JType.DOCUMENT:
868
                        return XmlNodeType.Document;
869
                    case JType.ELEMENT:
870
                        return XmlNodeType.Element;
871
                    case JType.ATTRIBUTE:
872
                        return XmlNodeType.Attribute;
873
                    case JType.TEXT:
874
                        return XmlNodeType.Text;
875
                    case JType.COMMENT:
876
                        return XmlNodeType.Comment;
877
                    case JType.PROCESSING_INSTRUCTION:
878
                        return XmlNodeType.ProcessingInstruction;
879
                    case JType.NAMESPACE:
880
                        return XmlNodeType.None;
881
                    default:
882
                        throw new ArgumentException("Unknown node kind");
883
                }
884
            }
885
        }
886

    
887
        /// <summary>
888
        /// The typed value of the node, as an instance of <c>XdmValue</c>.
889
        /// </summary>
890
        /// <exception>
891
        /// A DynamicError is thrown if the node has no typed value, as will be the case for
892
        /// an element with element-only content.
893
        /// </exception>
894

    
895
        public XdmValue TypedValue
896
        {
897
            get { return XdmValue.Wrap(((NodeInfo)value).atomize()); }
898
        }
899

    
900
        /// <summary>
901
        /// Unwraps the underlying XmlNode object from the XdmValue.
902
        /// If the method does not wrap a XmlNode then a null is returned
903
        /// </summary>
904
        /// <returns>The underlying XmlNode</returns>
905
        public XmlNode getUnderlyingXmlNode()
906
        {
907

    
908
            if (value is net.sf.saxon.dotnet.DotNetNodeWrapper)
909
            {
910

    
911
                return (XmlNode)((net.sf.saxon.dotnet.DotNetNodeWrapper)value).getRealNode();
912
            }
913
            return null;
914
        }
915

    
916
        /// <summary>
917
        /// The string value of the node.
918
        /// </summary>
919

    
920
        public String StringValue
921
        {
922
            get { return ((NodeInfo)value).getStringValue(); }
923
        }
924

    
925
        /// <summary>
926
        /// Get the parent of this node.
927
        /// </summary>
928
        /// <remarks>
929
        /// Returns either a document node, and element node, or null in the case where
930
        /// this node has no parent. 
931
        /// </remarks>
932

    
933
        public XdmNode Parent
934
        {
935
            get {
936
                NodeInfo parent = ((NodeInfo)value).getParent();
937
                return (parent == null ? null : (XdmNode)XdmValue.Wrap(parent)); 
938
            }
939
        }
940

    
941
        /// <summary>
942
        /// Get the root of the tree containing this node.
943
        /// </summary>
944
        /// <remarks>
945
        /// Returns the root of the tree containing this node (which might be this node itself).
946
        /// </remarks>
947

    
948
        public XdmNode Root
949
        {
950
            get
951
            {
952
                XdmNode parent = Parent;
953
                if (parent == null)
954
                {
955
                    return this;
956
                }
957
                else
958
                {
959
                    return parent.Root;
960
                }
961
            }
962
        }
963

    
964
        /// <summary>
965
        /// Get a the string value of a named attribute of this element. 
966
        /// </summary>
967
        /// <remarks>
968
        /// Returns null if this node is not an element, or if this element has no
969
        /// attribute with the specified name.
970
        /// </remarks>
971
        /// <param name="name">The name of the attribute whose value is required</param>
972

    
973
        public String GetAttributeValue(QName name)
974
        {
975
            return ((NodeInfo)value).getAttributeValue(name.Uri, name.LocalName);
976
        }
977

    
978
        /// <summary>
979
        /// Get an enumerator that supplies all the nodes on one of the XPath
980
        /// axes, starting with this node.
981
        /// </summary>
982
        /// <param name="axis">
983
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child AxisInfo.
984
        /// </param>
985
        /// <remarks>
986
        /// The nodes are returned in axis order: that is, document order for a forwards
987
        /// axis, reverse document order for a reverse AxisInfo.
988
        /// </remarks>
989

    
990
        public IEnumerator EnumerateAxis(XdmAxis axis)
991
        {
992
            return new SequenceEnumerator(((NodeInfo)value).iterateAxis(GetAxisNumber(axis)));
993
        }
994

    
995
        /// <summary>
996
        /// Get an enumerator that selects all the nodes on one of the XPath
997
        /// axes, provided they have a given name. The nodes selected are those of the principal
998
        /// node kind (elements for most axes, attributes for the attribute axis, namespace nodes
999
        /// for the namespace axis) whose name matches the name given in the second argument.
1000
        /// </summary>
1001
        /// <param name="axis">
1002
        /// The axis to be navigated, for example <c>XdmAxis.Child</c> for the child AxisInfo.
1003
        /// </param>
1004
        /// <param name="nodeName">
1005
        /// The name of the required nodes, for example <c>new QName("", "item")</c> to select
1006
        /// nodes with local name "item", in no namespace.
1007
        /// </param>
1008
        /// <remarks>
1009
        /// The nodes are returned in axis order: that is, document order for a forwards
1010
        /// axis, reverse document order for a reverse AxisInfo.
1011
        /// </remarks>
1012

    
1013
        public IEnumerator EnumerateAxis(XdmAxis axis, QName nodeName)
1014
        {
1015
            int kind;
1016
            switch (axis)
1017
            {
1018
                case XdmAxis.Attribute:
1019
                    kind = net.sf.saxon.type.Type.ATTRIBUTE;
1020
                    break;
1021
                case XdmAxis.Namespace:
1022
                    kind = net.sf.saxon.type.Type.NAMESPACE;
1023
                    break;
1024
                default:
1025
                    kind = net.sf.saxon.type.Type.ELEMENT;
1026
                    break;
1027
            }
1028
            NamePool pool = ((NodeInfo)value).getConfiguration().getNamePool();
1029
            int nameCode = pool.allocate("", nodeName.Uri, nodeName.LocalName);
1030
            NameTest test = new NameTest(kind, nameCode, pool);
1031
            return new SequenceEnumerator(((NodeInfo)value).iterateAxis(GetAxisNumber(axis), test));
1032
        }
1033

    
1034
        private static byte GetAxisNumber(XdmAxis axis)
1035
        {
1036
            switch (axis)
1037
            {
1038
                case XdmAxis.Ancestor: return AxisInfo.ANCESTOR;
1039
                case XdmAxis.AncestorOrSelf: return AxisInfo.ANCESTOR_OR_SELF;
1040
                case XdmAxis.Attribute: return AxisInfo.ATTRIBUTE;
1041
                case XdmAxis.Child: return AxisInfo.CHILD;
1042
                case XdmAxis.Descendant: return AxisInfo.DESCENDANT;
1043
                case XdmAxis.DescendantOrSelf: return AxisInfo.DESCENDANT_OR_SELF;
1044
                case XdmAxis.Following: return AxisInfo.FOLLOWING;
1045
                case XdmAxis.FollowingSibling: return AxisInfo.FOLLOWING_SIBLING;
1046
                case XdmAxis.Namespace: return AxisInfo.NAMESPACE;
1047
                case XdmAxis.Parent: return AxisInfo.PARENT;
1048
                case XdmAxis.Preceding: return AxisInfo.PRECEDING;
1049
                case XdmAxis.PrecedingSibling: return AxisInfo.PRECEDING_SIBLING;
1050
                case XdmAxis.Self: return AxisInfo.SELF;
1051
            }
1052
            return 0;
1053
        }
1054

    
1055
        /// <summary>
1056
        /// The Base URI of the node.
1057
        /// </summary>
1058

    
1059
        public Uri BaseUri
1060
        {
1061
            get { 
1062
				string baseUriStr = ((NodeInfo)value).getBaseURI();
1063
				if (baseUriStr == null || baseUriStr.Equals("")) {
1064
					return null;
1065
				}
1066
				return new Uri(baseUriStr); 
1067
			}
1068
        }
1069

    
1070
        /// <summary>
1071
        /// The Document URI of the node.
1072
        /// </summary>
1073

    
1074
        public Uri DocumentUri
1075
        {
1076
            get
1077
            {
1078
                String s = ((NodeInfo)value).getSystemId();
1079
                if (s == null || s.Length == 0)
1080
                {
1081
                    return null;
1082
                }
1083
                return new Uri(s);
1084
            }
1085
        }
1086

    
1087
        /// <summary>
1088
        /// Send the node (that is, the subtree rooted at this node) to an <c>XmlWriter</c>
1089
        /// </summary>
1090
        /// <remarks>
1091
        /// Note that a <c>XmlWriter</c> can only handle a well-formed XML document. This method
1092
        /// will therefore signal an exception if the node is a document node with no children, or with
1093
        /// more than one element child.
1094
        /// </remarks>
1095
        /// <param name="writer">
1096
        /// The <c>XmlWriter</c> to which the node is to be written
1097
        /// </param>
1098

    
1099
        public void WriteTo(XmlWriter writer)
1100
        {
1101
            NodeInfo node = ((NodeInfo)value);
1102
            DotNetReceiver receiver = new DotNetReceiver(writer);
1103
            receiver.setPipelineConfiguration(node.getConfiguration().makePipelineConfiguration());
1104
            receiver.open();
1105
            node.copy(receiver, net.sf.saxon.om.CopyOptions.ALL_NAMESPACES, 0);
1106
            receiver.close();
1107
        }
1108

    
1109
        /// <summary>
1110
        /// Return a serialization of this node as lexical XML
1111
        /// </summary>
1112
        /// <remarks>
1113
        /// <para>In the case of an element node, the result will be a well-formed
1114
        /// XML document serialized as defined in the W3C XSLT/XQuery serialization specification,
1115
        /// using options method="xml", indent="yes", omit-xml-declaration="yes".</para>
1116
        /// <para>In the case of a document node, the result will be a well-formed
1117
        /// XML document provided that the document node contains exactly one element child,
1118
        /// and no text node children. In other cases it will be a well-formed external
1119
        /// general parsed entity.</para>
1120
        /// <para>In the case of an attribute node, the output is a string in the form
1121
        /// <c>name="value"</c>. The name will use the original namespace prefix.</para>
1122
        /// <para>Other nodes, such as text nodes, comments, and processing instructions, are
1123
        /// represented as they would appear in lexical XML.</para>
1124
        /// </remarks>
1125

    
1126
        public String OuterXml
1127
        {
1128
            get
1129
            {
1130
                NodeInfo node = ((NodeInfo)value);
1131

    
1132
                if (node.getNodeKind() == JType.ATTRIBUTE)
1133
                {
1134
                    String val = node.getStringValue().Replace("\"", "&quot;");
1135
                    val = val.Replace("<", "&lt;");
1136
                    val = val.Replace("&", "&amp;");
1137
                    return node.getDisplayName() + "=\"" + val + '"';
1138
                }
1139

    
1140
                Serializer serializer = new Serializer();
1141
                serializer.SetOutputProperty(Serializer.METHOD, "xml");
1142
                serializer.SetOutputProperty(Serializer.INDENT, "yes");
1143
                serializer.SetOutputProperty(Serializer.OMIT_XML_DECLARATION, "yes");
1144

    
1145
                StringWriter sw = new StringWriter();
1146
                serializer.SetOutputWriter(sw);
1147
                node.copy(serializer.GetReceiver(node.getConfiguration()), net.sf.saxon.om.CopyOptions.ALL_NAMESPACES, 0);
1148
                return sw.ToString();
1149
            }
1150
        }
1151

    
1152
        /// <summary>
1153
        /// Two instances of XdmNode are equal if they represent the same node. That is, the Equals()
1154
        /// method returns the same result as the XPath "is" operator.
1155
        /// </summary>
1156
        /// <param name="obj">The object node to be compared</param>
1157
         
1158
        public override bool Equals(object obj)
1159
        {
1160
            return obj is XdmNode && ((NodeInfo)value).equals((NodeInfo)((XdmNode)obj).value);
1161
        }
1162

    
1163
        /// <summary>
1164
        /// The hashCode of a node reflects the equality relationship: if two XdmNode instances
1165
        /// represent the same node, then they have the same hashCode
1166
        /// </summary>
1167

    
1168
        public override int GetHashCode()
1169
        {
1170
            return ((NodeInfo)value).hashCode();
1171
        }
1172

    
1173
        /// <summary>
1174
        /// Return a string representation of the node.
1175
        /// </summary>
1176
        /// <remarks>
1177
        /// This currently returns the same as the <c>OuterXml</c> property.
1178
        /// To get the string value as defined in XPath, use the <c>StringValue</c> property.
1179
        /// </remarks>
1180

    
1181
        public override String ToString()
1182
        {
1183
            return OuterXml;
1184
        }
1185

    
1186
        /// <summary>
1187
        /// Escape hatch to the underlying class in the Java implementation
1188
        /// </summary>
1189

    
1190
        public NodeInfo Implementation
1191
        {
1192
            get { return ((NodeInfo)value); }
1193
        }
1194

    
1195

    
1196
    }
1197

    
1198

    
1199
    /// <summary inherits="XdmValue">
1200
    /// The class <c>XdmEmptySequence</c> represents an empty sequence in the XDM Data Model.
1201
    /// </summary>
1202
    /// <remarks>
1203
    /// <para>An empty sequence <i>may</i> also be represented by an <c>XdmValue</c> whose length
1204
    /// happens to be zero. Applications should therefore not test to see whether an object
1205
    /// is an instance of this class in order to decide whether it is empty.</para>
1206
    /// <para>In interfaces that expect an <c>XdmItem</c>, an empty sequence is represented
1207
    /// by a CLI <c>null</c> value.</para> 
1208
    /// </remarks>
1209

    
1210
    [Serializable]
1211
    public sealed class XdmEmptySequence : XdmValue
1212
    {
1213

    
1214
        ///<summary>The singular instance of this class</summary>
1215

    
1216
        public static XdmEmptySequence INSTANCE = new XdmEmptySequence();
1217

    
1218
        private XdmEmptySequence()
1219
        {
1220
            this.value = JEmptySequence.getInstance();
1221
        }
1222
    }
1223

    
1224

    
1225
    /// <summary>
1226
    /// The QName class represents an instance of xs:QName, as defined in the XPath 2.0
1227
    /// data model. Internally, it has three components, a namespace URI, a local name, and
1228
    /// a prefix. The prefix is intended to be used only when converting the value back to 
1229
    /// a string.
1230
    /// </summary>
1231
    /// <remarks>
1232
    /// Note that a QName is not itself an <c>XdmItem</c> in this model; however it can
1233
    /// be wrapped in an XdmItem.
1234
    /// </remarks>    
1235

    
1236
    [Serializable]
1237
    public sealed class QName
1238
    {
1239

    
1240
        private String prefix;
1241
        private String uri;
1242
        private String local;
1243
        int hashcode = -1;      // evaluated lazily
1244
        int fingerprint = -1;   // evaluated only if the QName is registered with the Processor
1245
        private NamePool pool = null;
1246

    
1247
        private static String XS = NamespaceConstant.SCHEMA;
1248

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

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

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

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

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

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

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

    
1270
        /// <summary>QName constant for the name xs:QName</summary>
1271
        public static readonly QName XS_QNAME = new QName(XS, "xs:QName");
1272

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

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

    
1279
        /// <summary>
1280
        /// Construct a QName representing a name in no namespace
1281
        /// </summary>
1282
        /// <remarks>
1283
        /// This constructor does not check that the components of the QName are
1284
        /// lexically valid.
1285
        /// </remarks>
1286
        /// <param name="local">The local part of the name
1287
        /// </param>
1288

    
1289
        public QName(String local)
1290
        {
1291
            // TODO: check for validity
1292
            this.prefix = String.Empty;
1293
            this.uri = String.Empty;
1294
            this.local = local;
1295
        }
1296

    
1297
        /// <summary>
1298
        /// Construct a QName using a namespace URI and a lexical representation.
1299
        /// The lexical representation may be a local name on its own, or it may 
1300
        /// be in the form <c>prefix:local-name</c>
1301
        /// </summary>
1302
        /// <remarks>
1303
        /// This constructor does not check that the components of the QName are
1304
        /// lexically valid.
1305
        /// </remarks>
1306
        /// <param name="uri">The namespace URI. Use either the string "" or null
1307
        /// for names that are not in any namespace.
1308
        /// </param>
1309
        /// <param name="lexical">Either the local part of the name, or the prefix
1310
        /// and local part in the format <c>prefix:local</c>
1311
        /// </param>
1312

    
1313
        public QName(String uri, String lexical)
1314
        {
1315
            // TODO: check for validity
1316
            this.uri = (uri == null ? "" : uri);
1317
            int colon = lexical.IndexOf(':');
1318
            if (colon < 0)
1319
            {
1320
                this.prefix = String.Empty;
1321
                this.local = lexical;
1322
            }
1323
            else
1324
            {
1325
                this.prefix = lexical.Substring(0, colon);
1326
                this.local = lexical.Substring(colon + 1);
1327
            }
1328
        }
1329

    
1330
        /// <summary>
1331
        /// Construct a QName using a namespace prefix, a namespace URI, and a local name
1332
        /// (in that order).
1333
        /// </summary>
1334
        /// <remarks>
1335
        /// This constructor does not check that the components of the QName are
1336
        /// lexically valid.
1337
        /// </remarks>
1338
        /// <param name="prefix">The prefix of the name. Use either the string ""
1339
        /// or null for names that have no prefix (that is, they are in the default
1340
        /// namespace)</param>
1341
        /// <param name="uri">The namespace URI. Use either the string "" or null
1342
        /// for names that are not in any namespace.
1343
        /// </param>
1344
        /// <param name="local">The local part of the name</param>
1345

    
1346
        public QName(String prefix, String uri, String local)
1347
        {
1348
            this.uri = (uri == null ? String.Empty : uri);
1349
            this.local = local;
1350
            this.prefix = (prefix == null ? String.Empty : prefix);
1351
        }
1352

    
1353
        /// <summary>
1354
        /// Construct a QName from a lexical QName, supplying an element node whose
1355
        /// in-scope namespaces are to be used to resolve any prefix contained in the QName.
1356
        /// </summary>
1357
        /// <remarks>
1358
        /// <para>This constructor checks that the components of the QName are
1359
        /// lexically valid.</para>
1360
        /// <para>If the lexical QName has no prefix, the name is considered to be in the
1361
        /// default namespace, as defined by <c>xmlns="..."</c>.</para>
1362
        /// <para>If the prefix of the lexical QName is not in scope, returns null.</para>
1363
        /// </remarks>
1364
        /// <param name="lexicalQName">The lexical QName, in the form <code>prefix:local</code>
1365
        /// or simply <c>local</c>.</param>
1366
        /// <param name="element">The element node whose in-scope namespaces are to be used
1367
        /// to resolve the prefix part of the lexical QName.</param>
1368
        /// <exception cref="ArgumentException">If the prefix of the lexical QName is not in scope</exception>
1369
        /// <exception cref="ArgumentException">If the lexical QName is invalid 
1370
        /// (for example, if it contains invalid characters)</exception>
1371
        /// 
1372

    
1373
        public QName(String lexicalQName, XdmNode element)
1374
        {
1375
            try
1376
            {
1377
                NodeInfo node = (NodeInfo)element.value;
1378
                NamePool pool = node.getConfiguration().getNamePool();
1379
                int nc = pool.allocateLexicalQName(lexicalQName, true, new InscopeNamespaceResolver(node));
1380
                this.uri = pool.getURI(nc);
1381
                this.local = pool.getLocalName(nc);
1382
                this.prefix = pool.getPrefix(nc);
1383
            }
1384
            catch (net.sf.saxon.trans.XPathException err)
1385
            {
1386
                throw new ArgumentException(err.getMessage());
1387
            }
1388
        }
1389

    
1390
        /// <summary>
1391
        /// Construct a <c>QName</c> from an <c>XmlQualifiedName</c> (as defined in the
1392
        /// <c>System.Xml</c> package).
1393
        /// </summary>
1394
        /// <remarks>
1395
        /// Note that an <c>XmlQualifiedName</c> does not contain any prefix, so the result
1396
        /// will always have a prefix of ""
1397
        /// </remarks>
1398
        /// <param name="qualifiedName">The XmlQualifiedName</param>
1399

    
1400
        public QName(XmlQualifiedName qualifiedName)
1401
        {
1402
            this.uri = qualifiedName.Namespace;
1403
            this.local = qualifiedName.Name;
1404
            this.prefix = String.Empty;
1405
        }
1406

    
1407
        //  internal constructor from a QNameValue
1408

    
1409
        internal QName(QNameValue q)
1410
        {
1411
            this.uri = q.getNamespaceURI();
1412
            this.prefix = q.getPrefix();
1413
            this.local = q.getLocalName();
1414
        }
1415

    
1416
        /// <summary>
1417
        /// Factory method to construct a QName from a string containing the expanded
1418
        /// QName in Clark notation, that is, <c>{uri}local</c>
1419
        /// </summary>
1420
        /// <remarks>
1421
        /// The prefix part of the <c>QName</c> will be set to an empty string.
1422
        /// </remarks>
1423
        /// <param name="expandedName">The URI in Clark notation: <c>{uri}local</c> if the
1424
        /// name is in a namespace, or simply <c>local</c> if not.</param> 
1425

    
1426
        public static QName FromClarkName(String expandedName)
1427
        {
1428
            String namespaceURI;
1429
            String localName;
1430
            if (expandedName[0] == '{')
1431
            {
1432
                int closeBrace = expandedName.IndexOf('}');
1433
                if (closeBrace < 0)
1434
                {
1435
                    throw new ArgumentException("No closing '}' in Clark name");
1436
                }
1437
                namespaceURI = expandedName.Substring(1, closeBrace - 1);
1438
                if (closeBrace == expandedName.Length)
1439
                {
1440
                    throw new ArgumentException("Missing local part in Clark name");
1441
                }
1442
                localName = expandedName.Substring(closeBrace + 1);
1443
            }
1444
            else
1445
            {
1446
                namespaceURI = "";
1447
                localName = expandedName;
1448
            }
1449

    
1450
            return new QName("", namespaceURI, localName);
1451
        }
1452

    
1453

    
1454
       /// <summary>
1455
       ///Factory method to construct a QName from a string containing the expanded
1456
       ///QName in EQName notation, that is, <c>Q{uri}local</c>
1457
       /// </summary>
1458
       /// <remarks>
1459
       ///The prefix part of the <c>QName</c> will be set to an empty string.
1460
       /// </remarks>
1461
       /// <param name="expandedName">The URI in EQName notation: <c>{uri}local</c> if the
1462
       /// name is in a namespace. For a name in no namespace, either of the
1463
       /// forms <c>Q{}local</c> or simply <c>local</c> are accepted.</param>
1464
       ///<returns> the QName corresponding to the supplied name in EQName notation. This will always
1465
       ///have an empty prefix.</returns>
1466
       
1467
        public static QName FromEQName(String expandedName)
1468
        {
1469
            String namespaceURI;
1470
            String localName;
1471
            if (expandedName[0] == 'Q' && expandedName[1] == '{')
1472
            {
1473
                int closeBrace = expandedName.IndexOf('}');
1474
                if (closeBrace < 0)
1475
                {
1476
                    throw new ArgumentException("No closing '}' in EQName");
1477
                }
1478
                namespaceURI = expandedName.Substring(2, closeBrace);
1479
                if (closeBrace == expandedName.Length)
1480
                {
1481
                    throw new ArgumentException("Missing local part in EQName");
1482
                }
1483
                localName = expandedName.Substring(closeBrace + 1);
1484
            }
1485
            else
1486
            {
1487
                namespaceURI = "";
1488
                localName = expandedName;
1489
            }
1490

    
1491
            return new QName("", namespaceURI, localName);
1492
        }
1493

    
1494
        /// <summary>
1495
        /// Factory method to construct a QName from Saxon's internal <c>StructuredQName</c>
1496
        /// representation.
1497
        /// </summary>
1498

    
1499
        internal static QName FromStructuredQName(StructuredQName sqn) {
1500
            return new QName(sqn.getPrefix(), sqn.getURI(), sqn.getLocalPart());
1501
        }
1502

    
1503
        /// <summary>
1504
        /// Register a QName with the <c>Processor</c>. This makes comparison faster
1505
        /// when the QName is compared with others that are also registered with the <c>Processor</c>.
1506
        /// </summary>
1507
        /// <remarks>
1508
        /// A given <c>QName</c> object can only be registered with one <c>Processor</c>.
1509
        /// </remarks>
1510
        /// <param name="processor">The Processor in which the name is to be registered.</param>
1511

    
1512
        public void Register(Processor processor)
1513
        {
1514
			if (pool != null && pool != processor.Implementation.getNamePool())
1515
            {
1516
                throw new InvalidOperationException("A QName cannot be registered with more than one Processor");
1517
            }
1518
			pool = processor.Implementation.getNamePool();
1519
            fingerprint = pool.allocate(prefix, uri, local) & 0xfffff;
1520
        }
1521

    
1522
        /// <summary>
1523
        /// Validate the QName against the XML 1.0 or XML 1.1 rules for valid names.
1524
        /// </summary>
1525
        /// <param name="processor">The Processor in which the name is to be validated.
1526
        /// This determines whether the XML 1.0 or XML 1.1 rules for forming names are used.</param>
1527
        /// <returns>true if the name is valid, false if not</returns>
1528

    
1529
        public bool IsValid(Processor processor)
1530
        {
1531
            if (prefix != String.Empty)
1532
            {
1533
                if (!NameChecker.isValidNCName(prefix))
1534
                {
1535
                    return false;
1536
                }
1537
            }
1538
            if (!NameChecker.isValidNCName(local))
1539
            {
1540
                return false;
1541
            }
1542
            return true;
1543
        }
1544

    
1545
        /// <summary>The prefix of the QName. This plays no role in operations such as comparison
1546
        /// of QNames for equality, but is retained (as specified in XPath) so that a string representation
1547
        /// can be reconstructed.
1548
        /// </summary>
1549
        /// <remarks>
1550
        /// Returns the zero-length string in the case of a QName that has no prefix.
1551
        /// </remarks>
1552

    
1553
        public String Prefix
1554
        {
1555
            get { return prefix; }
1556
        }
1557

    
1558
        /// <summary>The namespace URI of the QName. Returns "" (the zero-length string) if the
1559
        /// QName is not in a namespace.
1560
        /// </summary>
1561

    
1562
        public String Uri
1563
        {
1564
            get { return uri; }
1565
        }
1566

    
1567
        /// <summary>The local part of the QName</summary>
1568

    
1569
        public String LocalName
1570
        {
1571
            get { return local; }
1572
        }
1573

    
1574
        /// <summary>The expanded name, as a string using the notation devised by James Clark.
1575
        /// If the name is in a namespace, the resulting string takes the form <c>{uri}local</c>.
1576
        /// Otherwise, the value is the local part of the name.
1577
        /// </summary>
1578

    
1579
        public String ClarkName
1580
        {
1581
            get
1582
            {
1583
                if (uri == "")
1584
                {
1585
                    return local;
1586
                }
1587
                else
1588
                {
1589
                    return "{" + uri + "}" + local;
1590
                }
1591
            }
1592
        }
1593

    
1594
        /// <summary>
1595
        /// Convert the value to a string. The resulting string is the lexical form of the QName,
1596
        /// using the original prefix if there was one.
1597
        /// </summary>
1598

    
1599
        public override String ToString()
1600
        {
1601
            if (prefix == "")
1602
            {
1603
                return local;
1604
            }
1605
            else
1606
            {
1607
				return prefix + ":" + LocalName;
1608
            }
1609
        }
1610

    
1611
        /// <summary>
1612
        /// Get a hash code for the QName, to support equality matching. This supports the
1613
        /// semantics of equality, which considers only the namespace URI and local name, and
1614
        /// not the prefix.
1615
        /// </summary>
1616
        /// <remarks>
1617
        /// The algorithm for allocating a hash code does not depend on registering the QName 
1618
        /// with the <c>Processor</c>.
1619
        /// </remarks>
1620

    
1621
        public override int GetHashCode()
1622
        {
1623
            if (hashcode == -1)
1624
            {
1625
                hashcode = ClarkName.GetHashCode();
1626
            }
1627
            return hashcode;
1628
        }
1629

    
1630
        /// <summary>
1631
        /// Test whether two QNames are equal. This supports the
1632
        /// semantics of equality, which considers only the namespace URI and local name, and
1633
        /// not the prefix.
1634
        /// </summary>
1635
        /// <remarks>
1636
        /// The result of the function does not depend on registering the QName 
1637
        /// with the <c>Processor</c>, but is computed more quickly if the QNames have
1638
        /// both been registered
1639
        /// </remarks>
1640
        /// <param name="other">The value to be compared with this QName. If this value is not a QName, the
1641
        /// result is always false. Otherwise, it is true if the namespace URI and local name both match.</param>
1642

    
1643
        public override bool Equals(Object other)
1644
        {
1645
            if (!(other is QName))
1646
            {
1647
                return false;
1648
            }
1649
            if (pool != null && pool == ((QName)other).pool)
1650
            {
1651
                return fingerprint == ((QName)other).fingerprint;
1652
            }
1653
            if (GetHashCode() != ((QName)other).GetHashCode())
1654
            {
1655
                return false;
1656
            }
1657
            return ClarkName == ((QName)other).ClarkName;
1658
            //TODO: avoid computing ClarkName more than once
1659
        }
1660

    
1661
        /// <summary>
1662
        /// Convert the value to an <c>XmlQualifiedName</c> (as defined in the
1663
        /// <c>System.Xml</c> package)
1664
        /// </summary>
1665
        /// <remarks>
1666
        /// Note that this loses the prefix.
1667
        /// </remarks>
1668

    
1669
        public XmlQualifiedName ToXmlQualifiedName()
1670
        {
1671
            return new XmlQualifiedName(local, uri);
1672
        }
1673

    
1674
        /// <summary>
1675
        /// Convert to a net.sf.saxon.value.QNameValue
1676
        /// </summary>
1677

    
1678
        internal QNameValue ToQNameValue()
1679
        {
1680
            return new QNameValue(prefix, uri, local, null);
1681
        }
1682

    
1683
        internal JStructuredQName ToStructuredQName()
1684
        {
1685
            return new JStructuredQName(Prefix, Uri, LocalName);
1686
        }
1687

    
1688
        /// <summary>
1689
        /// Get the internal Saxon fingerprint of this name
1690
        /// </summary>
1691
        /// <param name="config">The Saxon configuration (the fingerprint for a QName is different in different configurations)</param>
1692
        /// <returns>
1693
        /// The integer fingerprint of the name
1694
        /// </returns>
1695

    
1696
        internal int GetFingerprint(JConfiguration config)
1697
        {
1698
            JNamePool namePool = config.getNamePool();
1699
            if (fingerprint != -1 && pool == namePool)
1700
            {
1701
                return fingerprint;
1702
            }
1703
            return namePool.allocate(prefix, uri, local) & 0xfffff;
1704
        }
1705

    
1706

    
1707

    
1708
    }
1709

    
1710
    /// <summary>
1711
    /// This class represents an enumeration of the values in an XPath
1712
    /// sequence. It implements the IEnumerator interface, and the objects
1713
    /// returned are always instances of <c>XdmItem</c>. In addition to the
1714
    /// methods defined by <c>IEnumerator</c>, an additional method <c>GetAnother</c>
1715
    /// must be implemented: this provides a new iterator over the same sequence
1716
    /// of items, positioned at the start of the sequence.
1717
    /// </summary>
1718
    /// <remarks>
1719
    /// Because the underlying value can be evaluated lazily, it is possible
1720
    /// for exceptions to occur as the sequence is being read.
1721
    /// </remarks>
1722

    
1723
    public interface IXdmEnumerator : IEnumerator
1724
    {
1725

    
1726
        /// <summary>
1727
        /// Create another <c>XdmEnumerator</c> over the same sequence of values, positioned at the start
1728
        /// of the sequence, with no change to this <c>XdmEnumerator</c>.
1729
        /// </summary>
1730
        /// <returns>
1731
        /// A new XdmEnumerator over the same sequence of XDM items, positioned at the start of the sequence.
1732
        /// </returns>
1733

    
1734
        /**public**/ IXdmEnumerator GetAnother();
1735
    }
1736

    
1737
    /// <summary>
1738
    /// This class is an implementation of <c>IXdmEnumerator</c> that wraps
1739
    /// a (Java) SequenceIterator.
1740
    /// </summary>
1741
    /// <remarks>
1742
    /// Because the underlying value can be evaluated lazily, it is possible
1743
    /// for exceptions to occur as the sequence is being read.
1744
    /// </remarks>
1745

    
1746
    [Serializable]
1747
    internal class SequenceEnumerator : IXdmEnumerator
1748
    {
1749

    
1750
        private SequenceIterator iter;
1751
		private Item current;
1752

    
1753
        internal SequenceEnumerator(SequenceIterator iter)
1754
        {
1755
            this.iter = iter;
1756
			current = null;
1757
        }
1758

    
1759
        /// <summary>Return the current item in the sequence</summary>
1760
        /// <returns>An object which will always be an instance of <c>XdmItem</c></returns>
1761

    
1762
        public object Current
1763
        {
1764
			get { return XdmValue.Wrap(current); }
1765
        }
1766

    
1767
        /// <summary>Move to the next item in the sequence</summary>
1768
        /// <returns>true if there are more items in the sequence</returns>
1769

    
1770
        public bool MoveNext()
1771
        {
1772
			Item nextItem = iter.next ();
1773
			current = nextItem;
1774
			return (nextItem != null);
1775
        }
1776

    
1777
        /// <summary>Reset the enumeration so that the next call of
1778
        /// <c>MoveNext</c> will position the enumeration at the
1779
        /// first item in the sequence</summary>
1780

    
1781
        public void Reset()
1782
        {
1783
            iter = iter.getAnother();
1784
        }
1785

    
1786
        /// <summary>
1787
        /// Create another XdmEnumerator over the same sequence of values, positioned at the start
1788
        /// of the sequence, with no change to this XdmEnumerator.
1789
        /// </summary>
1790
        /// <returns>
1791
        /// A new XdmEnumerator over the same sequence of XDM items, positioned at the start of the sequence.
1792
        /// </returns>
1793

    
1794
        public IXdmEnumerator GetAnother()
1795
        {
1796
            return new SequenceEnumerator(iter.getAnother());
1797
        }
1798
    }
1799

    
1800
    /// <summary>
1801
    /// Implementation of the (Java) interface SequenceIterator that wraps
1802
    /// a (.NET) IXdmEnumerator
1803
    /// </summary>
1804

    
1805
    internal class DotNetSequenceIterator : JSequenceIterator
1806
    {
1807
        // TODO: catch errors and throw an XPathException if necessary.
1808

    
1809
        IXdmEnumerator iter;
1810
        int pos = 0;
1811

    
1812
        public DotNetSequenceIterator(IXdmEnumerator iter)
1813
        {
1814
            this.iter = iter;
1815
        }
1816

    
1817
        public JItem next()
1818
        {
1819
            if (pos < 0)
1820
            {
1821
                return null;
1822
            }
1823
            bool more = iter.MoveNext();
1824
            if (more)
1825
            {
1826
                pos++;
1827
                XdmItem i = (XdmItem)iter.Current;
1828
                return (JItem)i.Unwrap();
1829
            }
1830
            else
1831
            {
1832
                pos = -1;
1833
                return null;
1834
            }
1835

    
1836
        }
1837

    
1838
        public JItem current()
1839
        {
1840
            if (pos < 0)
1841
            {
1842
                return null;
1843
            }
1844
            XdmItem i = (XdmItem)iter.Current;
1845
            return (JItem)i.Unwrap();
1846
        }
1847

    
1848
        public int position()
1849
        {
1850
            return pos;
1851
        }
1852

    
1853
        public void close()
1854
        {
1855
        }
1856

    
1857
        public SequenceIterator getAnother()
1858
        {
1859
            return new DotNetSequenceIterator(iter.GetAnother());
1860
        }
1861

    
1862
        public int getProperties()
1863
        {
1864
            return 0;
1865
        }
1866
    }
1867

    
1868
    /// <summary>
1869
    /// Enumeration identifying the thirteen XPath axes
1870
    /// </summary>
1871

    
1872
    public enum XdmAxis
1873
    {
1874
        /// <summary>The XPath ancestor axis</summary> 
1875
        Ancestor,
1876
        /// <summary>The XPath ancestor-or-self axis</summary> 
1877
        AncestorOrSelf,
1878
        /// <summary>The XPath attribute axis</summary> 
1879
        Attribute,
1880
        /// <summary>The XPath child axis</summary> 
1881
        Child,
1882
        /// <summary>The XPath descendant axis</summary> 
1883
        Descendant,
1884
        /// <summary>The XPath descandant-or-self axis</summary> 
1885
        DescendantOrSelf,
1886
        /// <summary>The XPath following axis</summary> 
1887
        Following,
1888
        /// <summary>The XPath following-sibling axis</summary> 
1889
        FollowingSibling,
1890
        /// <summary>The XPath namespace axis</summary> 
1891
        Namespace,
1892
        /// <summary>The XPath parent axis</summary> 
1893
        Parent,
1894
        /// <summary>The XPath preceding axis</summary> 
1895
        Preceding,
1896
        /// <summary>The XPath preceding-sibling axis</summary> 
1897
        PrecedingSibling,
1898
        /// <summary>The XPath self axis</summary> 
1899
        Self
1900
    }
1901

    
1902
    /// <summary>
1903
    /// An implementation of <code>IXdmEnumerator</code> that iterates over an empty sequence.
1904
    /// </summary>
1905

    
1906
    public class EmptyEnumerator : IXdmEnumerator
1907
    {
1908

    
1909
        public static EmptyEnumerator INSTANCE = new EmptyEnumerator();
1910

    
1911
        private EmptyEnumerator() { }
1912

    
1913
        public void Reset() { }
1914

    
1915
        public object Current
1916
        {
1917
            get { throw new InvalidOperationException("Collection is empty."); }
1918
        }
1919

    
1920
        public bool MoveNext()
1921
        {
1922
            return false;
1923
        }
1924

    
1925
        public IXdmEnumerator GetAnother()
1926
        {
1927
            return this;
1928
        }
1929
    }
1930

    
1931

    
1932
}
1933

    
1934
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1935
// Copyright (c) 2013 Saxonica Limited.
1936
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
1937
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
1938
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
1939
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(5-5/13)