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)