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
,
373 ancestorOrSelf
, namespaceAxis
;
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
);
389 namespaceAxis
= new XPathAxis (XPathAxisType
.Namespace
);
392 public static XPathAxis Child
{
393 get { return child; }
396 public static XPathAxis Descendant
{
397 get { return descendant; }
400 public static XPathAxis Attribute
{
401 get { return attribute; }
404 public static XPathAxis Self
{
408 public static XPathAxis DescendantOrSelf
{
409 get { return descendantOrSelf; }
412 public static XPathAxis FollowingSibling
{
413 get { return followingSibling; }
416 public static XPathAxis Following
{
417 get { return following; }
420 public static XPathAxis NamespaceAxis
{
421 get { return namespaceAxis; }
424 public static XPathAxis Parent
{
425 get { return parent; }
428 public static XPathAxis Ancestor
{
429 get { return ancestor; }
432 public static XPathAxis PrecedingSibling
{
433 get { return precedingSibling; }
436 public static XPathAxis Preceding
{
437 get { return preceding; }
440 public static XPathAxis AncestorOrSelf
{
441 get { return ancestorOrSelf; }
446 public class ItemType
448 static ItemType anyItem
= new ItemType (XmlTypeCode
.Item
);
449 static ItemType anyAtomicType
= new ItemType (XmlTypeCode
.AnyAtomicType
);
451 public static ItemType AnyItem
{
452 get { return anyItem; }
455 public static ItemType AnyAtomicType
{
456 get { return anyAtomicType; }
459 XmlTypeCode typeCode
;
461 public ItemType (XmlTypeCode typeCode
)
463 this.typeCode
= typeCode
;
466 public XmlTypeCode TypeCode
{
467 get { return typeCode; }
470 internal virtual void CheckReference (XQueryASTCompiler compiler
)
477 public class KindTest
: ItemType
479 public KindTest (XmlTypeCode type
)
484 internal virtual void Compile (XQueryASTCompiler compiler
)
488 public virtual bool Matches (XPathItem item
)
490 XPathNavigator nav
= item
as XPathNavigator
;
493 // FIXME: is it true? ('untyped' means 'matches with any type' ?
494 if (item
.XmlType
== null)
496 if (item
.XmlType
.TypeCode
!= TypeCode
)
502 public class DocumentTest
: KindTest
506 public DocumentTest (ElementTest content
)
507 : base (XmlTypeCode
.Document
)
509 this.content
= content
;
512 public ElementTest Content
{
513 get { return content; }
516 internal override void CheckReference (XQueryASTCompiler compiler
)
518 content
.CheckReference (compiler
);
521 internal override void Compile (XQueryASTCompiler compiler
)
525 public override bool Matches (XPathItem item
)
527 XPathNavigator nav
= item
as XPathNavigator
;
531 if (item
.XmlType
.TypeCode
!= XmlTypeCode
.Document
)
538 nav
.MoveToFirstChild ();
539 while (nav
.NodeType
!= XPathNodeType
.Element
)
540 if (!nav
.MoveToNext ())
542 return Content
.Matches (nav
);
546 public class ElementTest
: KindTest
548 XmlQualifiedName name
;
549 XmlQualifiedName typeName
;
550 XmlSchemaType schemaType
;
553 public ElementTest (XmlQualifiedName name
)
554 : base (XmlTypeCode
.Element
)
559 public ElementTest (XmlQualifiedName name
, XmlQualifiedName type
, bool nillable
)
560 : base (XmlTypeCode
.Element
)
563 this.typeName
= type
;
564 this.nillable
= nillable
;
567 public XmlQualifiedName Name
{
571 public XmlQualifiedName TypeName
{
572 get { return typeName; }
575 public XmlSchemaType SchemaType
{
581 public bool Nillable
{
582 get { return nillable; }
585 internal override void CheckReference (XQueryASTCompiler compiler
)
587 compiler
.CheckSchemaTypeName (typeName
);
590 internal override void Compile (XQueryASTCompiler compiler
)
592 schemaType
= compiler
.ResolveSchemaType (TypeName
);
593 if (schemaType
== null)
594 throw new XmlQueryCompileException ("Specified schema type was not found.");
597 public override bool Matches (XPathItem item
)
599 XPathNavigator nav
= item
as XPathNavigator
;
603 if (item
.XmlType
.TypeCode
!= XmlTypeCode
.Element
)
606 if (Name
!= XmlQualifiedName
.Empty
)
607 if (nav
.LocalName
!= Name
.Name
|| nav
.NamespaceURI
!= Name
.Namespace
)
610 // FIXME: it won't be XQueryConvert.CanConvert(), but other strict-matching evaluation
611 if (SchemaType
!= null && !XQueryConvert
.CanConvert (item
, SchemaType
))
613 // FIXME: check nillable
619 public class AttributeTest
: KindTest
621 static AttributeTest anyAttribute
;
623 static AttributeTest ()
625 anyAttribute
= new AttributeTest (XmlQualifiedName
.Empty
);
628 public static AttributeTest AnyAttribute
{
629 get { return anyAttribute; }
632 public AttributeTest (XmlQualifiedName name
)
633 : base (XmlTypeCode
.Attribute
)
638 public AttributeTest (XmlQualifiedName name
, XmlQualifiedName typeName
)
639 : base (XmlTypeCode
.Attribute
)
642 this.typeName
= typeName
;
645 XmlQualifiedName name
;
646 XmlQualifiedName typeName
;
647 XmlSchemaType schemaType
;
649 public XmlQualifiedName Name
{
653 public XmlQualifiedName TypeName
{
654 get { return typeName; }
657 public XmlSchemaType SchemaType
{
658 get { return schemaType; }
661 internal override void CheckReference (XQueryASTCompiler compiler
)
663 compiler
.CheckSchemaTypeName (typeName
);
666 internal override void Compile (XQueryASTCompiler compiler
)
668 schemaType
= compiler
.ResolveSchemaType (TypeName
);
669 if (schemaType
== null)
670 throw new XmlQueryCompileException ("Specified schema type was not found.");
673 public override bool Matches (XPathItem item
)
675 XPathNavigator nav
= item
as XPathNavigator
;
679 if (item
.XmlType
.TypeCode
!= XmlTypeCode
.Attribute
)
682 if (Name
!= XmlQualifiedName
.Empty
)
683 if (nav
.LocalName
!= Name
.Name
|| nav
.NamespaceURI
!= Name
.Namespace
)
686 // FIXME: it won't be XQueryConvert.CanConvert(), but other strict-matching evaluation
687 if (SchemaType
!= null && !XQueryConvert
.CanConvert (item
, SchemaType
))
694 public class XmlPITest
: KindTest
698 public XmlPITest (string nameTest
)
699 : base (XmlTypeCode
.ProcessingInstruction
)
701 this.name
= nameTest
;
708 internal override void CheckReference (XQueryASTCompiler compiler
)
712 internal override void Compile (XQueryASTCompiler compiler
)
716 public override bool Matches (XPathItem item
)
718 XPathNavigator nav
= item
as XPathNavigator
;
722 if (item
.XmlType
.TypeCode
!= XmlTypeCode
.ProcessingInstruction
)
724 if (Name
!= String
.Empty
&& nav
.LocalName
!= Name
)