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.
31 using System.Collections;
32 using System.Globalization;
34 using System.Xml.Schema;
35 using System.Xml.Query;
36 using System.Xml.XPath;
39 namespace Mono.Xml.XPath2
41 public class SequenceType
43 static SequenceType singleItem = new SequenceType (ItemType.AnyItem, Occurence.One);
44 static SequenceType singleAnyAtomic = new SequenceType (ItemType.AnyAtomicType, Occurence.One);
46 internal static SequenceType AnyType {
47 get { return Create (InternalPool.XsAnyType, Occurence.ZeroOrMore); }
49 internal static SequenceType SingleItem {
50 get { return singleItem; }
52 internal static SequenceType SingleAnyAtomic {
53 get { return singleAnyAtomic; }
56 internal static SequenceType Node {
57 get { return Create (XmlTypeCode.Node, Occurence.One); }
59 internal static SequenceType Document {
60 get { return Create (XmlTypeCode.Document, Occurence.One); }
62 internal static SequenceType Element {
63 get { return Create (XmlTypeCode.Element, Occurence.One); }
65 internal static SequenceType Attribute {
66 get { return Create (XmlTypeCode.Attribute, Occurence.One); }
68 internal static SequenceType Namespace {
69 get { return Create (XmlTypeCode.Namespace, Occurence.One); }
71 internal static SequenceType Text {
72 get { return Create (XmlTypeCode.Text, Occurence.One); }
74 internal static SequenceType XmlPI {
75 get { return Create (XmlTypeCode.ProcessingInstruction, Occurence.One); }
77 internal static SequenceType Comment {
78 get { return Create (XmlTypeCode.Comment, Occurence.One); }
81 internal static SequenceType AtomicString {
82 get { return Create (InternalPool.XsString, Occurence.One); }
84 internal static SequenceType Boolean {
85 get { return Create (InternalPool.XsBoolean, Occurence.One); }
87 internal static SequenceType Decimal {
88 get { return Create (InternalPool.XsDecimal, Occurence.One); }
90 internal static SequenceType Integer {
91 get { return Create (InternalPool.XsInteger, Occurence.One); }
93 internal static SequenceType Int {
94 get { return Create (InternalPool.XsInt, Occurence.One); }
96 internal static SequenceType Short {
97 get { return Create (InternalPool.XsShort, Occurence.One); }
99 internal static SequenceType UnsignedInt {
100 get { return Create (InternalPool.XsUnsignedInt, Occurence.One); }
102 internal static SequenceType UnsignedShort {
103 get { return Create (InternalPool.XsUnsignedShort, Occurence.One); }
105 internal static SequenceType Double {
106 get { return Create (InternalPool.XsDouble, Occurence.One); }
108 internal static SequenceType Single {
109 get { return Create (InternalPool.XsFloat, Occurence.One); }
111 internal static SequenceType DateTime {
112 get { return Create (InternalPool.XsDateTime, Occurence.One); }
114 internal static SequenceType QName {
115 get { return Create (InternalPool.XsQName, Occurence.One); }
118 internal static SequenceType IntegerList {
119 get { return Create (XmlTypeCode.Integer, Occurence.ZeroOrMore); }
123 static Hashtable standardTypes = new Hashtable ();
125 internal static SequenceType Create (Type cliType)
129 return Create (InternalPool.XmlTypeCodeFromRuntimeType (cliType.GetElementType (), true), Occurence.ZeroOrMore);
130 // if (cliType.GetInterface ("System.Collections.IEnumerable") != null)
131 // return Create (XmlTypeCode.Item, Occurence.ZeroOrMore);
132 if (cliType == typeof (XmlQualifiedName))
134 if (cliType == typeof (XPathNavigator) || cliType.IsSubclassOf (typeof (XPathNavigator)))
136 if (cliType == typeof (XPathAtomicValue))
137 return SingleAnyAtomic;
138 if (cliType == typeof (XPathItem))
140 // FIXME: handle Nullable type
141 return Create (InternalPool.XmlTypeCodeFromRuntimeType (cliType, true), Occurence.One);
144 internal static SequenceType Create (XmlTypeCode typeCode, Occurence occurence)
147 case XmlTypeCode.Item:
148 case XmlTypeCode.AnyAtomicType:
149 case XmlTypeCode.Node:
150 case XmlTypeCode.Document:
151 case XmlTypeCode.Element:
152 case XmlTypeCode.Attribute:
153 case XmlTypeCode.ProcessingInstruction:
154 case XmlTypeCode.Comment:
155 case XmlTypeCode.Namespace:
156 case XmlTypeCode.Text:
157 return new SequenceType (new ItemType (typeCode), occurence);
159 return Create (XmlSchemaType.GetBuiltInSimpleType (typeCode), occurence);
163 internal static SequenceType Create (XmlSchemaType schemaType, Occurence occurence)
165 switch (schemaType.QualifiedName.Namespace) {
166 case XmlSchema.Namespace:
167 case InternalPool.XdtNamespace:
170 return new SequenceType (schemaType, occurence);
173 Hashtable cacheForType = standardTypes [schemaType] as Hashtable;
174 if (cacheForType == null) {
175 cacheForType = new Hashtable ();
176 standardTypes [schemaType] = cacheForType;
178 SequenceType type = cacheForType [occurence] as SequenceType;
182 SequenceType t = new SequenceType (schemaType, occurence);
183 cacheForType [occurence] = t;
188 internal static SequenceType ComputeCommonBase (SequenceType t1, SequenceType t2)
191 // throw new NotImplementedException ();
192 return SequenceType.AnyType;
195 internal static bool IsNumeric (XmlTypeCode code)
198 case XmlTypeCode.Decimal:
199 case XmlTypeCode.Float:
200 case XmlTypeCode.Double:
201 case XmlTypeCode.Integer:
202 case XmlTypeCode.NonPositiveInteger:
203 case XmlTypeCode.NegativeInteger:
204 case XmlTypeCode.Long:
205 case XmlTypeCode.Int:
206 case XmlTypeCode.Short:
207 case XmlTypeCode.Byte:
208 case XmlTypeCode.NonNegativeInteger:
209 case XmlTypeCode.UnsignedLong:
210 case XmlTypeCode.UnsignedInt:
211 case XmlTypeCode.UnsignedShort:
212 case XmlTypeCode.UnsignedByte:
213 case XmlTypeCode.PositiveInteger:
221 private SequenceType (XmlSchemaType schemaType, Occurence occurence)
223 this.schemaType = schemaType;
224 this.itemType = ItemType.AnyItem;
225 this.occurence = occurence;
228 internal SequenceType (ItemType itemType, Occurence occurence)
230 this.schemaType = InternalPool.XsAnyType;
231 this.itemType = itemType;
232 this.occurence = occurence;
235 XmlSchemaType schemaType;
239 public XmlSchemaType SchemaType {
240 get { return schemaType; }
243 public ItemType ItemType {
244 get { return itemType; }
247 public Occurence Occurence {
248 get { return occurence; }
251 internal bool Matches (XPathSequence iter)
253 throw new NotImplementedException ();
257 internal bool CanConvertTo (SequenceType other)
259 // FIXME: implement precisely
260 return this == other;
261 // throw new NotImplementedException ();
264 internal bool CanConvert (XPathSequence iter)
266 bool occured = false;
267 bool onlyOnce = (occurence == Occurence.One || occurence == Occurence.Optional);
268 bool required = (occurence == Occurence.One || occurence == Occurence.OneOrMore);
269 foreach (XPathItem item in iter) {
270 if (occured && onlyOnce)
272 if (!CanConvert (item))
275 return occured || !required;
278 public bool CanConvert (XPathItem item)
280 throw new NotImplementedException ();
283 public bool IsInstance (XPathItem item)
285 throw new NotImplementedException ();
288 public XPathItem Convert (XPathItem item)
290 throw new NotImplementedException ();
293 public object ToRuntimeType (XPathSequence seq)
295 // FIXME: handle ZeroOrMore|OneOrMore
298 case Occurence.Optional:
299 if (!seq.MoveNext ())
301 XPathItem item = seq.Current;
302 // FIXME: should check and reject two or
304 return item.TypedValue;
306 ArrayList al = new ArrayList ();
307 while (seq.MoveNext ())
308 al.Add (seq.Current.TypedValue);
309 return al.ToArray (InternalPool.RuntimeTypeFromXmlTypeCode (schemaType.TypeCode));
314 public enum Occurence
324 public enum XPathAxisType
338 Namespace // only applicable under XPath 2.0, not XQuery 1.0
341 public class XPathAxis
343 // FIXME: add more parameters to distinguish them
344 private XPathAxis (XPathAxisType axisType)
346 this.axisType = axisType;
348 case XPathAxisType.Parent:
349 case XPathAxisType.Ancestor:
350 case XPathAxisType.AncestorOrSelf:
351 case XPathAxisType.Preceding:
352 case XPathAxisType.PrecedingSibling:
359 XPathAxisType axisType;
361 public bool ReverseAxis {
362 get { return reverse; }
365 public XPathAxisType AxisType {
366 get { return axisType; }
369 static XPathAxis child, descendant, attribute, self,
370 descendantOrSelf, followingSibling, following,
371 parent, ancestor, precedingSibling, preceding,
372 ancestorOrSelf, namespaceAxis;
376 child = new XPathAxis (XPathAxisType.Child);
377 descendant = new XPathAxis (XPathAxisType.Descendant);
378 attribute = new XPathAxis (XPathAxisType.Attribute);
379 self = new XPathAxis (XPathAxisType.Self);
380 descendantOrSelf = new XPathAxis (XPathAxisType.DescendantOrSelf);
381 followingSibling = new XPathAxis (XPathAxisType.FollowingSibling);
382 following = new XPathAxis (XPathAxisType.Following);
383 parent = new XPathAxis (XPathAxisType.Parent);
384 ancestor = new XPathAxis (XPathAxisType.Ancestor);
385 precedingSibling = new XPathAxis (XPathAxisType.PrecedingSibling);
386 preceding = new XPathAxis (XPathAxisType.Preceding);
387 ancestorOrSelf = new XPathAxis (XPathAxisType.AncestorOrSelf);
388 namespaceAxis = new XPathAxis (XPathAxisType.Namespace);
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 NamespaceAxis {
420 get { return namespaceAxis; }
423 public static XPathAxis Parent {
424 get { return parent; }
427 public static XPathAxis Ancestor {
428 get { return ancestor; }
431 public static XPathAxis PrecedingSibling {
432 get { return precedingSibling; }
435 public static XPathAxis Preceding {
436 get { return preceding; }
439 public static XPathAxis AncestorOrSelf {
440 get { return ancestorOrSelf; }
445 public class ItemType
447 static ItemType anyItem = new ItemType (XmlTypeCode.Item);
448 static ItemType anyAtomicType = new ItemType (XmlTypeCode.AnyAtomicType);
450 public static ItemType AnyItem {
451 get { return anyItem; }
454 public static ItemType AnyAtomicType {
455 get { return anyAtomicType; }
458 XmlTypeCode typeCode;
460 public ItemType (XmlTypeCode typeCode)
462 this.typeCode = typeCode;
465 public XmlTypeCode TypeCode {
466 get { return typeCode; }
469 internal virtual void CheckReference (XQueryASTCompiler compiler)
476 public class KindTest : ItemType
478 public KindTest (XmlTypeCode type)
483 internal virtual void Compile (XQueryASTCompiler compiler)
487 public virtual bool Matches (XPathItem item)
489 XPathNavigator nav = item as XPathNavigator;
492 // FIXME: is it true? ('untyped' means 'matches with any type' ?
493 if (item.XmlType == null)
495 if (item.XmlType.TypeCode != TypeCode)
501 public class DocumentTest : KindTest
505 public DocumentTest (ElementTest content)
506 : base (XmlTypeCode.Document)
508 this.content = content;
511 public ElementTest Content {
512 get { return content; }
515 internal override void CheckReference (XQueryASTCompiler compiler)
517 content.CheckReference (compiler);
520 internal override void Compile (XQueryASTCompiler compiler)
524 public override bool Matches (XPathItem item)
526 XPathNavigator nav = item as XPathNavigator;
530 if (item.XmlType.TypeCode != XmlTypeCode.Document)
537 nav.MoveToFirstChild ();
538 while (nav.NodeType != XPathNodeType.Element)
539 if (!nav.MoveToNext ())
541 return Content.Matches (nav);
545 public class ElementTest : KindTest
547 XmlQualifiedName name;
548 XmlQualifiedName typeName;
549 XmlSchemaType schemaType;
552 public ElementTest (XmlQualifiedName name)
553 : base (XmlTypeCode.Element)
558 public ElementTest (XmlQualifiedName name, XmlQualifiedName type, bool nillable)
559 : base (XmlTypeCode.Element)
562 this.typeName = type;
563 this.nillable = nillable;
566 public XmlQualifiedName Name {
570 public XmlQualifiedName TypeName {
571 get { return typeName; }
574 public XmlSchemaType SchemaType {
580 public bool Nillable {
581 get { return nillable; }
584 internal override void CheckReference (XQueryASTCompiler compiler)
586 compiler.CheckSchemaTypeName (typeName);
589 internal override void Compile (XQueryASTCompiler compiler)
591 schemaType = compiler.ResolveSchemaType (TypeName);
592 if (schemaType == null)
593 throw new XmlQueryCompileException ("Specified schema type was not found.");
596 public override bool Matches (XPathItem item)
598 XPathNavigator nav = item as XPathNavigator;
602 if (item.XmlType.TypeCode != XmlTypeCode.Element)
605 if (Name != XmlQualifiedName.Empty)
606 if (nav.LocalName != Name.Name || nav.NamespaceURI != Name.Namespace)
609 // FIXME: it won't be XQueryConvert.CanConvert(), but other strict-matching evaluation
610 if (SchemaType != null && !XQueryConvert.CanConvert (item, SchemaType))
612 // FIXME: check nillable
618 public class AttributeTest : KindTest
620 static AttributeTest anyAttribute;
622 static AttributeTest ()
624 anyAttribute = new AttributeTest (XmlQualifiedName.Empty);
627 public static AttributeTest AnyAttribute {
628 get { return anyAttribute; }
631 public AttributeTest (XmlQualifiedName name)
632 : base (XmlTypeCode.Attribute)
637 public AttributeTest (XmlQualifiedName name, XmlQualifiedName typeName)
638 : base (XmlTypeCode.Attribute)
641 this.typeName = typeName;
644 XmlQualifiedName name;
645 XmlQualifiedName typeName;
646 XmlSchemaType schemaType;
648 public XmlQualifiedName Name {
652 public XmlQualifiedName TypeName {
653 get { return typeName; }
656 public XmlSchemaType SchemaType {
657 get { return schemaType; }
660 internal override void CheckReference (XQueryASTCompiler compiler)
662 compiler.CheckSchemaTypeName (typeName);
665 internal override void Compile (XQueryASTCompiler compiler)
667 schemaType = compiler.ResolveSchemaType (TypeName);
668 if (schemaType == null)
669 throw new XmlQueryCompileException ("Specified schema type was not found.");
672 public override bool Matches (XPathItem item)
674 XPathNavigator nav = item as XPathNavigator;
678 if (item.XmlType.TypeCode != XmlTypeCode.Attribute)
681 if (Name != XmlQualifiedName.Empty)
682 if (nav.LocalName != Name.Name || nav.NamespaceURI != Name.Namespace)
685 // FIXME: it won't be XQueryConvert.CanConvert(), but other strict-matching evaluation
686 if (SchemaType != null && !XQueryConvert.CanConvert (item, SchemaType))
693 public class XmlPITest : KindTest
697 public XmlPITest (string nameTest)
698 : base (XmlTypeCode.ProcessingInstruction)
700 this.name = nameTest;
707 internal override void CheckReference (XQueryASTCompiler compiler)
711 internal override void Compile (XQueryASTCompiler compiler)
715 public override bool Matches (XPathItem item)
717 XPathNavigator nav = item as XPathNavigator;
721 if (item.XmlType.TypeCode != XmlTypeCode.ProcessingInstruction)
723 if (Name != String.Empty && nav.LocalName != Name)