2 // SequenceType.cs - represents XPath 2.0 item type
5 // Atsushi Enomoto <atsushi@ximian.com>
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System
.Collections
;
33 using System
.Globalization
;
35 using System
.Xml
.Schema
;
36 using System
.Xml
.Query
;
37 using System
.Xml
.XPath
;
40 namespace Mono
.Xml
.XPath2
42 public class SequenceType
44 static SequenceType singleItem
= new SequenceType (ItemType
.AnyItem
, Occurence
.One
);
45 static SequenceType singleAnyAtomic
= new SequenceType (ItemType
.AnyAtomicType
, Occurence
.One
);
47 internal static SequenceType AnyType
{
48 get { return Create (InternalPool.XsAnyType, Occurence.ZeroOrMore); }
50 internal static SequenceType SingleItem
{
51 get { return singleItem; }
53 internal static SequenceType SingleAnyAtomic
{
54 get { return singleAnyAtomic; }
57 internal static SequenceType Node
{
58 get { return Create (XmlTypeCode.Node, Occurence.One); }
60 internal static SequenceType Document
{
61 get { return Create (XmlTypeCode.Document, Occurence.One); }
63 internal static SequenceType Element
{
64 get { return Create (XmlTypeCode.Element, Occurence.One); }
66 internal static SequenceType Attribute
{
67 get { return Create (XmlTypeCode.Attribute, Occurence.One); }
69 internal static SequenceType Namespace
{
70 get { return Create (XmlTypeCode.Namespace, Occurence.One); }
72 internal static SequenceType Text
{
73 get { return Create (XmlTypeCode.Text, Occurence.One); }
75 internal static SequenceType XmlPI
{
76 get { return Create (XmlTypeCode.ProcessingInstruction, Occurence.One); }
78 internal static SequenceType Comment
{
79 get { return Create (XmlTypeCode.Comment, Occurence.One); }
82 internal static SequenceType AtomicString
{
83 get { return Create (InternalPool.XsString, Occurence.One); }
85 internal static SequenceType Boolean
{
86 get { return Create (InternalPool.XsBoolean, Occurence.One); }
88 internal static SequenceType Decimal
{
89 get { return Create (InternalPool.XsDecimal, Occurence.One); }
91 internal static SequenceType Integer
{
92 get { return Create (InternalPool.XsInteger, Occurence.One); }
94 internal static SequenceType Int
{
95 get { return Create (InternalPool.XsInt, Occurence.One); }
97 internal static SequenceType Short
{
98 get { return Create (InternalPool.XsShort, Occurence.One); }
100 internal static SequenceType UnsignedInt
{
101 get { return Create (InternalPool.XsUnsignedInt, Occurence.One); }
103 internal static SequenceType UnsignedShort
{
104 get { return Create (InternalPool.XsUnsignedShort, Occurence.One); }
106 internal static SequenceType Double
{
107 get { return Create (InternalPool.XsDouble, Occurence.One); }
109 internal static SequenceType Single
{
110 get { return Create (InternalPool.XsFloat, Occurence.One); }
112 internal static SequenceType DateTime
{
113 get { return Create (InternalPool.XsDateTime, Occurence.One); }
115 internal static SequenceType QName
{
116 get { return Create (InternalPool.XsQName, Occurence.One); }
119 internal static SequenceType IntegerList
{
120 get { return Create (XmlTypeCode.Integer, Occurence.ZeroOrMore); }
124 static Hashtable standardTypes
= new Hashtable ();
126 internal static SequenceType
Create (Type cliType
)
130 return Create (InternalPool
.XmlTypeCodeFromRuntimeType (cliType
.GetElementType (), true), Occurence
.ZeroOrMore
);
131 // if (cliType.GetInterface ("System.Collections.IEnumerable") != null)
132 // return Create (XmlTypeCode.Item, Occurence.ZeroOrMore);
133 if (cliType
== typeof (XmlQualifiedName
))
135 if (cliType
== typeof (XPathNavigator
) || cliType
.IsSubclassOf (typeof (XPathNavigator
)))
137 if (cliType
== typeof (XPathAtomicValue
))
138 return SingleAnyAtomic
;
139 if (cliType
== typeof (XPathItem
))
141 // FIXME: handle Nullable type
142 return Create (InternalPool
.XmlTypeCodeFromRuntimeType (cliType
, true), Occurence
.One
);
145 internal static SequenceType
Create (XmlTypeCode typeCode
, Occurence occurence
)
148 case XmlTypeCode
.Item
:
149 case XmlTypeCode
.AnyAtomicType
:
150 case XmlTypeCode
.Node
:
151 case XmlTypeCode
.Document
:
152 case XmlTypeCode
.Element
:
153 case XmlTypeCode
.Attribute
:
154 case XmlTypeCode
.ProcessingInstruction
:
155 case XmlTypeCode
.Comment
:
156 case XmlTypeCode
.Namespace
:
157 case XmlTypeCode
.Text
:
158 return new SequenceType (new ItemType (typeCode
), occurence
);
160 return Create (XmlSchemaType
.GetBuiltInSimpleType (typeCode
), occurence
);
164 internal static SequenceType
Create (XmlSchemaType schemaType
, Occurence occurence
)
166 switch (schemaType
.QualifiedName
.Namespace
) {
167 case XmlSchema
.Namespace
:
168 case InternalPool
.XdtNamespace
:
171 return new SequenceType (schemaType
, occurence
);
174 Hashtable cacheForType
= standardTypes
[schemaType
] as Hashtable
;
175 if (cacheForType
== null) {
176 cacheForType
= new Hashtable ();
177 standardTypes
[schemaType
] = cacheForType
;
179 SequenceType type
= cacheForType
[occurence
] as SequenceType
;
183 SequenceType t
= new SequenceType (schemaType
, occurence
);
184 cacheForType
[occurence
] = t
;
189 internal static SequenceType
ComputeCommonBase (SequenceType t1
, SequenceType t2
)
192 // throw new NotImplementedException ();
193 return SequenceType
.AnyType
;
196 internal static bool IsNumeric (XmlTypeCode code
)
199 case XmlTypeCode
.Decimal
:
200 case XmlTypeCode
.Float
:
201 case XmlTypeCode
.Double
:
202 case XmlTypeCode
.Integer
:
203 case XmlTypeCode
.NonPositiveInteger
:
204 case XmlTypeCode
.NegativeInteger
:
205 case XmlTypeCode
.Long
:
206 case XmlTypeCode
.Int
:
207 case XmlTypeCode
.Short
:
208 case XmlTypeCode
.Byte
:
209 case XmlTypeCode
.NonNegativeInteger
:
210 case XmlTypeCode
.UnsignedLong
:
211 case XmlTypeCode
.UnsignedInt
:
212 case XmlTypeCode
.UnsignedShort
:
213 case XmlTypeCode
.UnsignedByte
:
214 case XmlTypeCode
.PositiveInteger
:
222 private SequenceType (XmlSchemaType schemaType
, Occurence occurence
)
224 this.schemaType
= schemaType
;
225 this.itemType
= ItemType
.AnyItem
;
226 this.occurence
= occurence
;
229 internal SequenceType (ItemType itemType
, Occurence occurence
)
231 this.schemaType
= InternalPool
.XsAnyType
;
232 this.itemType
= itemType
;
233 this.occurence
= occurence
;
236 XmlSchemaType schemaType
;
240 public XmlSchemaType SchemaType
{
241 get { return schemaType; }
244 public ItemType ItemType
{
245 get { return itemType; }
248 public Occurence Occurence
{
249 get { return occurence; }
252 internal bool Matches (XPathSequence iter
)
254 throw new NotImplementedException ();
258 internal bool CanConvertTo (SequenceType other
)
260 // FIXME: implement precisely
261 return this == other
;
262 // throw new NotImplementedException ();
265 internal bool CanConvert (XPathSequence iter
)
267 bool occured
= false;
268 bool onlyOnce
= (occurence
== Occurence
.One
|| occurence
== Occurence
.Optional
);
269 bool required
= (occurence
== Occurence
.One
|| occurence
== Occurence
.OneOrMore
);
270 foreach (XPathItem item
in iter
) {
271 if (occured
&& onlyOnce
)
273 if (!CanConvert (item
))
276 return occured
|| !required
;
279 public bool CanConvert (XPathItem item
)
281 throw new NotImplementedException ();
284 public bool IsInstance (XPathItem item
)
286 throw new NotImplementedException ();
289 public XPathItem
Convert (XPathItem item
)
291 throw new NotImplementedException ();
294 public object ToRuntimeType (XPathSequence seq
)
296 // FIXME: handle ZeroOrMore|OneOrMore
299 case Occurence
.Optional
:
300 if (!seq
.MoveNext ())
302 XPathItem item
= seq
.Current
;
303 // FIXME: should check and reject two or
305 return item
.TypedValue
;
307 ArrayList al
= new ArrayList ();
308 while (seq
.MoveNext ())
309 al
.Add (seq
.Current
.TypedValue
);
310 return al
.ToArray (InternalPool
.RuntimeTypeFromXmlTypeCode (schemaType
.TypeCode
));
315 public enum Occurence
325 public enum XPathAxisType
339 Namespace
// only applicable under XPath 2.0, not XQuery 1.0
342 public class XPathAxis
344 // FIXME: add more parameters to distinguish them
345 private XPathAxis (XPathAxisType axisType
)
347 this.axisType
= axisType
;
349 case XPathAxisType
.Parent
:
350 case XPathAxisType
.Ancestor
:
351 case XPathAxisType
.AncestorOrSelf
:
352 case XPathAxisType
.Preceding
:
353 case XPathAxisType
.PrecedingSibling
:
360 XPathAxisType axisType
;
362 public bool ReverseAxis
{
363 get { return reverse; }
366 public XPathAxisType AxisType
{
367 get { return axisType; }
370 static XPathAxis child
, descendant
, attribute
, self
,
371 descendantOrSelf
, followingSibling
, following
,
372 parent
, ancestor
, precedingSibling
, preceding
,
377 child
= new XPathAxis (XPathAxisType
.Child
);
378 descendant
= new XPathAxis (XPathAxisType
.Descendant
);
379 attribute
= new XPathAxis (XPathAxisType
.Attribute
);
380 self
= new XPathAxis (XPathAxisType
.Self
);
381 descendantOrSelf
= new XPathAxis (XPathAxisType
.DescendantOrSelf
);
382 followingSibling
= new XPathAxis (XPathAxisType
.FollowingSibling
);
383 following
= new XPathAxis (XPathAxisType
.Following
);
384 parent
= new XPathAxis (XPathAxisType
.Parent
);
385 ancestor
= new XPathAxis (XPathAxisType
.Ancestor
);
386 precedingSibling
= new XPathAxis (XPathAxisType
.PrecedingSibling
);
387 preceding
= new XPathAxis (XPathAxisType
.Preceding
);
388 ancestorOrSelf
= new XPathAxis (XPathAxisType
.AncestorOrSelf
);
391 public static XPathAxis Child
{
392 get { return child; }
395 public static XPathAxis Descendant
{
396 get { return descendant; }
399 public static XPathAxis Attribute
{
400 get { return attribute; }
403 public static XPathAxis Self
{
407 public static XPathAxis DescendantOrSelf
{
408 get { return descendantOrSelf; }
411 public static XPathAxis FollowingSibling
{
412 get { return followingSibling; }
415 public static XPathAxis Following
{
416 get { return following; }
419 public static XPathAxis Parent
{
420 get { return parent; }
423 public static XPathAxis Ancestor
{
424 get { return ancestor; }
427 public static XPathAxis PrecedingSibling
{
428 get { return precedingSibling; }
431 public static XPathAxis Preceding
{
432 get { return preceding; }
435 public static XPathAxis AncestorOrSelf
{
436 get { return ancestorOrSelf; }
441 public class ItemType
443 static ItemType anyItem
= new ItemType (XmlTypeCode
.Item
);
444 static ItemType anyAtomicType
= new ItemType (XmlTypeCode
.AnyAtomicType
);
446 public static ItemType AnyItem
{
447 get { return anyItem; }
450 public static ItemType AnyAtomicType
{
451 get { return anyAtomicType; }
454 XmlTypeCode typeCode
;
456 public ItemType (XmlTypeCode typeCode
)
458 this.typeCode
= typeCode
;
461 public XmlTypeCode TypeCode
{
462 get { return typeCode; }
465 internal virtual void CheckReference (XQueryASTCompiler compiler
)
472 public class KindTest
: ItemType
474 public KindTest (XmlTypeCode type
)
479 internal virtual void Compile (XQueryASTCompiler compiler
)
483 public virtual bool Matches (XPathItem item
)
485 XPathNavigator nav
= item
as XPathNavigator
;
488 // FIXME: is it true? ('untyped' means 'matches with any type' ?
489 if (item
.XmlType
== null)
491 if (item
.XmlType
.TypeCode
!= TypeCode
)
497 public class DocumentTest
: KindTest
501 public DocumentTest (ElementTest content
)
502 : base (XmlTypeCode
.Document
)
504 this.content
= content
;
507 public ElementTest Content
{
508 get { return content; }
511 internal override void CheckReference (XQueryASTCompiler compiler
)
513 content
.CheckReference (compiler
);
516 internal override void Compile (XQueryASTCompiler compiler
)
520 public override bool Matches (XPathItem item
)
522 XPathNavigator nav
= item
as XPathNavigator
;
526 if (item
.XmlType
.TypeCode
!= XmlTypeCode
.Document
)
533 nav
.MoveToFirstChild ();
534 while (nav
.NodeType
!= XPathNodeType
.Element
)
535 if (!nav
.MoveToNext ())
537 return Content
.Matches (nav
);
541 public class ElementTest
: KindTest
543 XmlQualifiedName name
;
544 XmlQualifiedName typeName
;
545 XmlSchemaType schemaType
;
548 public ElementTest (XmlQualifiedName name
)
549 : base (XmlTypeCode
.Element
)
554 public ElementTest (XmlQualifiedName name
, XmlQualifiedName type
, bool nillable
)
555 : base (XmlTypeCode
.Element
)
558 this.typeName
= type
;
559 this.nillable
= nillable
;
562 public XmlQualifiedName Name
{
566 public XmlQualifiedName TypeName
{
567 get { return typeName; }
570 public XmlSchemaType SchemaType
{
576 public bool Nillable
{
577 get { return nillable; }
580 internal override void CheckReference (XQueryASTCompiler compiler
)
582 compiler
.CheckSchemaTypeName (typeName
);
585 internal override void Compile (XQueryASTCompiler compiler
)
587 schemaType
= compiler
.ResolveSchemaType (TypeName
);
588 if (schemaType
== null)
589 throw new XmlQueryCompileException ("Specified schema type was not found.");
592 public override bool Matches (XPathItem item
)
594 XPathNavigator nav
= item
as XPathNavigator
;
598 if (item
.XmlType
.TypeCode
!= XmlTypeCode
.Element
)
601 if (Name
!= XmlQualifiedName
.Empty
)
602 if (nav
.LocalName
!= Name
.Name
|| nav
.NamespaceURI
!= Name
.Namespace
)
605 // FIXME: it won't be XQueryConvert.CanConvert(), but other strict-matching evaluation
606 if (SchemaType
!= null && !XQueryConvert
.CanConvert (item
, SchemaType
))
608 // FIXME: check nillable
614 public class AttributeTest
: KindTest
616 static AttributeTest anyAttribute
;
618 static AttributeTest ()
620 anyAttribute
= new AttributeTest (XmlQualifiedName
.Empty
);
623 public static AttributeTest AnyAttribute
{
624 get { return anyAttribute; }
627 public AttributeTest (XmlQualifiedName name
)
628 : base (XmlTypeCode
.Attribute
)
633 public AttributeTest (XmlQualifiedName name
, XmlQualifiedName typeName
)
634 : base (XmlTypeCode
.Attribute
)
637 this.typeName
= typeName
;
640 XmlQualifiedName name
;
641 XmlQualifiedName typeName
;
642 XmlSchemaType schemaType
;
644 public XmlQualifiedName Name
{
648 public XmlQualifiedName TypeName
{
649 get { return typeName; }
652 public XmlSchemaType SchemaType
{
653 get { return schemaType; }
656 internal override void CheckReference (XQueryASTCompiler compiler
)
658 compiler
.CheckSchemaTypeName (typeName
);
661 internal override void Compile (XQueryASTCompiler compiler
)
663 schemaType
= compiler
.ResolveSchemaType (TypeName
);
664 if (schemaType
== null)
665 throw new XmlQueryCompileException ("Specified schema type was not found.");
668 public override bool Matches (XPathItem item
)
670 XPathNavigator nav
= item
as XPathNavigator
;
674 if (item
.XmlType
.TypeCode
!= XmlTypeCode
.Attribute
)
677 if (Name
!= XmlQualifiedName
.Empty
)
678 if (nav
.LocalName
!= Name
.Name
|| nav
.NamespaceURI
!= Name
.Namespace
)
681 // FIXME: it won't be XQueryConvert.CanConvert(), but other strict-matching evaluation
682 if (SchemaType
!= null && !XQueryConvert
.CanConvert (item
, SchemaType
))
689 public class XmlPITest
: KindTest
693 public XmlPITest (string nameTest
)
694 : base (XmlTypeCode
.ProcessingInstruction
)
696 this.name
= nameTest
;
703 internal override void CheckReference (XQueryASTCompiler compiler
)
707 internal override void Compile (XQueryASTCompiler compiler
)
711 public override bool Matches (XPathItem item
)
713 XPathNavigator nav
= item
as XPathNavigator
;
717 if (item
.XmlType
.TypeCode
!= XmlTypeCode
.ProcessingInstruction
)
719 if (Name
!= String
.Empty
&& nav
.LocalName
!= Name
)