XmlQueryTypeFactory.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / XmlUtils / System / Xml / Xsl / XmlQueryTypeFactory.cs / 5 / XmlQueryTypeFactory.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
using System.Collections.Generic;
using System.Diagnostics; 
using System.Globalization;
using System.IO;
using System.Xml.Schema;
using System.Xml.XPath; 

namespace System.Xml.Xsl { 
    using TF = XmlQueryTypeFactory; 

    ///  
    /// This class is the only way to create concrete instances of the abstract XmlQueryType class.
    /// Once basic types have been created, they can be combined and transformed in various ways.
    /// 
    internal static class XmlQueryTypeFactory { 
        //-----------------------------------------------
        // Type Construction Operators 
        //----------------------------------------------- 

        ///  
        /// Create an XmlQueryType from an XmlTypeCode.
        /// 
        /// the type code of the item
        /// true if the dynamic type is guaranteed to match the static type exactly 
        /// the atomic value type
        public static XmlQueryType Type(XmlTypeCode code, bool isStrict) { 
            return ItemType.Create(code, isStrict); 
        }
 
        /// 
        /// Create an XmlQueryType from an Xsd simple type (where variety can be Atomic, List, or Union).
        /// 
        /// the simple Xsd schema type of the atomic value 
        /// true if the dynamic type is guaranteed to match the static type exactly
        /// the atomic value type 
        public static XmlQueryType Type(XmlSchemaSimpleType schemaType, bool isStrict) { 
            if (schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic) {
                // We must special-case xs:anySimpleType because it is broken in Xsd and is sometimes treated as 
                // an atomic value and sometimes as a list value.  In XQuery, it always maps to xdt:anyAtomicType*.
                if (schemaType == DatatypeImplementation.AnySimpleType)
                    return AnyAtomicTypeS;
 
                return ItemType.Create(schemaType, isStrict);
            } 
 
            // Skip restrictions. It is safe to do that because this is a list or union, so it's not a build in type
            while (schemaType.DerivedBy == XmlSchemaDerivationMethod.Restriction) 
                schemaType = (XmlSchemaSimpleType) schemaType.BaseXmlSchemaType;

            // Convert Xsd list
            if (schemaType.DerivedBy == XmlSchemaDerivationMethod.List) 
                return PrimeProduct(Type(((XmlSchemaSimpleTypeList) schemaType.Content).BaseItemType, isStrict), XmlQueryCardinality.ZeroOrMore);
 
            // Convert Xsd union 
            Debug.Assert(schemaType.DerivedBy == XmlSchemaDerivationMethod.Union);
            XmlSchemaSimpleType[] baseMemberTypes = ((XmlSchemaSimpleTypeUnion) schemaType.Content).BaseMemberTypes; 
            XmlQueryType[] queryMemberTypes = new XmlQueryType[baseMemberTypes.Length];

            for (int i = 0; i < baseMemberTypes.Length; i++)
                queryMemberTypes[i] = Type(baseMemberTypes[i], isStrict); 

            return Choice(queryMemberTypes); 
        } 

        ///  
        /// Construct the union of two XmlQueryTypes
        /// 
        /// the left type
        /// the right type 
        /// the union type
        public static XmlQueryType Choice(XmlQueryType left, XmlQueryType right) { 
            return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List(left), right)), left.Cardinality | right.Cardinality); 
        }
 
        /// 
        /// Construct the union of several XmlQueryTypes
        /// 
        /// the list of types 
        /// the union type
        public static XmlQueryType Choice(params XmlQueryType[] types) { 
            if (types.Length == 0) 
                return None;
            else if (types.Length == 1) 
                return types[0];

            // Union each type with next type
            List list = new List(types[0]); 
            XmlQueryCardinality card = types[0].Cardinality;
 
            for (int i = 1; i < types.Length; i++) { 
                PrimeChoice(list, types[i]);
                card |= types[i].Cardinality; 
            }

            return SequenceType.Create(ChoiceType.Create(list), card);
        } 

        ///  
        /// Create a Node XmlQueryType which is the choice between several different node kinds. 
        /// 
        /// the node kinds which will make up the choice 
        /// the node type
        public static XmlQueryType NodeChoice(XmlNodeKindFlags kinds) {
            return ChoiceType.Create(kinds);
        } 

        ///  
        /// Construct the sequence of two XmlQueryTypes 
        /// 
        /// the left type 
        /// the right type
        /// the sequence type
        public static XmlQueryType Sequence(XmlQueryType left, XmlQueryType right) {
            return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List(left), right)), left.Cardinality + right.Cardinality); 
        }
 
    #if NEVER 
        /// 
        /// Construct the sequence of several XmlQueryTypes 
        /// 
        /// the sequence of types
        /// the sequence type
        public XmlQueryType Sequence(params XmlQueryType[] types) { 
            XmlQueryCardinality card = XmlQueryCardinality.Zero;
 
            foreach (XmlQueryType t in types) 
                card += t.Cardinality;
 
            return PrimeProduct(Choice(types), card);
        }
    #endif
 
        /// 
        /// Compute the product of the prime of "t" with cardinality "c". 
        ///  
        /// the member type
        /// the cardinality 
        /// the prime type with the indicated cardinality applied
        public static XmlQueryType PrimeProduct(XmlQueryType t, XmlQueryCardinality c) {
            // If cardinality stays the same, then this is a no-op
            if (t.Cardinality == c && !t.IsDod) 
                return t;
 
            return SequenceType.Create(t.Prime, c); 
        }
 
        /// 
        /// Compute a sequence with cardinality *= c.
        /// 
        /// the type to sequence 
        /// the cardinality multiplier
        /// the sequence of t with cardinality *= c 
        public static XmlQueryType Product(XmlQueryType t, XmlQueryCardinality c) { 
            return PrimeProduct(t, t.Cardinality * c);
        } 

        /// 
        /// Compute a sequence of zero to some max cardinality.
        ///  
        /// the type to sequence
        /// the upper bound 
        /// the sequence of t from 0 to c 
        public static XmlQueryType AtMost(XmlQueryType t, XmlQueryCardinality c) {
            return PrimeProduct(t, c.AtMost()); 
        }

        #region Built-in types
        //----------------------------------------------- 
        // Pre-Created Types
        // 
        // Abbreviations: 
        //   P = Plus (+)
        //   Q = Question Mark (?) 
        //   S = Star (*)
        //   X = Exact (IsStrict = true)
        //-----------------------------------------------
 
        public static readonly XmlQueryType None                = ChoiceType.None;
        public static readonly XmlQueryType Empty               = SequenceType.Zero; 
 
        public static readonly XmlQueryType Item                = TF.Type(XmlTypeCode.Item, false);
        public static readonly XmlQueryType ItemS               = TF.PrimeProduct(Item, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Node                = TF.Type(XmlTypeCode.Node, false);
        public static readonly XmlQueryType NodeS               = TF.PrimeProduct(Node, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType Element             = TF.Type(XmlTypeCode.Element, false);
        public static readonly XmlQueryType ElementS            = TF.PrimeProduct(Element, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Document            = TF.Type(XmlTypeCode.Document, false);
        public static readonly XmlQueryType DocumentS           = TF.PrimeProduct(Document, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Attribute           = TF.Type(XmlTypeCode.Attribute, false); 
        public static readonly XmlQueryType AttributeQ          = TF.PrimeProduct(Attribute, XmlQueryCardinality.ZeroOrOne);
        public static readonly XmlQueryType AttributeS          = TF.PrimeProduct(Attribute, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Namespace           = TF.Type(XmlTypeCode.Namespace, false);
        public static readonly XmlQueryType NamespaceS          = TF.PrimeProduct(Namespace, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType Text                = TF.Type(XmlTypeCode.Text, false);
        public static readonly XmlQueryType TextS               = TF.PrimeProduct(Text, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Comment             = TF.Type(XmlTypeCode.Comment, false);
        public static readonly XmlQueryType CommentS            = TF.PrimeProduct(Comment, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType PI                  = TF.Type(XmlTypeCode.ProcessingInstruction, false); 
        public static readonly XmlQueryType PIS                 = TF.PrimeProduct(PI, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType DocumentOrElement   = TF.Choice(Document, Element); 
        public static readonly XmlQueryType DocumentOrElementQ  = TF.PrimeProduct(DocumentOrElement, XmlQueryCardinality.ZeroOrOne);
        public static readonly XmlQueryType DocumentOrElementS  = TF.PrimeProduct(DocumentOrElement, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType Content             = TF.Choice(Element, Comment, PI, Text);
        public static readonly XmlQueryType ContentS            = TF.PrimeProduct(Content, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType DocumentOrContent   = TF.Choice(Document, Content);
        public static readonly XmlQueryType DocumentOrContentS  = TF.PrimeProduct(DocumentOrContent, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType AttributeOrContent  = TF.Choice(Attribute, Content); 
        public static readonly XmlQueryType AttributeOrContentS = TF.PrimeProduct(AttributeOrContent, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType AnyAtomicType       = TF.Type(XmlTypeCode.AnyAtomicType, false); 
        public static readonly XmlQueryType AnyAtomicTypeS      = TF.PrimeProduct(AnyAtomicType, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType String              = TF.Type(XmlTypeCode.String, false);
        public static readonly XmlQueryType StringX             = TF.Type(XmlTypeCode.String, true);
        public static readonly XmlQueryType StringXS            = TF.PrimeProduct(StringX, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Boolean             = TF.Type(XmlTypeCode.Boolean, false);
        public static readonly XmlQueryType BooleanX            = TF.Type(XmlTypeCode.Boolean, true); 
        public static readonly XmlQueryType Int                 = TF.Type(XmlTypeCode.Int, false); 
        public static readonly XmlQueryType IntX                = TF.Type(XmlTypeCode.Int, true);
        public static readonly XmlQueryType IntXS               = TF.PrimeProduct(IntX, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType IntegerX            = TF.Type(XmlTypeCode.Integer, true);
        public static readonly XmlQueryType LongX               = TF.Type(XmlTypeCode.Long, true);
        public static readonly XmlQueryType DecimalX            = TF.Type(XmlTypeCode.Decimal, true);
        public static readonly XmlQueryType FloatX              = TF.Type(XmlTypeCode.Float, true); 
        public static readonly XmlQueryType Double              = TF.Type(XmlTypeCode.Double, false);
        public static readonly XmlQueryType DoubleX             = TF.Type(XmlTypeCode.Double, true); 
        public static readonly XmlQueryType DateTimeX           = TF.Type(XmlTypeCode.DateTime, true); 
        public static readonly XmlQueryType QNameX              = TF.Type(XmlTypeCode.QName, true);
        public static readonly XmlQueryType UntypedDocument     = ItemType.UntypedDocument; 
        public static readonly XmlQueryType UntypedElement      = ItemType.UntypedElement;
        public static readonly XmlQueryType UntypedAttribute    = ItemType.UntypedAttribute;
        public static readonly XmlQueryType UntypedNode         = TF.Choice(UntypedDocument, UntypedElement, UntypedAttribute, Namespace, Text, Comment, PI);
        public static readonly XmlQueryType UntypedNodeS        = TF.PrimeProduct(UntypedNode, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType NodeNotRtf          = ItemType.NodeNotRtf;
        public static readonly XmlQueryType NodeNotRtfQ         = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrOne); 
        public static readonly XmlQueryType NodeNotRtfS         = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType NodeDodS            = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrMore);
        #endregion 

        //-----------------------------------------------
        // Helpers
        //----------------------------------------------- 

        ///  
        /// Construct the union of two lists of prime XmlQueryTypes.  Types are added to "accumulator" as necessary to ensure 
        /// it contains a superset of "types".
        ///  
        private static List PrimeChoice(List accumulator, IList types) {
            foreach (XmlQueryType sourceItem in types) {
                AddItemToChoice(accumulator, sourceItem);
            } 
            return accumulator;
        } 
 
        /// 
        /// Adds itemType to a union. Returns false if new item is a subtype of one of the types in the list. 
        /// 
        private static void AddItemToChoice(List accumulator, XmlQueryType itemType) {
            Debug.Assert(itemType.IsSingleton, "All types should be prime.");
 
            bool addToList = true;
            for (int i = 0; i < accumulator.Count; i++) { 
                // If new prime is a subtype of existing prime, don't add it to the union 
                if (itemType.IsSubtypeOf(accumulator[i])) {
                    return; 
                }

                // If new prime is a subtype of existing prime, then replace the existing prime with new prime
                if (accumulator[i].IsSubtypeOf(itemType)) { 
                    if (addToList) {
                        addToList = false; 
                        accumulator[i] = itemType; 
                    }
                    else { 
                        accumulator.RemoveAt(i);
                        i --;
                    }
                } 
            }
 
            if (addToList) { 
                accumulator.Add(itemType);
            } 
        }

        #region NodeKindToTypeCode
        ///  
        /// Map XPathNodeType to XmlTypeCode.
        ///  
        private static readonly XmlTypeCode[] NodeKindToTypeCode = { 
            /* XPathNodeType.Root */                    XmlTypeCode.Document,
            /* XPathNodeType.Element */                 XmlTypeCode.Element, 
            /* XPathNodeType.Attribute */               XmlTypeCode.Attribute,
            /* XPathNodeType.Namespace */               XmlTypeCode.Namespace,
            /* XPathNodeType.Text */                    XmlTypeCode.Text,
            /* XPathNodeType.SignificantWhitespace */   XmlTypeCode.Text, 
            /* XPathNodeType.Whitespace */              XmlTypeCode.Text,
            /* XPathNodeType.ProcessingInstruction */   XmlTypeCode.ProcessingInstruction, 
            /* XPathNodeType.Comment */                 XmlTypeCode.Comment, 
            /* XPathNodeType.All */                     XmlTypeCode.Node,
        }; 
        #endregion

        //-----------------------------------------------
        // XmlQueryType Implementations 
        //-----------------------------------------------
 
        ///  
        /// Implementation of XmlQueryType for singleton types.
        ///  
        private sealed class ItemType : XmlQueryType {
            // If you add new types here, add them to SpecialBuiltInItemTypes as well
            public static readonly XmlQueryType UntypedDocument;
            public static readonly XmlQueryType UntypedElement; 
            public static readonly XmlQueryType UntypedAttribute;
            public static readonly XmlQueryType NodeNotRtf; 
            public static readonly XmlQueryType NodeDod; 

            private static XmlQueryType[] BuiltInItemTypes; 
            private static XmlQueryType[] BuiltInItemTypesStrict;
            private static XmlQueryType[] SpecialBuiltInItemTypes;

            private XmlTypeCode code; 
            private XmlQualifiedNameTest nameTest;
            private XmlSchemaType schemaType; 
            private bool isNillable; 
            private XmlNodeKindFlags nodeKinds;
            private bool isStrict; 
            private bool isNotRtf;

            /// 
            /// Construct arrays of built-in types. 
            /// 
            static ItemType() { 
            #if DEBUG 
                Array arrEnum = Enum.GetValues(typeof(XmlTypeCode));
                Debug.Assert((XmlTypeCode) arrEnum.GetValue(arrEnum.Length - 1) == XmlTypeCode.DayTimeDuration, 
                             "DayTimeDuration is no longer the last item in XmlTypeCode.  This code expects it to be.");
            #endif

                int typeCount = (int) XmlTypeCode.DayTimeDuration + 1; 

                BuiltInItemTypes = new XmlQueryType[typeCount]; 
                BuiltInItemTypesStrict = new XmlQueryType[typeCount]; 

                for (int i = 0; i < typeCount; i++) { 
                    XmlTypeCode typeCode = (XmlTypeCode)i;

                    switch ((XmlTypeCode) i) {
                        case XmlTypeCode.None: 
                            BuiltInItemTypes[i] = ChoiceType.None;
                            BuiltInItemTypesStrict[i] = ChoiceType.None; 
                            continue; 

                        case XmlTypeCode.Item: 
                        case XmlTypeCode.Node:
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, false);
                            BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
                            break; 

                        case XmlTypeCode.Document: 
                        case XmlTypeCode.Element: 
                        case XmlTypeCode.Namespace:
                        case XmlTypeCode.ProcessingInstruction: 
                        case XmlTypeCode.Comment:
                        case XmlTypeCode.Text:
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true);
                            BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; 
                            break;
 
                        case XmlTypeCode.Attribute: 
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnySimpleType, false, false, true);
                            BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; 
                            break;

                        case XmlTypeCode.AnyAtomicType:
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnyAtomicType, false, false, true); 
                            BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
                            break; 
 
                        case XmlTypeCode.UntypedAtomic:
                            // xdt:untypedAtomic is sealed, and therefore always strict 
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, true, true);
                            BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
                            break;
 
                        default:
                            XmlSchemaType builtInType = XmlSchemaType.GetBuiltInSimpleType(typeCode); 
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, false, true); 
                            BuiltInItemTypesStrict[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, true, true);
                            break; 
                    }
                }

                UntypedDocument = new ItemType(XmlTypeCode.Document, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true); 
                UntypedElement = new ItemType(XmlTypeCode.Element, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true);
                UntypedAttribute = new ItemType(XmlTypeCode.Attribute, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, false, true); 
                NodeNotRtf = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true); 
                NodeDod = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true);
 
                SpecialBuiltInItemTypes = new XmlQueryType[4] { UntypedDocument, UntypedElement, UntypedAttribute, NodeNotRtf };
            }

            ///  
            /// Create ItemType from XmlTypeCode.
            ///  
            public static XmlQueryType Create(XmlTypeCode code, bool isStrict) { 
                // No objects need to be allocated, as corresponding ItemTypes for all type codes have been statically allocated
                if (isStrict) 
                    return BuiltInItemTypesStrict[(int) code];

                return BuiltInItemTypes[(int) code];
            } 

            ///  
            /// Create ItemType from Xsd atomic type. 
            /// 
            public static XmlQueryType Create(XmlSchemaSimpleType schemaType, bool isStrict) { 
                Debug.Assert(schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic, "List or Union Xsd types should have been handled by caller.");
                XmlTypeCode code = schemaType.Datatype.TypeCode;

                // If schemaType is a built-in type, 
                if (schemaType == XmlSchemaType.GetBuiltInSimpleType(code)) {
                    // Then use statically allocated type 
                    return Create(code, isStrict); 
                }
 
                // Otherwise, create a new type
                return new ItemType(code, XmlQualifiedNameTest.Wildcard, schemaType, false, isStrict, true);
            }
 
            /// 
            /// Create Document, Element or Attribute with specified name test, content type and nillable. 
            ///  
            public static XmlQueryType Create(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) {
                // If this is a Document, Element, or Attribute, 
                switch (code) {
                case XmlTypeCode.Document:
                case XmlTypeCode.Element:
                    if (nameTest.IsWildcard) { 
                        // Normalize document(*, xs:anyType), element(*, xs:anyType)
                        if (contentType == XmlSchemaComplexType.AnyType) 
                            return Create(code, false); 

                        // Normalize document(xs:untypedAny), element(*, xs:untypedAny) 
                        if (contentType == XmlSchemaComplexType.UntypedAnyType) {
                            Debug.Assert(!isNillable);
                            if (code == XmlTypeCode.Element)
                                return UntypedElement; 
                            if (code == XmlTypeCode.Document)
                                return UntypedDocument; 
                        } 
                    }
                    // Create new ItemType 
                    return new ItemType(code, nameTest, contentType, isNillable, false, true);

                case XmlTypeCode.Attribute:
                    if (nameTest.IsWildcard) { 
                        // Normalize attribute(xs:anySimpleType)
                        if (contentType == DatatypeImplementation.AnySimpleType) 
                            return Create(code, false); 

                        // Normalize attribute(xs:untypedAtomic) 
                        if (contentType == DatatypeImplementation.UntypedAtomicType)
                            return UntypedAttribute;
                    }
                    // Create new ItemType 
                    return new ItemType(code, nameTest, contentType, isNillable, false, true);
 
                default: 
                    return Create(code, false);
 
                }
            }

            ///  
            /// Private constructor.  Create methods should be used to create instances.
            ///  
            private ItemType(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType schemaType, bool isNillable, bool isStrict, bool isNotRtf) { 
                Debug.Assert(nameTest != null, "nameTest cannot be null");
                Debug.Assert(schemaType != null, "schemaType cannot be null"); 
                this.code = code;
                this.nameTest = nameTest;
                this.schemaType = schemaType;
                this.isNillable = isNillable; 
                this.isStrict = isStrict;
                this.isNotRtf = isNotRtf; 
 
                Debug.Assert(!IsAtomicValue || schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic);
 
                switch (code) {
                    case XmlTypeCode.Item: this.nodeKinds = XmlNodeKindFlags.Any; break;
                    case XmlTypeCode.Node: this.nodeKinds = XmlNodeKindFlags.Any; break;
                    case XmlTypeCode.Document: this.nodeKinds = XmlNodeKindFlags.Document; break; 
                    case XmlTypeCode.Element: this.nodeKinds = XmlNodeKindFlags.Element; break;
                    case XmlTypeCode.Attribute: this.nodeKinds = XmlNodeKindFlags.Attribute; break; 
                    case XmlTypeCode.Namespace: this.nodeKinds = XmlNodeKindFlags.Namespace; break; 
                    case XmlTypeCode.ProcessingInstruction: this.nodeKinds = XmlNodeKindFlags.PI; break;
                    case XmlTypeCode.Comment: this.nodeKinds = XmlNodeKindFlags.Comment; break; 
                    case XmlTypeCode.Text: this.nodeKinds = XmlNodeKindFlags.Text; break;
                    default: this.nodeKinds = XmlNodeKindFlags.None; break;
                }
            } 

            //----------------------------------------------- 
            // Serialization 
            //-----------------------------------------------
 
            /// 
            /// Serialize the object to BinaryWriter.
            /// 
            public override void GetObjectData(BinaryWriter writer) { 
                sbyte code = (sbyte) this.code;
 
                for (int idx = 0; idx < SpecialBuiltInItemTypes.Length; idx++) { 
                    if ((object) this == (object) SpecialBuiltInItemTypes[idx]) {
                        code = (sbyte) ~idx; 
                        break;
                    }
                }
 
                writer.Write(code);
 
                if (0 <= code) { 
                    Debug.Assert((object) this == (object) Create(this.code, this.isStrict), "Unknown type");
                    writer.Write(this.isStrict); 
                }
            }

            ///  
            /// Deserialize the object from BinaryReader.
            ///  
            public static XmlQueryType Create(BinaryReader reader) { 
                sbyte code = reader.ReadSByte();
 
                if (0 <= code)
                    return Create((XmlTypeCode) code, /*isStrict:*/reader.ReadBoolean());
                else
                    return SpecialBuiltInItemTypes[~code]; 
            }
 
            //----------------------------------------------- 
            // ItemType, OccurenceIndicator Properties
            //----------------------------------------------- 

            /// 
            /// Return the TypeCode.
            ///  
            public override XmlTypeCode TypeCode {
                get { return this.code; } 
            } 

            ///  
            /// Return the NameTest.
            /// 
            public override XmlQualifiedNameTest NameTest {
                get { return this.nameTest; } 
            }
 
            ///  
            /// Return the Xsd schema type.  This must be non-null for atomic value types.
            ///  
            public override XmlSchemaType SchemaType {
                get { return this.schemaType; }
            }
 
            /// 
            /// Return the IsNillable. 
            ///  
            public override bool IsNillable {
                get { return this.isNillable; } 
            }

            /// 
            /// Since this is always an atomic value type, NodeKinds = None. 
            /// 
            public override XmlNodeKindFlags NodeKinds { 
                get { return this.nodeKinds; } 
            }
 
            /// 
            /// Return flag indicating whether the dynamic type is guaranteed to be the same as the static type.
            /// 
            public override bool IsStrict { 
                get { return this.isStrict; }
            } 
 
            /// 
            /// Return flag indicating whether this is not an Rtf. 
            /// 
            public override bool IsNotRtf {
                get { return this.isNotRtf; }
            } 

            ///  
            /// Only NodeDod type returns true. 
            /// 
            public override bool IsDod { 
                get { return (object) this == (object) NodeDod; }
            }

            ///  
            /// Always return cardinality One.
            ///  
            public override XmlQueryCardinality Cardinality { 
                get { return XmlQueryCardinality.One; }
            } 

            /// 
            /// Prime of atomic value type is itself.
            ///  
            public override XmlQueryType Prime {
                get { return this; } 
            } 

            ///  
            /// Return the item's converter.
            /// 
            public override XmlValueConverter ClrMapping {
                get { 
                    // Return value converter from XmlSchemaType if type is atomic
                    if (IsAtomicValue) 
                        return SchemaType.ValueConverter; 

                    // Return node converter if item must be a node 
                    if (IsNode)
                        return XmlNodeConverter.Node;

                    // Otherwise return item converter 
                    return XmlAnyConverter.Item;
                } 
            } 

 
            //-----------------------------------------------
            // ListBase implementation
            //-----------------------------------------------
 
            /// 
            /// AtomicValueType is only a composition of itself, rather than other smaller types. 
            ///  
            public override int Count {
                get { return 1; } 
            }

            /// 
            /// AtomicValueType is only a composition of itself, rather than other smaller types. 
            /// 
            public override XmlQueryType this[int index] { 
                get { 
                    if (index != 0)
                        throw new IndexOutOfRangeException(); 

                    return this;
                }
                set { throw new NotSupportedException(); } 
            }
        } 
 

        ///  
        /// Implementation of XmlQueryType that composes a choice of various prime types.
        /// 
        private sealed class ChoiceType : XmlQueryType {
            public static readonly XmlQueryType None = new ChoiceType(new List()); 

            private XmlTypeCode code; 
            private XmlSchemaType schemaType; 
            private XmlNodeKindFlags nodeKinds;
            private List members; 

            /// 
            /// Create choice between node kinds.
            ///  
            public static XmlQueryType Create(XmlNodeKindFlags nodeKinds) {
                List members; 
 
                // If exactly one kind is set, then create singleton ItemType
                if (Bits.ExactlyOne((uint) nodeKinds)) 
                    return ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint) nodeKinds)], false);

                members = new List();
                while (nodeKinds != XmlNodeKindFlags.None) { 
                    members.Add(ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint) nodeKinds)], false));
 
                    nodeKinds = (XmlNodeKindFlags) Bits.ClearLeast((uint) nodeKinds); 
                }
 
                return Create(members);
            }

            ///  
            /// Create choice containing the specified list of types.
            ///  
            public static XmlQueryType Create(List members) { 
                if (members.Count == 0)
                    return None; 

                if (members.Count == 1)
                    return members[0];
 
                return new ChoiceType(members);
            } 
 
            /// 
            /// Private constructor.  Create methods should be used to create instances. 
            /// 
            private ChoiceType(List members) {
                Debug.Assert(members != null && members.Count != 1, "ChoiceType must contain a list with 0 or >1 types.");
 
                this.members = members;
 
                // Compute supertype of all member types 
                for (int i = 0; i < members.Count; i++) {
                    XmlQueryType t = members[i]; 
                    Debug.Assert(t.Cardinality == XmlQueryCardinality.One, "ChoiceType member types must be prime types.");

                    // Summarize the union of member types as a single type
                    if (this.code == XmlTypeCode.None) { 
                        // None combined with member type is the member type
                        this.code = t.TypeCode; 
                        this.schemaType = t.SchemaType; 
                    }
                    else if (IsNode && t.IsNode) { 
                        // Node combined with node is node
                        if (this.code == t.TypeCode) {
                            // Element or attribute combined with element or attribute can be summarized as element(*, XmlSchemaComplexType.AnyType) or attribute(*, DatatypeImplementation.AnySimpleType)
                            if (this.code == XmlTypeCode.Element) 
                                this.schemaType = XmlSchemaComplexType.AnyType;
                            else if (this.code == XmlTypeCode.Attribute) 
                                this.schemaType = DatatypeImplementation.AnySimpleType; 
                        }
                        else { 
                            this.code = XmlTypeCode.Node;
                            this.schemaType = null;
                        }
                    } 
                    else if (IsAtomicValue && t.IsAtomicValue) {
                        // Atomic value combined with atomic value is atomic value 
                        this.code = XmlTypeCode.AnyAtomicType; 
                        this.schemaType = DatatypeImplementation.AnyAtomicType;
                    } 
                    else {
                        // Else we'll summarize types as Item
                        this.code = XmlTypeCode.Item;
                        this.schemaType = null; 
                    }
 
                    // Always track union of node kinds 
                    this.nodeKinds |= t.NodeKinds;
                } 
            }

            private static readonly XmlTypeCode[] NodeKindToTypeCode = {
                /* None */          XmlTypeCode.None, 
                /* Document */      XmlTypeCode.Document,
                /* Element */       XmlTypeCode.Element, 
                /* Attribute */     XmlTypeCode.Attribute, 
                /* Text */          XmlTypeCode.Text,
                /* Comment */       XmlTypeCode.Comment, 
                /* PI */            XmlTypeCode.ProcessingInstruction,
                /* Namespace */     XmlTypeCode.Namespace,
            };
 
            //-----------------------------------------------
            // Serialization 
            //----------------------------------------------- 

            ///  
            /// Serialize the object to BinaryWriter.
            /// 
            public override void GetObjectData(BinaryWriter writer) {
                writer.Write(this.members.Count); 
                for (int i = 0; i < this.members.Count; i++) {
                    TF.Serialize(writer, this.members[i]); 
                } 
            }
 
            /// 
            /// Deserialize the object from BinaryReader.
            /// 
            public static XmlQueryType Create(BinaryReader reader) { 
                int length = reader.ReadInt32();
                List members = new List(length); 
                for (int i = 0; i < length; i++) { 
                    members.Add(TF.Deserialize(reader));
                } 
                return Create(members);
            }

            //----------------------------------------------- 
            // ItemType, OccurenceIndicator Properties
            //----------------------------------------------- 
 
            /// 
            /// Return a type code which is a supertype of all member types. 
            /// 
            public override XmlTypeCode TypeCode {
                get { return this.code; }
            } 

            ///  
            /// Return the NameTest. 
            /// 
            public override XmlQualifiedNameTest NameTest { 
                get { return XmlQualifiedNameTest.Wildcard; }
            }

            ///  
            /// Return an Xsd schema type which is a supertype of all member types.
            ///  
            public override XmlSchemaType SchemaType { 
                get { return this.schemaType; }
            } 

            /// 
            /// Return the IsNillable.
            ///  
            public override bool IsNillable {
                get { return false; } 
            } 

            ///  
            /// Return a set of NodeKinds which is the union of all member node kinds.
            /// 
            public override XmlNodeKindFlags NodeKinds {
                get { return this.nodeKinds; } 
            }
 
            ///  
            /// Choice types are always non-strict, except for the empty choice.
            ///  
            public override bool IsStrict {
                get { return members.Count == 0; }
            }
 
            /// 
            /// Return true if every type in the choice is not an Rtf. 
            ///  
            public override bool IsNotRtf {
                get { 
                    for (int i = 0; i < members.Count; i++) {
                        if (!this.members[i].IsNotRtf)
                            return false;
                    } 
                    return true;
                } 
            } 

            ///  
            /// Return true if every type in the choice is in document order with no duplicates.
            /// 
            public override bool IsDod {
                get { 
                    for (int i = 0; i < members.Count; i++) {
                        if (!this.members[i].IsDod) 
                            return false; 
                    }
                    return true; 
                }
            }

            ///  
            /// Always return cardinality none or one.
            ///  
            public override XmlQueryCardinality Cardinality { 
                get { return TypeCode == XmlTypeCode.None ? XmlQueryCardinality.None : XmlQueryCardinality.One; }
            } 

            /// 
            /// Prime of union type is itself.
            ///  
            public override XmlQueryType Prime {
                get { return this; } 
            } 

            ///  
            /// Always return the item converter.
            /// 
            public override XmlValueConverter ClrMapping {
                get { 
                    if (this.code == XmlTypeCode.None || this.code == XmlTypeCode.Item)
                        return XmlAnyConverter.Item; 
 
                    if (IsAtomicValue)
                        return SchemaType.ValueConverter; 

                    return XmlNodeConverter.Node;
                }
            } 

            //----------------------------------------------- 
            // ListBase implementation 
            //-----------------------------------------------
 
            /// 
            /// Return the number of union member types.
            /// 
            public override int Count { 
                get { return this.members.Count; }
            } 
 
            /// 
            /// Return a union member type by index. 
            /// 
            public override XmlQueryType this[int index] {
                get { return this.members[index]; }
                set { throw new NotSupportedException(); } 
            }
        } 
 

        ///  
        /// Implementation of XmlQueryType that modifies the cardinality of a composed type.
        /// 
        private sealed class SequenceType : XmlQueryType {
            public static readonly XmlQueryType Zero = new SequenceType(ChoiceType.None, XmlQueryCardinality.Zero); 

            private XmlQueryType prime; 
            private XmlQueryCardinality card; 
            private XmlValueConverter converter;
 
            /// 
            /// Create sequence type from prime and cardinality.
            /// 
            public static XmlQueryType Create(XmlQueryType prime, XmlQueryCardinality card) { 
                Debug.Assert(prime != null, "SequenceType can only modify the cardinality of a non-null XmlQueryType.");
                Debug.Assert(prime.IsSingleton, "Prime type must have cardinality one."); 
 
                if (prime.TypeCode == XmlTypeCode.None) {
                    // If cardinality includes zero, then return (None, Zero), else return (None, None). 
                    return XmlQueryCardinality.Zero <= card ? Zero : None;
                }

                // Normalize sequences with these cardinalities: None, Zero, One 

                if (card == XmlQueryCardinality.None) { 
                    return None; 
                }
                else if (card == XmlQueryCardinality.Zero) { 
                    return Zero;
                }
                else if (card == XmlQueryCardinality.One) {
                    return prime; 
                }
 
                return new SequenceType(prime, card); 
            }
 
            /// 
            /// Private constructor.  Create methods should be used to create instances.
            /// 
            private SequenceType(XmlQueryType prime, XmlQueryCardinality card) { 
                this.prime = prime;
                this.card = card; 
            } 

            //----------------------------------------------- 
            // Serialization
            //-----------------------------------------------

            ///  
            /// Serialize the object to BinaryWriter.
            ///  
            public override void GetObjectData(BinaryWriter writer) { 
                writer.Write(this.IsDod);
                if (this.IsDod) 
                    return;

                TF.Serialize(writer, this.prime);
                this.card.GetObjectData(writer); 
            }
 
            ///  
            /// Deserialize the object from BinaryReader.
            ///  
            public static XmlQueryType Create(BinaryReader reader) {
                if (reader.ReadBoolean())
                    return TF.NodeDodS;
 
                XmlQueryType prime = TF.Deserialize(reader);
                XmlQueryCardinality card = new XmlQueryCardinality(reader); 
                return Create(prime, card); 
            }
 
            //-----------------------------------------------
            // ItemType, OccurenceIndicator Properties
            //-----------------------------------------------
 
            /// 
            /// Return the TypeCode of the prime type. 
            ///  
            public override XmlTypeCode TypeCode {
                get { return this.prime.TypeCode; } 
            }

            /// 
            /// Return the NameTest of the prime type 
            /// 
            public override XmlQualifiedNameTest NameTest { 
                get { return this.prime.NameTest; } 
            }
 
            /// 
            /// Return the Xsd schema type of the prime type.
            /// 
            public override XmlSchemaType SchemaType { 
                get { return this.prime.SchemaType; }
            } 
 
            /// 
            /// Return the IsNillable of the prime type 
            /// 
            public override bool IsNillable {
                get { return this.prime.IsNillable; }
            } 

            ///  
            /// Return the NodeKinds of the prime type. 
            /// 
            public override XmlNodeKindFlags NodeKinds { 
                get { return this.prime.NodeKinds; }
            }

            ///  
            /// Return the IsStrict flag of the prime type.
            ///  
            public override bool IsStrict { 
                get { return this.prime.IsStrict; }
            } 

            /// 
            /// Return the IsNotRtf flag of the prime type.
            ///  
            public override bool IsNotRtf {
                get { return this.prime.IsNotRtf; } 
            } 

            ///  
            /// Return the IsDod flag of the prime type.
            /// 
            public override bool IsDod {
                get { return (object) this == (object) NodeDodS; } 
            }
 
            ///  
            /// Return the modified cardinality.
            ///  
            public override XmlQueryCardinality Cardinality {
                get { return this.card; }
            }
 
            /// 
            /// Return prime of sequence type. 
            ///  
            public override XmlQueryType Prime {
                get { return this.prime; } 
            }

            /// 
            /// Return the prime's converter wrapped in a list converter. 
            /// 
            public override XmlValueConverter ClrMapping { 
                get { 
                    if (this.converter == null)
                        this.converter = XmlListConverter.Create(this.prime.ClrMapping); 

                    return this.converter;
                }
            } 

 
            //----------------------------------------------- 
            // ListBase implementation
            //----------------------------------------------- 

            /// 
            /// Return the Count of the prime type.
            ///  
            public override int Count {
                get { return this.prime.Count; } 
            } 

            ///  
            /// Return the parts of the prime type.
            /// 
            public override XmlQueryType this[int index] {
                get { return this.prime[index]; } 
                set { throw new NotSupportedException(); }
            } 
        } 

        ///  
        /// Create a Node XmlQueryType having an XSD content type.
        /// 
        /// unless kind is Root, Element, or Attribute, "contentType" is ignored
        /// content type of the node 
        /// the node type
        public static XmlQueryType Type(XPathNodeType kind, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) { 
            return ItemType.Create(NodeKindToTypeCode[(int)kind], nameTest, contentType, isNillable); 
        }
 
        #region Serialization
        /// 
        /// Check if the given type can be serialized.
        ///  
        [Conditional("DEBUG")]
        public static void CheckSerializability(XmlQueryType type) { 
            type.GetObjectData(new BinaryWriter(Stream.Null)); 
        }
 
        /// 
        /// Serialize XmlQueryType to BinaryWriter.
        /// 
        public static void Serialize(BinaryWriter writer, XmlQueryType type) { 
            sbyte subtypeId;
 
            if (type.GetType() == typeof(ItemType)) 
                subtypeId = 0;
            else if (type.GetType() == typeof(ChoiceType)) 
                subtypeId = 1;
            else if (type.GetType() == typeof(SequenceType))
                subtypeId = 2;
            else { 
                Debug.Fail("Don't know how to serialize " + type.GetType().ToString());
                subtypeId = -1; 
            } 

            writer.Write(subtypeId); 
            type.GetObjectData(writer);
        }

        ///  
        /// Deserialize XmlQueryType from BinaryReader.
        ///  
        public static XmlQueryType Deserialize(BinaryReader reader) { 
            switch (reader.ReadByte()) {
            case 0: return ItemType.Create(reader); 
            case 1: return ChoiceType.Create(reader);
            case 2: return SequenceType.Create(reader);
            default:
                Debug.Fail("Unexpected XmlQueryType's subtype id"); 
                return null;
            } 
        } 
        #endregion
 
    #if NEVER   // Remove from code since we don't use and FxCop complains.  May re-add later.
        private XmlSchemaSet schemaSet;

        ///  
        /// Create an XmlQueryType having an XSD name test, content type and nillable.
        ///  
        /// unless code is Document, Element, or Attribute, "contentType" is ignored 
        /// name test on the node
        /// content type of the node 
        /// nillable property
        /// the item type
        public XmlQueryType Type(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) {
            return ItemType.Create(code, nameTest, contentType, isNillable); 
        }
 
        ///  
        /// Create a strict XmlQueryType from the source.
        ///  
        /// source type
        /// strict type if the source is atomic, the source otherwise
        public XmlQueryType StrictType(XmlQueryType source) {
            if (source.IsAtomicValue && source.Count == 1) 
                return SequenceType.Create(ItemType.Create((XmlSchemaSimpleType)source.SchemaType, true), source.Cardinality);
 
            return source; 
        }
 
        /// 
        /// Create an XmlQueryType from an XmlTypeCode and cardinality.
        /// 
        /// the type code of the item 
        /// cardinality
        /// build-in type type 
        public XmlQueryType Type(XmlTypeCode code, XmlQueryCardinality card) { 
            return SequenceType.Create(ItemType.Create(code, false), card);
        } 

        /// 
        /// Create an XmlQueryType having an XSD name test, content type, nillable and cardinality.
        ///  
        /// unless code is Document, Element, or Attribute, "contentType" is ignored
        /// name test on the node 
        /// content type of the node 
        /// nillable property
        /// cardinality 
        /// the item type
        public XmlQueryType Type(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable, XmlQueryCardinality card) {
            return SequenceType.Create(ItemType.Create(code, nameTest, contentType, isNillable), card);
        } 

        ///  
        /// Construct the intersection of two XmlQueryTypes 
        /// 
        /// the left type 
        /// the right type
        /// the intersection type
        public XmlQueryType Intersect(XmlQueryType left, XmlQueryType right) {
            return SequenceType.Create(ChoiceType.Create(PrimeIntersect(left, right)), left.Cardinality & right.Cardinality); 
        }
 
        ///  
        /// Construct the intersection of several XmlQueryTypes
        ///  
        /// the list of types
        /// the intersection type
        public XmlQueryType Intersect(params XmlQueryType[] types) {
            if (types.Length == 0) 
                return None;
            else if (types.Length == 1) 
                return types[0]; 

            // Intersect each type with next type 
            List list = PrimeIntersect(types[0], types[1]);
            XmlQueryCardinality card = types[0].Cardinality & types[1].Cardinality;

            for (int i = 2; i < types.Length; i++) { 
                list = PrimeIntersect(list, types[i]);
                card &= types[i].Cardinality; 
            } 

            return SequenceType.Create(ChoiceType.Create(list), card); 
        }

        /// 
        /// Construct the intersection of two lists of prime XmlQueryTypes. 
        /// 
        private List PrimeIntersect(IList left, IList right) { 
            List list = new List(); 

            foreach (XmlQueryType leftItem in left) { 
                foreach (XmlQueryType rightItem in right) {
                    XmlQueryType intersection = IntersectItemTypes(leftItem, rightItem);
                    // Do not add none1 to a list
                    if ((object)intersection != (object)None) { 
                        list.Add(intersection);
                    } 
                } 
            }
            return list; 
        }

        /// 
        /// Converts type of sequence of items to type of sequnce of atomic value 
        //  See http://www.w3.org/TR/2004/xquery-semantics/#jd_data for the detailed description
        ///  
        /// source type 
        /// type of the sequence of atomic values
        public XmlQueryType DataOn(XmlQueryType source) { 
            List list = new List();
            XmlQueryCardinality card = XmlQueryCardinality.None;

            foreach (XmlQueryType sourceItem  in source) { 
                switch (sourceItem.TypeCode) {
                case XmlTypeCode.Item: 
                case XmlTypeCode.Node: 
                    AddItemToChoice(list, AnyAtomicType);
                    card = XmlQueryCardinality.ZeroOrMore; 
                    break;
                case XmlTypeCode.Document:
                case XmlTypeCode.Text:
                    AddItemToChoice(list, UntypedAtomic); 
                    card |= XmlQueryCardinality.One;
                    break; 
                case XmlTypeCode.Comment: 
                case XmlTypeCode.ProcessingInstruction:
                    AddItemToChoice(list, String); 
                    card |= XmlQueryCardinality.One;
                    break;
                case XmlTypeCode.Element:
                case XmlTypeCode.Attribute: 
                    XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
                    if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType || sourceSchemaType == DatatypeImplementation.UntypedAtomicType) { 
                        AddItemToChoice(list, UntypedAtomic); 
                        card |= XmlQueryCardinality.One;
                    } 
                    else if (sourceSchemaType == XmlSchemaComplexType.AnyType || sourceSchemaType == DatatypeImplementation.AnySimpleType) {
                        AddItemToChoice(list, AnyAtomicType);
                        card = XmlQueryCardinality.ZeroOrMore;
                    } 
                    else {
                        if (sourceSchemaType.Datatype == null) { 
                            // Complex content adds anyAtomicType* if mixed 
                            XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceItem.SchemaType;
                            if (complexType.ContentType == XmlSchemaContentType.Mixed) { 
                                AddItemToChoice(list, AnyAtomicType);
                                card = XmlQueryCardinality.ZeroOrMore;
                            }
                            else { 
                                // Error if mixed is false
                                return null; 
                            } 
                        }
                        else { 
                            // Simple content
                            XmlSchemaType schemaType = sourceItem.SchemaType;

                            // Go up the tree until it's a simple type 
                            while (schemaType is XmlSchemaComplexType) {
                                schemaType = schemaType.BaseXmlSchemaType; 
                            } 

                            // Calculate XmlQueryType from XmlSchemaSimpleType 
                            XmlQueryType atomicSeq = Type((XmlSchemaSimpleType)schemaType, false);

                            // Add prime to a choice
                            // It doen't have to be a single item! 
                            PrimeChoice(list, atomicSeq.Prime);
 
                            // Add cardinality to a choice 
                            card |= atomicSeq.Cardinality;
                        } 
                        // Add ? if nillable
                        if (sourceItem.IsNillable) {
                            card *= XmlQueryCardinality.ZeroOrOne;
                        } 
                    }
                    break; 
                case XmlTypeCode.Namespace: 
                    card |= XmlQueryCardinality.Zero;
                    break; 
                case XmlTypeCode.None:
                    break;
                default:
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); 
                    AddItemToChoice(list, sourceItem);
                    card |= XmlQueryCardinality.One; 
                    break; 
                }
            } 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
        }

        ///  
        /// Filter type of node sequence with a type (filter)
        ///  
        /// source type 
        /// type filter
        /// type of the filtered node sequence 
        public XmlQueryType FilterOf(XmlQueryType source, XmlQueryType filter) {
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
            List list = new List();
            XmlQueryCardinality card = XmlQueryCardinality.None; 

            foreach (XmlQueryType sourceItem in source) { 
                card |= AddFilteredPrime(list, sourceItem, filter, true); 
            }
            // Make sure that cardinality is at least Zero 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
        }

        ///  
        /// For the type of node sequence calculate type of children filtered with a type (filter)
        ///  
        /// source type 
        /// type filter
        /// type of the children node sequence 
        public XmlQueryType ChildrenOf(XmlQueryType source, XmlQueryType filter) {
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
            List list = new List();
            XmlQueryCardinality card = XmlQueryCardinality.None; 

            foreach (XmlQueryType sourceItem in source) { 
                switch (sourceItem.TypeCode) { 
                case XmlTypeCode.Node:
                case XmlTypeCode.Document: 
                case XmlTypeCode.Element:
                    XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
                    XmlQueryCardinality itemCard = XmlQueryCardinality.None;
                    // Only element and document can have children 
                    if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) {
                        // content of xdt:untypedAny is element(*, xdt:untypedAny)* 
                        itemCard = (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore); 
                        itemCard += AddFilteredPrime(list, Text, filter);
                    } 
                    else if (sourceSchemaType.Datatype != null) {
                        // Text is the only child node simple type can have
                        itemCard = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne;
                    } 
                    else {
                        // Complex content 
                        XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType; 
                        itemCard = AddChildParticle(list, complexType.ContentTypeParticle, filter);
                        if (complexType.ContentType == XmlSchemaContentType.Mixed) { 
                            itemCard += AddFilteredPrime(list, Text, filter);
                        }
                    }
                    itemCard += AddFilteredPrime(list, PI, filter); 
                    itemCard += AddFilteredPrime(list, Comment, filter);
                    card |= itemCard; 
                    break; 

                case XmlTypeCode.Attribute: 
                case XmlTypeCode.ProcessingInstruction:
                case XmlTypeCode.Comment:
                case XmlTypeCode.Namespace:
                case XmlTypeCode.Text: 
                    card |= XmlQueryCardinality.Zero;
                    break; 
 
                default:
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); 
                    return null;
                }
            }
            // Make sure that cardinality is at least Zero 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
        } 
 
        /// 
        /// For the type of node sequence calculate type of attributes filtered with a type (filter) 
        /// 
        /// source type
        /// type filter
        /// type of the children node sequence 
        public XmlQueryType AttributesOf(XmlQueryType source, XmlQueryType filter) {
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); 
            List list = new List(); 
            XmlQueryCardinality card = XmlQueryCardinality.None;
 
            foreach (XmlQueryType sourceItem in source) {
                switch (sourceItem.TypeCode) {
                case XmlTypeCode.Node:
                case XmlTypeCode.Element: 
                    XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
                    if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { 
                        // attfibutes of of xdt:untypedAny are attribute(*, xdt:untypedAtomic)* 
                        card |= AddFilteredPrime(list, UntypedAttribute, filter) * XmlQueryCardinality.ZeroOrOne;
                    } 
                    else {
                        // Only complex type can have attributes
                        XmlSchemaComplexType type = sourceSchemaType as XmlSchemaComplexType;
                        if (type != null) { 
                            card |= AddAttributes(list, type.AttributeUses, type.AttributeWildcard, filter);
                        } 
                    } 
                    break;
 
                case XmlTypeCode.Document:
                case XmlTypeCode.Attribute:
                case XmlTypeCode.ProcessingInstruction:
                case XmlTypeCode.Comment: 
                case XmlTypeCode.Namespace:
                case XmlTypeCode.Text: 
                    card |= XmlQueryCardinality.Zero; 
                    break;
 
                default:
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
                    return null;
                } 
            }
            // Make sure that cardinality is at least Zero 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); 
        }
 
        /// 
        /// For the type of node sequence calculate type of parent filtered with a type (filter)
        /// 
        /// source type 
        /// type filter
        /// type of the parent node sequence 
        public XmlQueryType ParentOf(XmlQueryType source, XmlQueryType filter) { 
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
            List list = new List(); 
            XmlQueryCardinality card = XmlQueryCardinality.None;

            foreach (XmlQueryType sourceItem  in source) {
                switch (sourceItem.TypeCode) { 
                case XmlTypeCode.Node:
                case XmlTypeCode.ProcessingInstruction: 
                case XmlTypeCode.Comment: 
                case XmlTypeCode.Text:
                case XmlTypeCode.Element: 
                    if (schemaSet == null) {
                        card |= AddFilteredPrime(list, UntypedDocument, filter) * XmlQueryCardinality.ZeroOrOne;
                        card |= AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrOne;
                    } 
                    else {
                        card |= AddFilteredPrime(list, Document, filter) * XmlQueryCardinality.ZeroOrOne; 
                        card |= AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrOne; 
                    }
                    break; 

                case XmlTypeCode.Namespace:
                case XmlTypeCode.Attribute:
                    if (schemaSet == null) { 
                        card |= (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrOne);
                    } 
                    else { 
                        card |= (AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrOne);
                    } 
                    break;

                case XmlTypeCode.Document:
                    card |= XmlQueryCardinality.Zero; 
                    break;
 
                default: 
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
                    break; 
                }
            }
            // Make sure that cardinality is at least Zero
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); 
        }
 
        ///  
        /// For the type of node sequence calculate type of descendants filtered with a type (filter)
        ///  
        /// source type
        /// type filter
        /// type of the descendants node sequence
        public XmlQueryType DescendantsOf(XmlQueryType source, XmlQueryType filter) { 
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
            List list = new List(); 
            XmlQueryCardinality card = XmlQueryCardinality.None; 

            foreach (XmlQueryType sourceItem  in source) { 
                switch (sourceItem.TypeCode) {
                case XmlTypeCode.Node:
                case XmlTypeCode.Document:
                case XmlTypeCode.Element: 
                    XmlQueryCardinality itemCard = XmlQueryCardinality.None;
                    if ((filter.NodeKinds & (XmlNodeKindFlags.Element | XmlNodeKindFlags.Text)) != 0) { 
                        Dictionary allTypes = new Dictionary(); 
                        XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
                        if (sourceSchemaType == null) { 
                            Debug.Assert(sourceItem.TypeCode == XmlTypeCode.Node);
                            sourceSchemaType = XmlSchemaComplexType.AnyType;
                        }
                        itemCard = AddElementOrTextDescendants(list, allTypes, sourceSchemaType, filter); 
                    }
                    itemCard += AddFilteredPrime(list, PI, filter); 
                    itemCard += AddFilteredPrime(list, Comment, filter); 
                    card |= itemCard;
                    break; 

                case XmlTypeCode.Attribute:
                case XmlTypeCode.ProcessingInstruction:
                case XmlTypeCode.Comment: 
                case XmlTypeCode.Namespace:
                case XmlTypeCode.Text: 
                    card |= XmlQueryCardinality.Zero; 
                    break;
 
                default:
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
                        break;
                } 
            }
            // Make sure that cardinality is at least Zero 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); 
        }
 
        /// 
        /// For the type of node sequence calculate type of ancestor filtered with a type (filter)
        /// 
        /// source type 
        /// type filter
        /// type of the ancestor node sequence 
        public XmlQueryType AncestorsOf(XmlQueryType source, XmlQueryType filter) { 
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
            List list = new List(); 
            XmlQueryCardinality card = XmlQueryCardinality.None;

            foreach (XmlQueryType sourceItem  in source) {
                switch (sourceItem.TypeCode) { 
                case XmlTypeCode.Node:
                case XmlTypeCode.ProcessingInstruction: 
                case XmlTypeCode.Comment: 
                case XmlTypeCode.Text:
                case XmlTypeCode.Element: 
                case XmlTypeCode.Namespace:
                case XmlTypeCode.Attribute:
                    if (schemaSet == null) {
                        card |= (AddFilteredPrime(list, UntypedDocument, filter) * XmlQueryCardinality.ZeroOrOne) 
                                + (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore);
                    } 
                    else { 
                        card |= (AddFilteredPrime(list, Document, filter) * XmlQueryCardinality.ZeroOrOne)
                                + (AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrMore); 
                    }
                    break;

                case XmlTypeCode.Document: 
                    card |= XmlQueryCardinality.Zero;
                    break; 
 
                default:
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); 
                    break;
                }
            }
            // Make sure that cardinality is at least Zero 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
        } 
 
        private XmlQueryCardinality AddAttributes(List list, XmlSchemaObjectTable attributeUses, XmlSchemaAnyAttribute attributeWildcard, XmlQueryType filter) {
            XmlQueryCardinality card = XmlQueryCardinality.Zero; 
            if (attributeWildcard != null) {
                XmlSchemaType attributeSchemaType = attributeWildcard.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? DatatypeImplementation.UntypedAtomicType : DatatypeImplementation.AnySimpleType;

                // wildcard will match more then one attribute 
                switch (attributeWildcard.NamespaceList.Type) {
                case NamespaceList.ListType.Set: 
                    foreach (string ns in attributeWildcard.NamespaceList.Enumerate) { 
                        card += AddFilteredPrime(list, CreateAttributeType(ns, false, attributeSchemaType), filter);
                    } 
                    break;
                case NamespaceList.ListType.Other:
                    card += AddFilteredPrime(list, CreateAttributeType(attributeWildcard.NamespaceList.Excluded, true, attributeSchemaType), filter);
                    break; 
                case NamespaceList.ListType.Any:
                default: 
                    card +=  AddFilteredPrime(list, attributeWildcard.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedAttribute : Attribute, filter); 
                    break;
                } 
                // Always optional
                card *= XmlQueryCardinality.ZeroOrOne;
            }
            foreach (XmlSchemaAttribute attribute in attributeUses.Values) { 
                XmlQueryCardinality cardAttr = AddFilteredPrime(list, CreateAttributeType(attribute), filter);
                if (cardAttr != XmlQueryCardinality.Zero) { 
                    Debug.Assert(cardAttr == XmlQueryCardinality.ZeroOrOne || cardAttr == XmlQueryCardinality.One); 
                    card += (attribute.Use == XmlSchemaUse.Optional ? XmlQueryCardinality.ZeroOrOne : cardAttr);
                } 
            }
            return card;
        }
 
        private XmlQueryType CreateAttributeType(XmlSchemaAttribute attribute) {
            return ItemType.Create(XmlTypeCode.Attribute, XmlQualifiedNameTest.New(attribute.QualifiedName), attribute.AttributeSchemaType, false); 
        } 

        private XmlQueryType CreateAttributeType(string ns, bool exclude, XmlSchemaType schemaType) { 
            return ItemType.Create(XmlTypeCode.Attribute, XmlQualifiedNameTest.New(ns, exclude), schemaType, false);
        }

        private XmlQueryCardinality AddDescendantParticle(List list, Dictionary allTypes, XmlSchemaParticle particle, XmlQueryType filter) { 
            XmlQueryCardinality card = XmlQueryCardinality.None;
            XmlSchemaElement element = particle as XmlSchemaElement; 
            if (element != null) { 
                // Single element
                XmlQueryType elementType = CreateElementType(element); 

                // Add it
                card = AddFilteredPrime(list, elementType, filter);
 
                // Descend
                card += AddElementOrTextDescendants(list, allTypes, elementType.SchemaType, filter); 
            } 
            else {
                XmlSchemaAny any = particle as XmlSchemaAny; 
                if (any != null) {
                    // Descendants of any
                    card = AddFilteredPrime(list, Element, filter);
                } 
                else {
                    XmlSchemaGroupBase group = particle as XmlSchemaGroupBase; 
                    if (group.Items.Count != 0) { 
                        if (particle is XmlSchemaChoice) {
                            foreach (XmlSchemaParticle p in group.Items) { 
                                card |= AddDescendantParticle(list, allTypes, p, filter);
                            }
                        }
                        else { // Sequence and  All 
                            foreach (XmlSchemaParticle p in group.Items) {
                                card += AddDescendantParticle(list, allTypes, p, filter); 
                            } 
                        }
                    } 
                }
            }
            return card * CardinalityOfParticle(particle);
        } 

        private XmlQueryCardinality AddElementOrTextDescendants(List list, 
            Dictionary allTypes, XmlSchemaType sourceSchemaType, XmlQueryType filter) { 
            XmlQueryCardinality card = XmlQueryCardinality.None;
            if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { 
                card = AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore;
                card += AddFilteredPrime(list, Text, filter);
            }
            else if (sourceSchemaType.Datatype != null) { 
                // Text is the only child node simple content of complext type
                card = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne; 
            } 
            else {
                // Complex content 
                XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType;
                if (complexType.QualifiedName.IsEmpty || !allTypes.TryGetValue(complexType.QualifiedName, out card)) {
                    allTypes[complexType.QualifiedName] = XmlQueryCardinality.ZeroOrMore; // take care of left recursion
                    card = AddDescendantParticle(list, allTypes, complexType.ContentTypeParticle, filter); 
                    allTypes[complexType.QualifiedName] = card;  //set correct card
                    if (complexType.ContentType == XmlSchemaContentType.Mixed) { 
                        card += AddFilteredPrime(list, Text, filter); 
                    }
                } 
            }
            return card;
        }
 
        /// 
        /// Create type based on an XmlSchemaElement 
        ///  
        private XmlQueryType CreateElementType(XmlSchemaElement element) {
            return ItemType.Create(XmlTypeCode.Element, XmlQualifiedNameTest.New(element.QualifiedName), element.ElementSchemaType, element.IsNillable); 
        }

        /// 
        /// Create type based on a wildcard 
        /// 
        private XmlQueryType CreateElementType(string ns, bool exclude, XmlSchemaType schemaType) { 
            return ItemType.Create(XmlTypeCode.Element, XmlQualifiedNameTest.New(ns, exclude), schemaType, false); 
        }
 
        /// 
        ///  Descend though the content model
        /// 
        private XmlQueryCardinality AddChildParticle(List list, XmlSchemaParticle particle, XmlQueryType filter) { 
            XmlQueryCardinality card = XmlQueryCardinality.None;
            XmlSchemaElement element = particle as XmlSchemaElement; 
            if (element != null) { 
                // Single element
                card = AddFilteredPrime(list, CreateElementType(element), filter); 
            }
            else {
                // XmlSchemaAny matches more then one element
                XmlSchemaAny any = particle as XmlSchemaAny; 
                if (any != null) {
                    XmlSchemaType elementSchemaType = any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? XmlSchemaComplexType.UntypedAnyType : XmlSchemaComplexType.AnyType; 
                    switch (any.NamespaceList.Type) { 
                    case NamespaceList.ListType.Set:
                        // Add a separate type for each namespace in the list 
                        foreach (string ns in any.NamespaceList.Enumerate) {
                            card |= AddFilteredPrime(list, CreateElementType(ns, false, elementSchemaType), filter);
                        }
                        break; 
                    case NamespaceList.ListType.Other:
                        // Add ##other 
                        card = AddFilteredPrime(list, CreateElementType(any.NamespaceList.Excluded, true, elementSchemaType), filter); 
                        break;
                    case NamespaceList.ListType.Any: 
                    default:
                        // Add ##any
                        card = AddFilteredPrime(list, any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedElement : Element, filter);
                        break; 
                    }
                } 
                else { 
                    //  recurse into particle group
                    XmlSchemaGroupBase group = particle as XmlSchemaGroupBase; 
                    if (group.Items.Count != 0) {
                        if (particle is XmlSchemaChoice) {
                            foreach (XmlSchemaParticle p in group.Items) {
                                card |= AddChildParticle(list, p, filter); 
                            }
                        } 
                        else { // Sequence and  All 
                            foreach (XmlSchemaParticle p in group.Items) {
                                card += AddChildParticle(list, p, filter); 
                            }
                        }
                    }
                } 
            }
            return card * CardinalityOfParticle(particle); 
        } 

        ///  
        /// Apply filter an item type, add the result to a list, return cardinality
        /// 
        private XmlQueryCardinality AddFilteredPrime(List list, XmlQueryType source, XmlQueryType filter) {
            return AddFilteredPrime(list, source, filter, false); 

        } 
        private XmlQueryCardinality AddFilteredPrime(List list, XmlQueryType source, XmlQueryType filter, bool forseSingle) { 
            Debug.Assert(source.IsNode && source.IsSingleton);
            Debug.Assert(filter.IsNode && filter.IsSingleton); 

            // Intersect types
            XmlQueryType intersection = IntersectItemTypes(source, filter);
            if ((object)intersection == (object)None) { 
                return XmlQueryCardinality.Zero;
            } 
            AddItemToChoice(list, intersection); 
            // In the case of forseSingle - filtering all nodes behave as singletones
            XmlTypeCode typeCode = (forseSingle ? XmlTypeCode.Node : intersection.TypeCode); 
            switch (typeCode) {
            case XmlTypeCode.Node:
            case XmlTypeCode.Document:
            case XmlTypeCode.Element: 
                // Filter can result in empty sequence if filter is not wider then source
                if (intersection == source) 
                    return XmlQueryCardinality.One; 
                else
                    return  XmlQueryCardinality.ZeroOrOne; 

            case XmlTypeCode.Attribute:
                    // wildcard attribute matches more then one node
                if (!intersection.NameTest.IsSingleName) 
                    return XmlQueryCardinality.ZeroOrMore;
                else if (intersection == source) 
                    return XmlQueryCardinality.One; 
                else
                    return  XmlQueryCardinality.ZeroOrOne; 
            case XmlTypeCode.Comment:
            case XmlTypeCode.Text:
            case XmlTypeCode.ProcessingInstruction:
            case XmlTypeCode.Namespace: 
                return XmlQueryCardinality.ZeroOrMore;
 
            default: 
                Debug.Assert(false);
                return XmlQueryCardinality.None; 
            }
        }

        ///  
        /// Construct the intersection of two lists of prime XmlQueryTypes.
        ///  
        private XmlQueryType IntersectItemTypes(XmlQueryType left, XmlQueryType right) { 
            Debug.Assert(left.Count == 1 && left.IsSingleton, "left should be an item");
            Debug.Assert(right.Count == 1 && right.IsSingleton, "right should be an item"); 
            if (left.TypeCode == right.TypeCode && (left.NodeKinds & (XmlNodeKindFlags.Document | XmlNodeKindFlags.Element | XmlNodeKindFlags.Attribute)) != 0) {
                if (left.TypeCode == XmlTypeCode.Node) {
                    return left;
                } 
                // Intersect name tests
                XmlQualifiedNameTest nameTest = left.NameTest.Intersect(right.NameTest); 
 
                // Intersect types
                XmlSchemaType type = XmlSchemaType.IsDerivedFrom(left.SchemaType, right.SchemaType, /* exept:*/XmlSchemaDerivationMethod.Empty) ? left.SchemaType : 
                    XmlSchemaType.IsDerivedFrom(right.SchemaType, left.SchemaType, /* exept:*/XmlSchemaDerivationMethod.Empty) ? right.SchemaType : null;
                bool isNillable = left.IsNillable && right.IsNillable;

                if ((object)nameTest == (object)left.NameTest && type == left.SchemaType && isNillable == left.IsNillable) { 
                    // left is a subtype of right return left
                    return left; 
                } 
                else if ((object)nameTest == (object)right.NameTest && type == right.SchemaType && isNillable == right.IsNillable) {
                    // right is a subtype of left return right 
                    return right;
                }
                else if (nameTest != null && type != null) {
                    // create a new type 
                    return ItemType.Create(left.TypeCode, nameTest, type, isNillable);
                } 
            } 
            else if (left.IsSubtypeOf(right)) {
                // left is a subset of right, so left is in the intersection 
                return left;
            }
            else if (right.IsSubtypeOf(left)) {
                // right is a subset of left, so right is in the intersection 
                return right;
            } 
            return None; 
        }
 
        /// 
        /// Convert particle occurrance range into cardinality
        /// 
        private XmlQueryCardinality CardinalityOfParticle(XmlSchemaParticle particle) { 
            if (particle.MinOccurs == decimal.Zero) {
                if (particle.MaxOccurs == decimal.Zero) { 
                    return XmlQueryCardinality.Zero; 
                }
                else if (particle.MaxOccurs == decimal.One) { 
                    return XmlQueryCardinality.ZeroOrOne;
                }
                else {
                    return XmlQueryCardinality.ZeroOrMore; 
                }
            } 
            else { 
                if (particle.MaxOccurs == decimal.One) {
                    return XmlQueryCardinality.One; 
                }
                else {
                    return XmlQueryCardinality.OneOrMore;
                } 
            }
        } 
    #endif 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
using System.Collections.Generic;
using System.Diagnostics; 
using System.Globalization;
using System.IO;
using System.Xml.Schema;
using System.Xml.XPath; 

namespace System.Xml.Xsl { 
    using TF = XmlQueryTypeFactory; 

    ///  
    /// This class is the only way to create concrete instances of the abstract XmlQueryType class.
    /// Once basic types have been created, they can be combined and transformed in various ways.
    /// 
    internal static class XmlQueryTypeFactory { 
        //-----------------------------------------------
        // Type Construction Operators 
        //----------------------------------------------- 

        ///  
        /// Create an XmlQueryType from an XmlTypeCode.
        /// 
        /// the type code of the item
        /// true if the dynamic type is guaranteed to match the static type exactly 
        /// the atomic value type
        public static XmlQueryType Type(XmlTypeCode code, bool isStrict) { 
            return ItemType.Create(code, isStrict); 
        }
 
        /// 
        /// Create an XmlQueryType from an Xsd simple type (where variety can be Atomic, List, or Union).
        /// 
        /// the simple Xsd schema type of the atomic value 
        /// true if the dynamic type is guaranteed to match the static type exactly
        /// the atomic value type 
        public static XmlQueryType Type(XmlSchemaSimpleType schemaType, bool isStrict) { 
            if (schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic) {
                // We must special-case xs:anySimpleType because it is broken in Xsd and is sometimes treated as 
                // an atomic value and sometimes as a list value.  In XQuery, it always maps to xdt:anyAtomicType*.
                if (schemaType == DatatypeImplementation.AnySimpleType)
                    return AnyAtomicTypeS;
 
                return ItemType.Create(schemaType, isStrict);
            } 
 
            // Skip restrictions. It is safe to do that because this is a list or union, so it's not a build in type
            while (schemaType.DerivedBy == XmlSchemaDerivationMethod.Restriction) 
                schemaType = (XmlSchemaSimpleType) schemaType.BaseXmlSchemaType;

            // Convert Xsd list
            if (schemaType.DerivedBy == XmlSchemaDerivationMethod.List) 
                return PrimeProduct(Type(((XmlSchemaSimpleTypeList) schemaType.Content).BaseItemType, isStrict), XmlQueryCardinality.ZeroOrMore);
 
            // Convert Xsd union 
            Debug.Assert(schemaType.DerivedBy == XmlSchemaDerivationMethod.Union);
            XmlSchemaSimpleType[] baseMemberTypes = ((XmlSchemaSimpleTypeUnion) schemaType.Content).BaseMemberTypes; 
            XmlQueryType[] queryMemberTypes = new XmlQueryType[baseMemberTypes.Length];

            for (int i = 0; i < baseMemberTypes.Length; i++)
                queryMemberTypes[i] = Type(baseMemberTypes[i], isStrict); 

            return Choice(queryMemberTypes); 
        } 

        ///  
        /// Construct the union of two XmlQueryTypes
        /// 
        /// the left type
        /// the right type 
        /// the union type
        public static XmlQueryType Choice(XmlQueryType left, XmlQueryType right) { 
            return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List(left), right)), left.Cardinality | right.Cardinality); 
        }
 
        /// 
        /// Construct the union of several XmlQueryTypes
        /// 
        /// the list of types 
        /// the union type
        public static XmlQueryType Choice(params XmlQueryType[] types) { 
            if (types.Length == 0) 
                return None;
            else if (types.Length == 1) 
                return types[0];

            // Union each type with next type
            List list = new List(types[0]); 
            XmlQueryCardinality card = types[0].Cardinality;
 
            for (int i = 1; i < types.Length; i++) { 
                PrimeChoice(list, types[i]);
                card |= types[i].Cardinality; 
            }

            return SequenceType.Create(ChoiceType.Create(list), card);
        } 

        ///  
        /// Create a Node XmlQueryType which is the choice between several different node kinds. 
        /// 
        /// the node kinds which will make up the choice 
        /// the node type
        public static XmlQueryType NodeChoice(XmlNodeKindFlags kinds) {
            return ChoiceType.Create(kinds);
        } 

        ///  
        /// Construct the sequence of two XmlQueryTypes 
        /// 
        /// the left type 
        /// the right type
        /// the sequence type
        public static XmlQueryType Sequence(XmlQueryType left, XmlQueryType right) {
            return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List(left), right)), left.Cardinality + right.Cardinality); 
        }
 
    #if NEVER 
        /// 
        /// Construct the sequence of several XmlQueryTypes 
        /// 
        /// the sequence of types
        /// the sequence type
        public XmlQueryType Sequence(params XmlQueryType[] types) { 
            XmlQueryCardinality card = XmlQueryCardinality.Zero;
 
            foreach (XmlQueryType t in types) 
                card += t.Cardinality;
 
            return PrimeProduct(Choice(types), card);
        }
    #endif
 
        /// 
        /// Compute the product of the prime of "t" with cardinality "c". 
        ///  
        /// the member type
        /// the cardinality 
        /// the prime type with the indicated cardinality applied
        public static XmlQueryType PrimeProduct(XmlQueryType t, XmlQueryCardinality c) {
            // If cardinality stays the same, then this is a no-op
            if (t.Cardinality == c && !t.IsDod) 
                return t;
 
            return SequenceType.Create(t.Prime, c); 
        }
 
        /// 
        /// Compute a sequence with cardinality *= c.
        /// 
        /// the type to sequence 
        /// the cardinality multiplier
        /// the sequence of t with cardinality *= c 
        public static XmlQueryType Product(XmlQueryType t, XmlQueryCardinality c) { 
            return PrimeProduct(t, t.Cardinality * c);
        } 

        /// 
        /// Compute a sequence of zero to some max cardinality.
        ///  
        /// the type to sequence
        /// the upper bound 
        /// the sequence of t from 0 to c 
        public static XmlQueryType AtMost(XmlQueryType t, XmlQueryCardinality c) {
            return PrimeProduct(t, c.AtMost()); 
        }

        #region Built-in types
        //----------------------------------------------- 
        // Pre-Created Types
        // 
        // Abbreviations: 
        //   P = Plus (+)
        //   Q = Question Mark (?) 
        //   S = Star (*)
        //   X = Exact (IsStrict = true)
        //-----------------------------------------------
 
        public static readonly XmlQueryType None                = ChoiceType.None;
        public static readonly XmlQueryType Empty               = SequenceType.Zero; 
 
        public static readonly XmlQueryType Item                = TF.Type(XmlTypeCode.Item, false);
        public static readonly XmlQueryType ItemS               = TF.PrimeProduct(Item, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Node                = TF.Type(XmlTypeCode.Node, false);
        public static readonly XmlQueryType NodeS               = TF.PrimeProduct(Node, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType Element             = TF.Type(XmlTypeCode.Element, false);
        public static readonly XmlQueryType ElementS            = TF.PrimeProduct(Element, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Document            = TF.Type(XmlTypeCode.Document, false);
        public static readonly XmlQueryType DocumentS           = TF.PrimeProduct(Document, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Attribute           = TF.Type(XmlTypeCode.Attribute, false); 
        public static readonly XmlQueryType AttributeQ          = TF.PrimeProduct(Attribute, XmlQueryCardinality.ZeroOrOne);
        public static readonly XmlQueryType AttributeS          = TF.PrimeProduct(Attribute, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Namespace           = TF.Type(XmlTypeCode.Namespace, false);
        public static readonly XmlQueryType NamespaceS          = TF.PrimeProduct(Namespace, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType Text                = TF.Type(XmlTypeCode.Text, false);
        public static readonly XmlQueryType TextS               = TF.PrimeProduct(Text, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Comment             = TF.Type(XmlTypeCode.Comment, false);
        public static readonly XmlQueryType CommentS            = TF.PrimeProduct(Comment, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType PI                  = TF.Type(XmlTypeCode.ProcessingInstruction, false); 
        public static readonly XmlQueryType PIS                 = TF.PrimeProduct(PI, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType DocumentOrElement   = TF.Choice(Document, Element); 
        public static readonly XmlQueryType DocumentOrElementQ  = TF.PrimeProduct(DocumentOrElement, XmlQueryCardinality.ZeroOrOne);
        public static readonly XmlQueryType DocumentOrElementS  = TF.PrimeProduct(DocumentOrElement, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType Content             = TF.Choice(Element, Comment, PI, Text);
        public static readonly XmlQueryType ContentS            = TF.PrimeProduct(Content, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType DocumentOrContent   = TF.Choice(Document, Content);
        public static readonly XmlQueryType DocumentOrContentS  = TF.PrimeProduct(DocumentOrContent, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType AttributeOrContent  = TF.Choice(Attribute, Content); 
        public static readonly XmlQueryType AttributeOrContentS = TF.PrimeProduct(AttributeOrContent, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType AnyAtomicType       = TF.Type(XmlTypeCode.AnyAtomicType, false); 
        public static readonly XmlQueryType AnyAtomicTypeS      = TF.PrimeProduct(AnyAtomicType, XmlQueryCardinality.ZeroOrMore);
        public static readonly XmlQueryType String              = TF.Type(XmlTypeCode.String, false);
        public static readonly XmlQueryType StringX             = TF.Type(XmlTypeCode.String, true);
        public static readonly XmlQueryType StringXS            = TF.PrimeProduct(StringX, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType Boolean             = TF.Type(XmlTypeCode.Boolean, false);
        public static readonly XmlQueryType BooleanX            = TF.Type(XmlTypeCode.Boolean, true); 
        public static readonly XmlQueryType Int                 = TF.Type(XmlTypeCode.Int, false); 
        public static readonly XmlQueryType IntX                = TF.Type(XmlTypeCode.Int, true);
        public static readonly XmlQueryType IntXS               = TF.PrimeProduct(IntX, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType IntegerX            = TF.Type(XmlTypeCode.Integer, true);
        public static readonly XmlQueryType LongX               = TF.Type(XmlTypeCode.Long, true);
        public static readonly XmlQueryType DecimalX            = TF.Type(XmlTypeCode.Decimal, true);
        public static readonly XmlQueryType FloatX              = TF.Type(XmlTypeCode.Float, true); 
        public static readonly XmlQueryType Double              = TF.Type(XmlTypeCode.Double, false);
        public static readonly XmlQueryType DoubleX             = TF.Type(XmlTypeCode.Double, true); 
        public static readonly XmlQueryType DateTimeX           = TF.Type(XmlTypeCode.DateTime, true); 
        public static readonly XmlQueryType QNameX              = TF.Type(XmlTypeCode.QName, true);
        public static readonly XmlQueryType UntypedDocument     = ItemType.UntypedDocument; 
        public static readonly XmlQueryType UntypedElement      = ItemType.UntypedElement;
        public static readonly XmlQueryType UntypedAttribute    = ItemType.UntypedAttribute;
        public static readonly XmlQueryType UntypedNode         = TF.Choice(UntypedDocument, UntypedElement, UntypedAttribute, Namespace, Text, Comment, PI);
        public static readonly XmlQueryType UntypedNodeS        = TF.PrimeProduct(UntypedNode, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType NodeNotRtf          = ItemType.NodeNotRtf;
        public static readonly XmlQueryType NodeNotRtfQ         = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrOne); 
        public static readonly XmlQueryType NodeNotRtfS         = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrMore); 
        public static readonly XmlQueryType NodeDodS            = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrMore);
        #endregion 

        //-----------------------------------------------
        // Helpers
        //----------------------------------------------- 

        ///  
        /// Construct the union of two lists of prime XmlQueryTypes.  Types are added to "accumulator" as necessary to ensure 
        /// it contains a superset of "types".
        ///  
        private static List PrimeChoice(List accumulator, IList types) {
            foreach (XmlQueryType sourceItem in types) {
                AddItemToChoice(accumulator, sourceItem);
            } 
            return accumulator;
        } 
 
        /// 
        /// Adds itemType to a union. Returns false if new item is a subtype of one of the types in the list. 
        /// 
        private static void AddItemToChoice(List accumulator, XmlQueryType itemType) {
            Debug.Assert(itemType.IsSingleton, "All types should be prime.");
 
            bool addToList = true;
            for (int i = 0; i < accumulator.Count; i++) { 
                // If new prime is a subtype of existing prime, don't add it to the union 
                if (itemType.IsSubtypeOf(accumulator[i])) {
                    return; 
                }

                // If new prime is a subtype of existing prime, then replace the existing prime with new prime
                if (accumulator[i].IsSubtypeOf(itemType)) { 
                    if (addToList) {
                        addToList = false; 
                        accumulator[i] = itemType; 
                    }
                    else { 
                        accumulator.RemoveAt(i);
                        i --;
                    }
                } 
            }
 
            if (addToList) { 
                accumulator.Add(itemType);
            } 
        }

        #region NodeKindToTypeCode
        ///  
        /// Map XPathNodeType to XmlTypeCode.
        ///  
        private static readonly XmlTypeCode[] NodeKindToTypeCode = { 
            /* XPathNodeType.Root */                    XmlTypeCode.Document,
            /* XPathNodeType.Element */                 XmlTypeCode.Element, 
            /* XPathNodeType.Attribute */               XmlTypeCode.Attribute,
            /* XPathNodeType.Namespace */               XmlTypeCode.Namespace,
            /* XPathNodeType.Text */                    XmlTypeCode.Text,
            /* XPathNodeType.SignificantWhitespace */   XmlTypeCode.Text, 
            /* XPathNodeType.Whitespace */              XmlTypeCode.Text,
            /* XPathNodeType.ProcessingInstruction */   XmlTypeCode.ProcessingInstruction, 
            /* XPathNodeType.Comment */                 XmlTypeCode.Comment, 
            /* XPathNodeType.All */                     XmlTypeCode.Node,
        }; 
        #endregion

        //-----------------------------------------------
        // XmlQueryType Implementations 
        //-----------------------------------------------
 
        ///  
        /// Implementation of XmlQueryType for singleton types.
        ///  
        private sealed class ItemType : XmlQueryType {
            // If you add new types here, add them to SpecialBuiltInItemTypes as well
            public static readonly XmlQueryType UntypedDocument;
            public static readonly XmlQueryType UntypedElement; 
            public static readonly XmlQueryType UntypedAttribute;
            public static readonly XmlQueryType NodeNotRtf; 
            public static readonly XmlQueryType NodeDod; 

            private static XmlQueryType[] BuiltInItemTypes; 
            private static XmlQueryType[] BuiltInItemTypesStrict;
            private static XmlQueryType[] SpecialBuiltInItemTypes;

            private XmlTypeCode code; 
            private XmlQualifiedNameTest nameTest;
            private XmlSchemaType schemaType; 
            private bool isNillable; 
            private XmlNodeKindFlags nodeKinds;
            private bool isStrict; 
            private bool isNotRtf;

            /// 
            /// Construct arrays of built-in types. 
            /// 
            static ItemType() { 
            #if DEBUG 
                Array arrEnum = Enum.GetValues(typeof(XmlTypeCode));
                Debug.Assert((XmlTypeCode) arrEnum.GetValue(arrEnum.Length - 1) == XmlTypeCode.DayTimeDuration, 
                             "DayTimeDuration is no longer the last item in XmlTypeCode.  This code expects it to be.");
            #endif

                int typeCount = (int) XmlTypeCode.DayTimeDuration + 1; 

                BuiltInItemTypes = new XmlQueryType[typeCount]; 
                BuiltInItemTypesStrict = new XmlQueryType[typeCount]; 

                for (int i = 0; i < typeCount; i++) { 
                    XmlTypeCode typeCode = (XmlTypeCode)i;

                    switch ((XmlTypeCode) i) {
                        case XmlTypeCode.None: 
                            BuiltInItemTypes[i] = ChoiceType.None;
                            BuiltInItemTypesStrict[i] = ChoiceType.None; 
                            continue; 

                        case XmlTypeCode.Item: 
                        case XmlTypeCode.Node:
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, false);
                            BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
                            break; 

                        case XmlTypeCode.Document: 
                        case XmlTypeCode.Element: 
                        case XmlTypeCode.Namespace:
                        case XmlTypeCode.ProcessingInstruction: 
                        case XmlTypeCode.Comment:
                        case XmlTypeCode.Text:
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true);
                            BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; 
                            break;
 
                        case XmlTypeCode.Attribute: 
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnySimpleType, false, false, true);
                            BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; 
                            break;

                        case XmlTypeCode.AnyAtomicType:
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnyAtomicType, false, false, true); 
                            BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
                            break; 
 
                        case XmlTypeCode.UntypedAtomic:
                            // xdt:untypedAtomic is sealed, and therefore always strict 
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, true, true);
                            BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
                            break;
 
                        default:
                            XmlSchemaType builtInType = XmlSchemaType.GetBuiltInSimpleType(typeCode); 
                            BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, false, true); 
                            BuiltInItemTypesStrict[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, true, true);
                            break; 
                    }
                }

                UntypedDocument = new ItemType(XmlTypeCode.Document, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true); 
                UntypedElement = new ItemType(XmlTypeCode.Element, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true);
                UntypedAttribute = new ItemType(XmlTypeCode.Attribute, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, false, true); 
                NodeNotRtf = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true); 
                NodeDod = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true);
 
                SpecialBuiltInItemTypes = new XmlQueryType[4] { UntypedDocument, UntypedElement, UntypedAttribute, NodeNotRtf };
            }

            ///  
            /// Create ItemType from XmlTypeCode.
            ///  
            public static XmlQueryType Create(XmlTypeCode code, bool isStrict) { 
                // No objects need to be allocated, as corresponding ItemTypes for all type codes have been statically allocated
                if (isStrict) 
                    return BuiltInItemTypesStrict[(int) code];

                return BuiltInItemTypes[(int) code];
            } 

            ///  
            /// Create ItemType from Xsd atomic type. 
            /// 
            public static XmlQueryType Create(XmlSchemaSimpleType schemaType, bool isStrict) { 
                Debug.Assert(schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic, "List or Union Xsd types should have been handled by caller.");
                XmlTypeCode code = schemaType.Datatype.TypeCode;

                // If schemaType is a built-in type, 
                if (schemaType == XmlSchemaType.GetBuiltInSimpleType(code)) {
                    // Then use statically allocated type 
                    return Create(code, isStrict); 
                }
 
                // Otherwise, create a new type
                return new ItemType(code, XmlQualifiedNameTest.Wildcard, schemaType, false, isStrict, true);
            }
 
            /// 
            /// Create Document, Element or Attribute with specified name test, content type and nillable. 
            ///  
            public static XmlQueryType Create(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) {
                // If this is a Document, Element, or Attribute, 
                switch (code) {
                case XmlTypeCode.Document:
                case XmlTypeCode.Element:
                    if (nameTest.IsWildcard) { 
                        // Normalize document(*, xs:anyType), element(*, xs:anyType)
                        if (contentType == XmlSchemaComplexType.AnyType) 
                            return Create(code, false); 

                        // Normalize document(xs:untypedAny), element(*, xs:untypedAny) 
                        if (contentType == XmlSchemaComplexType.UntypedAnyType) {
                            Debug.Assert(!isNillable);
                            if (code == XmlTypeCode.Element)
                                return UntypedElement; 
                            if (code == XmlTypeCode.Document)
                                return UntypedDocument; 
                        } 
                    }
                    // Create new ItemType 
                    return new ItemType(code, nameTest, contentType, isNillable, false, true);

                case XmlTypeCode.Attribute:
                    if (nameTest.IsWildcard) { 
                        // Normalize attribute(xs:anySimpleType)
                        if (contentType == DatatypeImplementation.AnySimpleType) 
                            return Create(code, false); 

                        // Normalize attribute(xs:untypedAtomic) 
                        if (contentType == DatatypeImplementation.UntypedAtomicType)
                            return UntypedAttribute;
                    }
                    // Create new ItemType 
                    return new ItemType(code, nameTest, contentType, isNillable, false, true);
 
                default: 
                    return Create(code, false);
 
                }
            }

            ///  
            /// Private constructor.  Create methods should be used to create instances.
            ///  
            private ItemType(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType schemaType, bool isNillable, bool isStrict, bool isNotRtf) { 
                Debug.Assert(nameTest != null, "nameTest cannot be null");
                Debug.Assert(schemaType != null, "schemaType cannot be null"); 
                this.code = code;
                this.nameTest = nameTest;
                this.schemaType = schemaType;
                this.isNillable = isNillable; 
                this.isStrict = isStrict;
                this.isNotRtf = isNotRtf; 
 
                Debug.Assert(!IsAtomicValue || schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic);
 
                switch (code) {
                    case XmlTypeCode.Item: this.nodeKinds = XmlNodeKindFlags.Any; break;
                    case XmlTypeCode.Node: this.nodeKinds = XmlNodeKindFlags.Any; break;
                    case XmlTypeCode.Document: this.nodeKinds = XmlNodeKindFlags.Document; break; 
                    case XmlTypeCode.Element: this.nodeKinds = XmlNodeKindFlags.Element; break;
                    case XmlTypeCode.Attribute: this.nodeKinds = XmlNodeKindFlags.Attribute; break; 
                    case XmlTypeCode.Namespace: this.nodeKinds = XmlNodeKindFlags.Namespace; break; 
                    case XmlTypeCode.ProcessingInstruction: this.nodeKinds = XmlNodeKindFlags.PI; break;
                    case XmlTypeCode.Comment: this.nodeKinds = XmlNodeKindFlags.Comment; break; 
                    case XmlTypeCode.Text: this.nodeKinds = XmlNodeKindFlags.Text; break;
                    default: this.nodeKinds = XmlNodeKindFlags.None; break;
                }
            } 

            //----------------------------------------------- 
            // Serialization 
            //-----------------------------------------------
 
            /// 
            /// Serialize the object to BinaryWriter.
            /// 
            public override void GetObjectData(BinaryWriter writer) { 
                sbyte code = (sbyte) this.code;
 
                for (int idx = 0; idx < SpecialBuiltInItemTypes.Length; idx++) { 
                    if ((object) this == (object) SpecialBuiltInItemTypes[idx]) {
                        code = (sbyte) ~idx; 
                        break;
                    }
                }
 
                writer.Write(code);
 
                if (0 <= code) { 
                    Debug.Assert((object) this == (object) Create(this.code, this.isStrict), "Unknown type");
                    writer.Write(this.isStrict); 
                }
            }

            ///  
            /// Deserialize the object from BinaryReader.
            ///  
            public static XmlQueryType Create(BinaryReader reader) { 
                sbyte code = reader.ReadSByte();
 
                if (0 <= code)
                    return Create((XmlTypeCode) code, /*isStrict:*/reader.ReadBoolean());
                else
                    return SpecialBuiltInItemTypes[~code]; 
            }
 
            //----------------------------------------------- 
            // ItemType, OccurenceIndicator Properties
            //----------------------------------------------- 

            /// 
            /// Return the TypeCode.
            ///  
            public override XmlTypeCode TypeCode {
                get { return this.code; } 
            } 

            ///  
            /// Return the NameTest.
            /// 
            public override XmlQualifiedNameTest NameTest {
                get { return this.nameTest; } 
            }
 
            ///  
            /// Return the Xsd schema type.  This must be non-null for atomic value types.
            ///  
            public override XmlSchemaType SchemaType {
                get { return this.schemaType; }
            }
 
            /// 
            /// Return the IsNillable. 
            ///  
            public override bool IsNillable {
                get { return this.isNillable; } 
            }

            /// 
            /// Since this is always an atomic value type, NodeKinds = None. 
            /// 
            public override XmlNodeKindFlags NodeKinds { 
                get { return this.nodeKinds; } 
            }
 
            /// 
            /// Return flag indicating whether the dynamic type is guaranteed to be the same as the static type.
            /// 
            public override bool IsStrict { 
                get { return this.isStrict; }
            } 
 
            /// 
            /// Return flag indicating whether this is not an Rtf. 
            /// 
            public override bool IsNotRtf {
                get { return this.isNotRtf; }
            } 

            ///  
            /// Only NodeDod type returns true. 
            /// 
            public override bool IsDod { 
                get { return (object) this == (object) NodeDod; }
            }

            ///  
            /// Always return cardinality One.
            ///  
            public override XmlQueryCardinality Cardinality { 
                get { return XmlQueryCardinality.One; }
            } 

            /// 
            /// Prime of atomic value type is itself.
            ///  
            public override XmlQueryType Prime {
                get { return this; } 
            } 

            ///  
            /// Return the item's converter.
            /// 
            public override XmlValueConverter ClrMapping {
                get { 
                    // Return value converter from XmlSchemaType if type is atomic
                    if (IsAtomicValue) 
                        return SchemaType.ValueConverter; 

                    // Return node converter if item must be a node 
                    if (IsNode)
                        return XmlNodeConverter.Node;

                    // Otherwise return item converter 
                    return XmlAnyConverter.Item;
                } 
            } 

 
            //-----------------------------------------------
            // ListBase implementation
            //-----------------------------------------------
 
            /// 
            /// AtomicValueType is only a composition of itself, rather than other smaller types. 
            ///  
            public override int Count {
                get { return 1; } 
            }

            /// 
            /// AtomicValueType is only a composition of itself, rather than other smaller types. 
            /// 
            public override XmlQueryType this[int index] { 
                get { 
                    if (index != 0)
                        throw new IndexOutOfRangeException(); 

                    return this;
                }
                set { throw new NotSupportedException(); } 
            }
        } 
 

        ///  
        /// Implementation of XmlQueryType that composes a choice of various prime types.
        /// 
        private sealed class ChoiceType : XmlQueryType {
            public static readonly XmlQueryType None = new ChoiceType(new List()); 

            private XmlTypeCode code; 
            private XmlSchemaType schemaType; 
            private XmlNodeKindFlags nodeKinds;
            private List members; 

            /// 
            /// Create choice between node kinds.
            ///  
            public static XmlQueryType Create(XmlNodeKindFlags nodeKinds) {
                List members; 
 
                // If exactly one kind is set, then create singleton ItemType
                if (Bits.ExactlyOne((uint) nodeKinds)) 
                    return ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint) nodeKinds)], false);

                members = new List();
                while (nodeKinds != XmlNodeKindFlags.None) { 
                    members.Add(ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint) nodeKinds)], false));
 
                    nodeKinds = (XmlNodeKindFlags) Bits.ClearLeast((uint) nodeKinds); 
                }
 
                return Create(members);
            }

            ///  
            /// Create choice containing the specified list of types.
            ///  
            public static XmlQueryType Create(List members) { 
                if (members.Count == 0)
                    return None; 

                if (members.Count == 1)
                    return members[0];
 
                return new ChoiceType(members);
            } 
 
            /// 
            /// Private constructor.  Create methods should be used to create instances. 
            /// 
            private ChoiceType(List members) {
                Debug.Assert(members != null && members.Count != 1, "ChoiceType must contain a list with 0 or >1 types.");
 
                this.members = members;
 
                // Compute supertype of all member types 
                for (int i = 0; i < members.Count; i++) {
                    XmlQueryType t = members[i]; 
                    Debug.Assert(t.Cardinality == XmlQueryCardinality.One, "ChoiceType member types must be prime types.");

                    // Summarize the union of member types as a single type
                    if (this.code == XmlTypeCode.None) { 
                        // None combined with member type is the member type
                        this.code = t.TypeCode; 
                        this.schemaType = t.SchemaType; 
                    }
                    else if (IsNode && t.IsNode) { 
                        // Node combined with node is node
                        if (this.code == t.TypeCode) {
                            // Element or attribute combined with element or attribute can be summarized as element(*, XmlSchemaComplexType.AnyType) or attribute(*, DatatypeImplementation.AnySimpleType)
                            if (this.code == XmlTypeCode.Element) 
                                this.schemaType = XmlSchemaComplexType.AnyType;
                            else if (this.code == XmlTypeCode.Attribute) 
                                this.schemaType = DatatypeImplementation.AnySimpleType; 
                        }
                        else { 
                            this.code = XmlTypeCode.Node;
                            this.schemaType = null;
                        }
                    } 
                    else if (IsAtomicValue && t.IsAtomicValue) {
                        // Atomic value combined with atomic value is atomic value 
                        this.code = XmlTypeCode.AnyAtomicType; 
                        this.schemaType = DatatypeImplementation.AnyAtomicType;
                    } 
                    else {
                        // Else we'll summarize types as Item
                        this.code = XmlTypeCode.Item;
                        this.schemaType = null; 
                    }
 
                    // Always track union of node kinds 
                    this.nodeKinds |= t.NodeKinds;
                } 
            }

            private static readonly XmlTypeCode[] NodeKindToTypeCode = {
                /* None */          XmlTypeCode.None, 
                /* Document */      XmlTypeCode.Document,
                /* Element */       XmlTypeCode.Element, 
                /* Attribute */     XmlTypeCode.Attribute, 
                /* Text */          XmlTypeCode.Text,
                /* Comment */       XmlTypeCode.Comment, 
                /* PI */            XmlTypeCode.ProcessingInstruction,
                /* Namespace */     XmlTypeCode.Namespace,
            };
 
            //-----------------------------------------------
            // Serialization 
            //----------------------------------------------- 

            ///  
            /// Serialize the object to BinaryWriter.
            /// 
            public override void GetObjectData(BinaryWriter writer) {
                writer.Write(this.members.Count); 
                for (int i = 0; i < this.members.Count; i++) {
                    TF.Serialize(writer, this.members[i]); 
                } 
            }
 
            /// 
            /// Deserialize the object from BinaryReader.
            /// 
            public static XmlQueryType Create(BinaryReader reader) { 
                int length = reader.ReadInt32();
                List members = new List(length); 
                for (int i = 0; i < length; i++) { 
                    members.Add(TF.Deserialize(reader));
                } 
                return Create(members);
            }

            //----------------------------------------------- 
            // ItemType, OccurenceIndicator Properties
            //----------------------------------------------- 
 
            /// 
            /// Return a type code which is a supertype of all member types. 
            /// 
            public override XmlTypeCode TypeCode {
                get { return this.code; }
            } 

            ///  
            /// Return the NameTest. 
            /// 
            public override XmlQualifiedNameTest NameTest { 
                get { return XmlQualifiedNameTest.Wildcard; }
            }

            ///  
            /// Return an Xsd schema type which is a supertype of all member types.
            ///  
            public override XmlSchemaType SchemaType { 
                get { return this.schemaType; }
            } 

            /// 
            /// Return the IsNillable.
            ///  
            public override bool IsNillable {
                get { return false; } 
            } 

            ///  
            /// Return a set of NodeKinds which is the union of all member node kinds.
            /// 
            public override XmlNodeKindFlags NodeKinds {
                get { return this.nodeKinds; } 
            }
 
            ///  
            /// Choice types are always non-strict, except for the empty choice.
            ///  
            public override bool IsStrict {
                get { return members.Count == 0; }
            }
 
            /// 
            /// Return true if every type in the choice is not an Rtf. 
            ///  
            public override bool IsNotRtf {
                get { 
                    for (int i = 0; i < members.Count; i++) {
                        if (!this.members[i].IsNotRtf)
                            return false;
                    } 
                    return true;
                } 
            } 

            ///  
            /// Return true if every type in the choice is in document order with no duplicates.
            /// 
            public override bool IsDod {
                get { 
                    for (int i = 0; i < members.Count; i++) {
                        if (!this.members[i].IsDod) 
                            return false; 
                    }
                    return true; 
                }
            }

            ///  
            /// Always return cardinality none or one.
            ///  
            public override XmlQueryCardinality Cardinality { 
                get { return TypeCode == XmlTypeCode.None ? XmlQueryCardinality.None : XmlQueryCardinality.One; }
            } 

            /// 
            /// Prime of union type is itself.
            ///  
            public override XmlQueryType Prime {
                get { return this; } 
            } 

            ///  
            /// Always return the item converter.
            /// 
            public override XmlValueConverter ClrMapping {
                get { 
                    if (this.code == XmlTypeCode.None || this.code == XmlTypeCode.Item)
                        return XmlAnyConverter.Item; 
 
                    if (IsAtomicValue)
                        return SchemaType.ValueConverter; 

                    return XmlNodeConverter.Node;
                }
            } 

            //----------------------------------------------- 
            // ListBase implementation 
            //-----------------------------------------------
 
            /// 
            /// Return the number of union member types.
            /// 
            public override int Count { 
                get { return this.members.Count; }
            } 
 
            /// 
            /// Return a union member type by index. 
            /// 
            public override XmlQueryType this[int index] {
                get { return this.members[index]; }
                set { throw new NotSupportedException(); } 
            }
        } 
 

        ///  
        /// Implementation of XmlQueryType that modifies the cardinality of a composed type.
        /// 
        private sealed class SequenceType : XmlQueryType {
            public static readonly XmlQueryType Zero = new SequenceType(ChoiceType.None, XmlQueryCardinality.Zero); 

            private XmlQueryType prime; 
            private XmlQueryCardinality card; 
            private XmlValueConverter converter;
 
            /// 
            /// Create sequence type from prime and cardinality.
            /// 
            public static XmlQueryType Create(XmlQueryType prime, XmlQueryCardinality card) { 
                Debug.Assert(prime != null, "SequenceType can only modify the cardinality of a non-null XmlQueryType.");
                Debug.Assert(prime.IsSingleton, "Prime type must have cardinality one."); 
 
                if (prime.TypeCode == XmlTypeCode.None) {
                    // If cardinality includes zero, then return (None, Zero), else return (None, None). 
                    return XmlQueryCardinality.Zero <= card ? Zero : None;
                }

                // Normalize sequences with these cardinalities: None, Zero, One 

                if (card == XmlQueryCardinality.None) { 
                    return None; 
                }
                else if (card == XmlQueryCardinality.Zero) { 
                    return Zero;
                }
                else if (card == XmlQueryCardinality.One) {
                    return prime; 
                }
 
                return new SequenceType(prime, card); 
            }
 
            /// 
            /// Private constructor.  Create methods should be used to create instances.
            /// 
            private SequenceType(XmlQueryType prime, XmlQueryCardinality card) { 
                this.prime = prime;
                this.card = card; 
            } 

            //----------------------------------------------- 
            // Serialization
            //-----------------------------------------------

            ///  
            /// Serialize the object to BinaryWriter.
            ///  
            public override void GetObjectData(BinaryWriter writer) { 
                writer.Write(this.IsDod);
                if (this.IsDod) 
                    return;

                TF.Serialize(writer, this.prime);
                this.card.GetObjectData(writer); 
            }
 
            ///  
            /// Deserialize the object from BinaryReader.
            ///  
            public static XmlQueryType Create(BinaryReader reader) {
                if (reader.ReadBoolean())
                    return TF.NodeDodS;
 
                XmlQueryType prime = TF.Deserialize(reader);
                XmlQueryCardinality card = new XmlQueryCardinality(reader); 
                return Create(prime, card); 
            }
 
            //-----------------------------------------------
            // ItemType, OccurenceIndicator Properties
            //-----------------------------------------------
 
            /// 
            /// Return the TypeCode of the prime type. 
            ///  
            public override XmlTypeCode TypeCode {
                get { return this.prime.TypeCode; } 
            }

            /// 
            /// Return the NameTest of the prime type 
            /// 
            public override XmlQualifiedNameTest NameTest { 
                get { return this.prime.NameTest; } 
            }
 
            /// 
            /// Return the Xsd schema type of the prime type.
            /// 
            public override XmlSchemaType SchemaType { 
                get { return this.prime.SchemaType; }
            } 
 
            /// 
            /// Return the IsNillable of the prime type 
            /// 
            public override bool IsNillable {
                get { return this.prime.IsNillable; }
            } 

            ///  
            /// Return the NodeKinds of the prime type. 
            /// 
            public override XmlNodeKindFlags NodeKinds { 
                get { return this.prime.NodeKinds; }
            }

            ///  
            /// Return the IsStrict flag of the prime type.
            ///  
            public override bool IsStrict { 
                get { return this.prime.IsStrict; }
            } 

            /// 
            /// Return the IsNotRtf flag of the prime type.
            ///  
            public override bool IsNotRtf {
                get { return this.prime.IsNotRtf; } 
            } 

            ///  
            /// Return the IsDod flag of the prime type.
            /// 
            public override bool IsDod {
                get { return (object) this == (object) NodeDodS; } 
            }
 
            ///  
            /// Return the modified cardinality.
            ///  
            public override XmlQueryCardinality Cardinality {
                get { return this.card; }
            }
 
            /// 
            /// Return prime of sequence type. 
            ///  
            public override XmlQueryType Prime {
                get { return this.prime; } 
            }

            /// 
            /// Return the prime's converter wrapped in a list converter. 
            /// 
            public override XmlValueConverter ClrMapping { 
                get { 
                    if (this.converter == null)
                        this.converter = XmlListConverter.Create(this.prime.ClrMapping); 

                    return this.converter;
                }
            } 

 
            //----------------------------------------------- 
            // ListBase implementation
            //----------------------------------------------- 

            /// 
            /// Return the Count of the prime type.
            ///  
            public override int Count {
                get { return this.prime.Count; } 
            } 

            ///  
            /// Return the parts of the prime type.
            /// 
            public override XmlQueryType this[int index] {
                get { return this.prime[index]; } 
                set { throw new NotSupportedException(); }
            } 
        } 

        ///  
        /// Create a Node XmlQueryType having an XSD content type.
        /// 
        /// unless kind is Root, Element, or Attribute, "contentType" is ignored
        /// content type of the node 
        /// the node type
        public static XmlQueryType Type(XPathNodeType kind, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) { 
            return ItemType.Create(NodeKindToTypeCode[(int)kind], nameTest, contentType, isNillable); 
        }
 
        #region Serialization
        /// 
        /// Check if the given type can be serialized.
        ///  
        [Conditional("DEBUG")]
        public static void CheckSerializability(XmlQueryType type) { 
            type.GetObjectData(new BinaryWriter(Stream.Null)); 
        }
 
        /// 
        /// Serialize XmlQueryType to BinaryWriter.
        /// 
        public static void Serialize(BinaryWriter writer, XmlQueryType type) { 
            sbyte subtypeId;
 
            if (type.GetType() == typeof(ItemType)) 
                subtypeId = 0;
            else if (type.GetType() == typeof(ChoiceType)) 
                subtypeId = 1;
            else if (type.GetType() == typeof(SequenceType))
                subtypeId = 2;
            else { 
                Debug.Fail("Don't know how to serialize " + type.GetType().ToString());
                subtypeId = -1; 
            } 

            writer.Write(subtypeId); 
            type.GetObjectData(writer);
        }

        ///  
        /// Deserialize XmlQueryType from BinaryReader.
        ///  
        public static XmlQueryType Deserialize(BinaryReader reader) { 
            switch (reader.ReadByte()) {
            case 0: return ItemType.Create(reader); 
            case 1: return ChoiceType.Create(reader);
            case 2: return SequenceType.Create(reader);
            default:
                Debug.Fail("Unexpected XmlQueryType's subtype id"); 
                return null;
            } 
        } 
        #endregion
 
    #if NEVER   // Remove from code since we don't use and FxCop complains.  May re-add later.
        private XmlSchemaSet schemaSet;

        ///  
        /// Create an XmlQueryType having an XSD name test, content type and nillable.
        ///  
        /// unless code is Document, Element, or Attribute, "contentType" is ignored 
        /// name test on the node
        /// content type of the node 
        /// nillable property
        /// the item type
        public XmlQueryType Type(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) {
            return ItemType.Create(code, nameTest, contentType, isNillable); 
        }
 
        ///  
        /// Create a strict XmlQueryType from the source.
        ///  
        /// source type
        /// strict type if the source is atomic, the source otherwise
        public XmlQueryType StrictType(XmlQueryType source) {
            if (source.IsAtomicValue && source.Count == 1) 
                return SequenceType.Create(ItemType.Create((XmlSchemaSimpleType)source.SchemaType, true), source.Cardinality);
 
            return source; 
        }
 
        /// 
        /// Create an XmlQueryType from an XmlTypeCode and cardinality.
        /// 
        /// the type code of the item 
        /// cardinality
        /// build-in type type 
        public XmlQueryType Type(XmlTypeCode code, XmlQueryCardinality card) { 
            return SequenceType.Create(ItemType.Create(code, false), card);
        } 

        /// 
        /// Create an XmlQueryType having an XSD name test, content type, nillable and cardinality.
        ///  
        /// unless code is Document, Element, or Attribute, "contentType" is ignored
        /// name test on the node 
        /// content type of the node 
        /// nillable property
        /// cardinality 
        /// the item type
        public XmlQueryType Type(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable, XmlQueryCardinality card) {
            return SequenceType.Create(ItemType.Create(code, nameTest, contentType, isNillable), card);
        } 

        ///  
        /// Construct the intersection of two XmlQueryTypes 
        /// 
        /// the left type 
        /// the right type
        /// the intersection type
        public XmlQueryType Intersect(XmlQueryType left, XmlQueryType right) {
            return SequenceType.Create(ChoiceType.Create(PrimeIntersect(left, right)), left.Cardinality & right.Cardinality); 
        }
 
        ///  
        /// Construct the intersection of several XmlQueryTypes
        ///  
        /// the list of types
        /// the intersection type
        public XmlQueryType Intersect(params XmlQueryType[] types) {
            if (types.Length == 0) 
                return None;
            else if (types.Length == 1) 
                return types[0]; 

            // Intersect each type with next type 
            List list = PrimeIntersect(types[0], types[1]);
            XmlQueryCardinality card = types[0].Cardinality & types[1].Cardinality;

            for (int i = 2; i < types.Length; i++) { 
                list = PrimeIntersect(list, types[i]);
                card &= types[i].Cardinality; 
            } 

            return SequenceType.Create(ChoiceType.Create(list), card); 
        }

        /// 
        /// Construct the intersection of two lists of prime XmlQueryTypes. 
        /// 
        private List PrimeIntersect(IList left, IList right) { 
            List list = new List(); 

            foreach (XmlQueryType leftItem in left) { 
                foreach (XmlQueryType rightItem in right) {
                    XmlQueryType intersection = IntersectItemTypes(leftItem, rightItem);
                    // Do not add none1 to a list
                    if ((object)intersection != (object)None) { 
                        list.Add(intersection);
                    } 
                } 
            }
            return list; 
        }

        /// 
        /// Converts type of sequence of items to type of sequnce of atomic value 
        //  See http://www.w3.org/TR/2004/xquery-semantics/#jd_data for the detailed description
        ///  
        /// source type 
        /// type of the sequence of atomic values
        public XmlQueryType DataOn(XmlQueryType source) { 
            List list = new List();
            XmlQueryCardinality card = XmlQueryCardinality.None;

            foreach (XmlQueryType sourceItem  in source) { 
                switch (sourceItem.TypeCode) {
                case XmlTypeCode.Item: 
                case XmlTypeCode.Node: 
                    AddItemToChoice(list, AnyAtomicType);
                    card = XmlQueryCardinality.ZeroOrMore; 
                    break;
                case XmlTypeCode.Document:
                case XmlTypeCode.Text:
                    AddItemToChoice(list, UntypedAtomic); 
                    card |= XmlQueryCardinality.One;
                    break; 
                case XmlTypeCode.Comment: 
                case XmlTypeCode.ProcessingInstruction:
                    AddItemToChoice(list, String); 
                    card |= XmlQueryCardinality.One;
                    break;
                case XmlTypeCode.Element:
                case XmlTypeCode.Attribute: 
                    XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
                    if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType || sourceSchemaType == DatatypeImplementation.UntypedAtomicType) { 
                        AddItemToChoice(list, UntypedAtomic); 
                        card |= XmlQueryCardinality.One;
                    } 
                    else if (sourceSchemaType == XmlSchemaComplexType.AnyType || sourceSchemaType == DatatypeImplementation.AnySimpleType) {
                        AddItemToChoice(list, AnyAtomicType);
                        card = XmlQueryCardinality.ZeroOrMore;
                    } 
                    else {
                        if (sourceSchemaType.Datatype == null) { 
                            // Complex content adds anyAtomicType* if mixed 
                            XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceItem.SchemaType;
                            if (complexType.ContentType == XmlSchemaContentType.Mixed) { 
                                AddItemToChoice(list, AnyAtomicType);
                                card = XmlQueryCardinality.ZeroOrMore;
                            }
                            else { 
                                // Error if mixed is false
                                return null; 
                            } 
                        }
                        else { 
                            // Simple content
                            XmlSchemaType schemaType = sourceItem.SchemaType;

                            // Go up the tree until it's a simple type 
                            while (schemaType is XmlSchemaComplexType) {
                                schemaType = schemaType.BaseXmlSchemaType; 
                            } 

                            // Calculate XmlQueryType from XmlSchemaSimpleType 
                            XmlQueryType atomicSeq = Type((XmlSchemaSimpleType)schemaType, false);

                            // Add prime to a choice
                            // It doen't have to be a single item! 
                            PrimeChoice(list, atomicSeq.Prime);
 
                            // Add cardinality to a choice 
                            card |= atomicSeq.Cardinality;
                        } 
                        // Add ? if nillable
                        if (sourceItem.IsNillable) {
                            card *= XmlQueryCardinality.ZeroOrOne;
                        } 
                    }
                    break; 
                case XmlTypeCode.Namespace: 
                    card |= XmlQueryCardinality.Zero;
                    break; 
                case XmlTypeCode.None:
                    break;
                default:
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); 
                    AddItemToChoice(list, sourceItem);
                    card |= XmlQueryCardinality.One; 
                    break; 
                }
            } 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
        }

        ///  
        /// Filter type of node sequence with a type (filter)
        ///  
        /// source type 
        /// type filter
        /// type of the filtered node sequence 
        public XmlQueryType FilterOf(XmlQueryType source, XmlQueryType filter) {
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
            List list = new List();
            XmlQueryCardinality card = XmlQueryCardinality.None; 

            foreach (XmlQueryType sourceItem in source) { 
                card |= AddFilteredPrime(list, sourceItem, filter, true); 
            }
            // Make sure that cardinality is at least Zero 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
        }

        ///  
        /// For the type of node sequence calculate type of children filtered with a type (filter)
        ///  
        /// source type 
        /// type filter
        /// type of the children node sequence 
        public XmlQueryType ChildrenOf(XmlQueryType source, XmlQueryType filter) {
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
            List list = new List();
            XmlQueryCardinality card = XmlQueryCardinality.None; 

            foreach (XmlQueryType sourceItem in source) { 
                switch (sourceItem.TypeCode) { 
                case XmlTypeCode.Node:
                case XmlTypeCode.Document: 
                case XmlTypeCode.Element:
                    XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
                    XmlQueryCardinality itemCard = XmlQueryCardinality.None;
                    // Only element and document can have children 
                    if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) {
                        // content of xdt:untypedAny is element(*, xdt:untypedAny)* 
                        itemCard = (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore); 
                        itemCard += AddFilteredPrime(list, Text, filter);
                    } 
                    else if (sourceSchemaType.Datatype != null) {
                        // Text is the only child node simple type can have
                        itemCard = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne;
                    } 
                    else {
                        // Complex content 
                        XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType; 
                        itemCard = AddChildParticle(list, complexType.ContentTypeParticle, filter);
                        if (complexType.ContentType == XmlSchemaContentType.Mixed) { 
                            itemCard += AddFilteredPrime(list, Text, filter);
                        }
                    }
                    itemCard += AddFilteredPrime(list, PI, filter); 
                    itemCard += AddFilteredPrime(list, Comment, filter);
                    card |= itemCard; 
                    break; 

                case XmlTypeCode.Attribute: 
                case XmlTypeCode.ProcessingInstruction:
                case XmlTypeCode.Comment:
                case XmlTypeCode.Namespace:
                case XmlTypeCode.Text: 
                    card |= XmlQueryCardinality.Zero;
                    break; 
 
                default:
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); 
                    return null;
                }
            }
            // Make sure that cardinality is at least Zero 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
        } 
 
        /// 
        /// For the type of node sequence calculate type of attributes filtered with a type (filter) 
        /// 
        /// source type
        /// type filter
        /// type of the children node sequence 
        public XmlQueryType AttributesOf(XmlQueryType source, XmlQueryType filter) {
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); 
            List list = new List(); 
            XmlQueryCardinality card = XmlQueryCardinality.None;
 
            foreach (XmlQueryType sourceItem in source) {
                switch (sourceItem.TypeCode) {
                case XmlTypeCode.Node:
                case XmlTypeCode.Element: 
                    XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
                    if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { 
                        // attfibutes of of xdt:untypedAny are attribute(*, xdt:untypedAtomic)* 
                        card |= AddFilteredPrime(list, UntypedAttribute, filter) * XmlQueryCardinality.ZeroOrOne;
                    } 
                    else {
                        // Only complex type can have attributes
                        XmlSchemaComplexType type = sourceSchemaType as XmlSchemaComplexType;
                        if (type != null) { 
                            card |= AddAttributes(list, type.AttributeUses, type.AttributeWildcard, filter);
                        } 
                    } 
                    break;
 
                case XmlTypeCode.Document:
                case XmlTypeCode.Attribute:
                case XmlTypeCode.ProcessingInstruction:
                case XmlTypeCode.Comment: 
                case XmlTypeCode.Namespace:
                case XmlTypeCode.Text: 
                    card |= XmlQueryCardinality.Zero; 
                    break;
 
                default:
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
                    return null;
                } 
            }
            // Make sure that cardinality is at least Zero 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); 
        }
 
        /// 
        /// For the type of node sequence calculate type of parent filtered with a type (filter)
        /// 
        /// source type 
        /// type filter
        /// type of the parent node sequence 
        public XmlQueryType ParentOf(XmlQueryType source, XmlQueryType filter) { 
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
            List list = new List(); 
            XmlQueryCardinality card = XmlQueryCardinality.None;

            foreach (XmlQueryType sourceItem  in source) {
                switch (sourceItem.TypeCode) { 
                case XmlTypeCode.Node:
                case XmlTypeCode.ProcessingInstruction: 
                case XmlTypeCode.Comment: 
                case XmlTypeCode.Text:
                case XmlTypeCode.Element: 
                    if (schemaSet == null) {
                        card |= AddFilteredPrime(list, UntypedDocument, filter) * XmlQueryCardinality.ZeroOrOne;
                        card |= AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrOne;
                    } 
                    else {
                        card |= AddFilteredPrime(list, Document, filter) * XmlQueryCardinality.ZeroOrOne; 
                        card |= AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrOne; 
                    }
                    break; 

                case XmlTypeCode.Namespace:
                case XmlTypeCode.Attribute:
                    if (schemaSet == null) { 
                        card |= (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrOne);
                    } 
                    else { 
                        card |= (AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrOne);
                    } 
                    break;

                case XmlTypeCode.Document:
                    card |= XmlQueryCardinality.Zero; 
                    break;
 
                default: 
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
                    break; 
                }
            }
            // Make sure that cardinality is at least Zero
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); 
        }
 
        ///  
        /// For the type of node sequence calculate type of descendants filtered with a type (filter)
        ///  
        /// source type
        /// type filter
        /// type of the descendants node sequence
        public XmlQueryType DescendantsOf(XmlQueryType source, XmlQueryType filter) { 
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
            List list = new List(); 
            XmlQueryCardinality card = XmlQueryCardinality.None; 

            foreach (XmlQueryType sourceItem  in source) { 
                switch (sourceItem.TypeCode) {
                case XmlTypeCode.Node:
                case XmlTypeCode.Document:
                case XmlTypeCode.Element: 
                    XmlQueryCardinality itemCard = XmlQueryCardinality.None;
                    if ((filter.NodeKinds & (XmlNodeKindFlags.Element | XmlNodeKindFlags.Text)) != 0) { 
                        Dictionary allTypes = new Dictionary(); 
                        XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
                        if (sourceSchemaType == null) { 
                            Debug.Assert(sourceItem.TypeCode == XmlTypeCode.Node);
                            sourceSchemaType = XmlSchemaComplexType.AnyType;
                        }
                        itemCard = AddElementOrTextDescendants(list, allTypes, sourceSchemaType, filter); 
                    }
                    itemCard += AddFilteredPrime(list, PI, filter); 
                    itemCard += AddFilteredPrime(list, Comment, filter); 
                    card |= itemCard;
                    break; 

                case XmlTypeCode.Attribute:
                case XmlTypeCode.ProcessingInstruction:
                case XmlTypeCode.Comment: 
                case XmlTypeCode.Namespace:
                case XmlTypeCode.Text: 
                    card |= XmlQueryCardinality.Zero; 
                    break;
 
                default:
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
                        break;
                } 
            }
            // Make sure that cardinality is at least Zero 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); 
        }
 
        /// 
        /// For the type of node sequence calculate type of ancestor filtered with a type (filter)
        /// 
        /// source type 
        /// type filter
        /// type of the ancestor node sequence 
        public XmlQueryType AncestorsOf(XmlQueryType source, XmlQueryType filter) { 
            Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
            List list = new List(); 
            XmlQueryCardinality card = XmlQueryCardinality.None;

            foreach (XmlQueryType sourceItem  in source) {
                switch (sourceItem.TypeCode) { 
                case XmlTypeCode.Node:
                case XmlTypeCode.ProcessingInstruction: 
                case XmlTypeCode.Comment: 
                case XmlTypeCode.Text:
                case XmlTypeCode.Element: 
                case XmlTypeCode.Namespace:
                case XmlTypeCode.Attribute:
                    if (schemaSet == null) {
                        card |= (AddFilteredPrime(list, UntypedDocument, filter) * XmlQueryCardinality.ZeroOrOne) 
                                + (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore);
                    } 
                    else { 
                        card |= (AddFilteredPrime(list, Document, filter) * XmlQueryCardinality.ZeroOrOne)
                                + (AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrMore); 
                    }
                    break;

                case XmlTypeCode.Document: 
                    card |= XmlQueryCardinality.Zero;
                    break; 
 
                default:
                    Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); 
                    break;
                }
            }
            // Make sure that cardinality is at least Zero 
            return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
        } 
 
        private XmlQueryCardinality AddAttributes(List list, XmlSchemaObjectTable attributeUses, XmlSchemaAnyAttribute attributeWildcard, XmlQueryType filter) {
            XmlQueryCardinality card = XmlQueryCardinality.Zero; 
            if (attributeWildcard != null) {
                XmlSchemaType attributeSchemaType = attributeWildcard.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? DatatypeImplementation.UntypedAtomicType : DatatypeImplementation.AnySimpleType;

                // wildcard will match more then one attribute 
                switch (attributeWildcard.NamespaceList.Type) {
                case NamespaceList.ListType.Set: 
                    foreach (string ns in attributeWildcard.NamespaceList.Enumerate) { 
                        card += AddFilteredPrime(list, CreateAttributeType(ns, false, attributeSchemaType), filter);
                    } 
                    break;
                case NamespaceList.ListType.Other:
                    card += AddFilteredPrime(list, CreateAttributeType(attributeWildcard.NamespaceList.Excluded, true, attributeSchemaType), filter);
                    break; 
                case NamespaceList.ListType.Any:
                default: 
                    card +=  AddFilteredPrime(list, attributeWildcard.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedAttribute : Attribute, filter); 
                    break;
                } 
                // Always optional
                card *= XmlQueryCardinality.ZeroOrOne;
            }
            foreach (XmlSchemaAttribute attribute in attributeUses.Values) { 
                XmlQueryCardinality cardAttr = AddFilteredPrime(list, CreateAttributeType(attribute), filter);
                if (cardAttr != XmlQueryCardinality.Zero) { 
                    Debug.Assert(cardAttr == XmlQueryCardinality.ZeroOrOne || cardAttr == XmlQueryCardinality.One); 
                    card += (attribute.Use == XmlSchemaUse.Optional ? XmlQueryCardinality.ZeroOrOne : cardAttr);
                } 
            }
            return card;
        }
 
        private XmlQueryType CreateAttributeType(XmlSchemaAttribute attribute) {
            return ItemType.Create(XmlTypeCode.Attribute, XmlQualifiedNameTest.New(attribute.QualifiedName), attribute.AttributeSchemaType, false); 
        } 

        private XmlQueryType CreateAttributeType(string ns, bool exclude, XmlSchemaType schemaType) { 
            return ItemType.Create(XmlTypeCode.Attribute, XmlQualifiedNameTest.New(ns, exclude), schemaType, false);
        }

        private XmlQueryCardinality AddDescendantParticle(List list, Dictionary allTypes, XmlSchemaParticle particle, XmlQueryType filter) { 
            XmlQueryCardinality card = XmlQueryCardinality.None;
            XmlSchemaElement element = particle as XmlSchemaElement; 
            if (element != null) { 
                // Single element
                XmlQueryType elementType = CreateElementType(element); 

                // Add it
                card = AddFilteredPrime(list, elementType, filter);
 
                // Descend
                card += AddElementOrTextDescendants(list, allTypes, elementType.SchemaType, filter); 
            } 
            else {
                XmlSchemaAny any = particle as XmlSchemaAny; 
                if (any != null) {
                    // Descendants of any
                    card = AddFilteredPrime(list, Element, filter);
                } 
                else {
                    XmlSchemaGroupBase group = particle as XmlSchemaGroupBase; 
                    if (group.Items.Count != 0) { 
                        if (particle is XmlSchemaChoice) {
                            foreach (XmlSchemaParticle p in group.Items) { 
                                card |= AddDescendantParticle(list, allTypes, p, filter);
                            }
                        }
                        else { // Sequence and  All 
                            foreach (XmlSchemaParticle p in group.Items) {
                                card += AddDescendantParticle(list, allTypes, p, filter); 
                            } 
                        }
                    } 
                }
            }
            return card * CardinalityOfParticle(particle);
        } 

        private XmlQueryCardinality AddElementOrTextDescendants(List list, 
            Dictionary allTypes, XmlSchemaType sourceSchemaType, XmlQueryType filter) { 
            XmlQueryCardinality card = XmlQueryCardinality.None;
            if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { 
                card = AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore;
                card += AddFilteredPrime(list, Text, filter);
            }
            else if (sourceSchemaType.Datatype != null) { 
                // Text is the only child node simple content of complext type
                card = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne; 
            } 
            else {
                // Complex content 
                XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType;
                if (complexType.QualifiedName.IsEmpty || !allTypes.TryGetValue(complexType.QualifiedName, out card)) {
                    allTypes[complexType.QualifiedName] = XmlQueryCardinality.ZeroOrMore; // take care of left recursion
                    card = AddDescendantParticle(list, allTypes, complexType.ContentTypeParticle, filter); 
                    allTypes[complexType.QualifiedName] = card;  //set correct card
                    if (complexType.ContentType == XmlSchemaContentType.Mixed) { 
                        card += AddFilteredPrime(list, Text, filter); 
                    }
                } 
            }
            return card;
        }
 
        /// 
        /// Create type based on an XmlSchemaElement 
        ///  
        private XmlQueryType CreateElementType(XmlSchemaElement element) {
            return ItemType.Create(XmlTypeCode.Element, XmlQualifiedNameTest.New(element.QualifiedName), element.ElementSchemaType, element.IsNillable); 
        }

        /// 
        /// Create type based on a wildcard 
        /// 
        private XmlQueryType CreateElementType(string ns, bool exclude, XmlSchemaType schemaType) { 
            return ItemType.Create(XmlTypeCode.Element, XmlQualifiedNameTest.New(ns, exclude), schemaType, false); 
        }
 
        /// 
        ///  Descend though the content model
        /// 
        private XmlQueryCardinality AddChildParticle(List list, XmlSchemaParticle particle, XmlQueryType filter) { 
            XmlQueryCardinality card = XmlQueryCardinality.None;
            XmlSchemaElement element = particle as XmlSchemaElement; 
            if (element != null) { 
                // Single element
                card = AddFilteredPrime(list, CreateElementType(element), filter); 
            }
            else {
                // XmlSchemaAny matches more then one element
                XmlSchemaAny any = particle as XmlSchemaAny; 
                if (any != null) {
                    XmlSchemaType elementSchemaType = any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? XmlSchemaComplexType.UntypedAnyType : XmlSchemaComplexType.AnyType; 
                    switch (any.NamespaceList.Type) { 
                    case NamespaceList.ListType.Set:
                        // Add a separate type for each namespace in the list 
                        foreach (string ns in any.NamespaceList.Enumerate) {
                            card |= AddFilteredPrime(list, CreateElementType(ns, false, elementSchemaType), filter);
                        }
                        break; 
                    case NamespaceList.ListType.Other:
                        // Add ##other 
                        card = AddFilteredPrime(list, CreateElementType(any.NamespaceList.Excluded, true, elementSchemaType), filter); 
                        break;
                    case NamespaceList.ListType.Any: 
                    default:
                        // Add ##any
                        card = AddFilteredPrime(list, any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedElement : Element, filter);
                        break; 
                    }
                } 
                else { 
                    //  recurse into particle group
                    XmlSchemaGroupBase group = particle as XmlSchemaGroupBase; 
                    if (group.Items.Count != 0) {
                        if (particle is XmlSchemaChoice) {
                            foreach (XmlSchemaParticle p in group.Items) {
                                card |= AddChildParticle(list, p, filter); 
                            }
                        } 
                        else { // Sequence and  All 
                            foreach (XmlSchemaParticle p in group.Items) {
                                card += AddChildParticle(list, p, filter); 
                            }
                        }
                    }
                } 
            }
            return card * CardinalityOfParticle(particle); 
        } 

        ///  
        /// Apply filter an item type, add the result to a list, return cardinality
        /// 
        private XmlQueryCardinality AddFilteredPrime(List list, XmlQueryType source, XmlQueryType filter) {
            return AddFilteredPrime(list, source, filter, false); 

        } 
        private XmlQueryCardinality AddFilteredPrime(List list, XmlQueryType source, XmlQueryType filter, bool forseSingle) { 
            Debug.Assert(source.IsNode && source.IsSingleton);
            Debug.Assert(filter.IsNode && filter.IsSingleton); 

            // Intersect types
            XmlQueryType intersection = IntersectItemTypes(source, filter);
            if ((object)intersection == (object)None) { 
                return XmlQueryCardinality.Zero;
            } 
            AddItemToChoice(list, intersection); 
            // In the case of forseSingle - filtering all nodes behave as singletones
            XmlTypeCode typeCode = (forseSingle ? XmlTypeCode.Node : intersection.TypeCode); 
            switch (typeCode) {
            case XmlTypeCode.Node:
            case XmlTypeCode.Document:
            case XmlTypeCode.Element: 
                // Filter can result in empty sequence if filter is not wider then source
                if (intersection == source) 
                    return XmlQueryCardinality.One; 
                else
                    return  XmlQueryCardinality.ZeroOrOne; 

            case XmlTypeCode.Attribute:
                    // wildcard attribute matches more then one node
                if (!intersection.NameTest.IsSingleName) 
                    return XmlQueryCardinality.ZeroOrMore;
                else if (intersection == source) 
                    return XmlQueryCardinality.One; 
                else
                    return  XmlQueryCardinality.ZeroOrOne; 
            case XmlTypeCode.Comment:
            case XmlTypeCode.Text:
            case XmlTypeCode.ProcessingInstruction:
            case XmlTypeCode.Namespace: 
                return XmlQueryCardinality.ZeroOrMore;
 
            default: 
                Debug.Assert(false);
                return XmlQueryCardinality.None; 
            }
        }

        ///  
        /// Construct the intersection of two lists of prime XmlQueryTypes.
        ///  
        private XmlQueryType IntersectItemTypes(XmlQueryType left, XmlQueryType right) { 
            Debug.Assert(left.Count == 1 && left.IsSingleton, "left should be an item");
            Debug.Assert(right.Count == 1 && right.IsSingleton, "right should be an item"); 
            if (left.TypeCode == right.TypeCode && (left.NodeKinds & (XmlNodeKindFlags.Document | XmlNodeKindFlags.Element | XmlNodeKindFlags.Attribute)) != 0) {
                if (left.TypeCode == XmlTypeCode.Node) {
                    return left;
                } 
                // Intersect name tests
                XmlQualifiedNameTest nameTest = left.NameTest.Intersect(right.NameTest); 
 
                // Intersect types
                XmlSchemaType type = XmlSchemaType.IsDerivedFrom(left.SchemaType, right.SchemaType, /* exept:*/XmlSchemaDerivationMethod.Empty) ? left.SchemaType : 
                    XmlSchemaType.IsDerivedFrom(right.SchemaType, left.SchemaType, /* exept:*/XmlSchemaDerivationMethod.Empty) ? right.SchemaType : null;
                bool isNillable = left.IsNillable && right.IsNillable;

                if ((object)nameTest == (object)left.NameTest && type == left.SchemaType && isNillable == left.IsNillable) { 
                    // left is a subtype of right return left
                    return left; 
                } 
                else if ((object)nameTest == (object)right.NameTest && type == right.SchemaType && isNillable == right.IsNillable) {
                    // right is a subtype of left return right 
                    return right;
                }
                else if (nameTest != null && type != null) {
                    // create a new type 
                    return ItemType.Create(left.TypeCode, nameTest, type, isNillable);
                } 
            } 
            else if (left.IsSubtypeOf(right)) {
                // left is a subset of right, so left is in the intersection 
                return left;
            }
            else if (right.IsSubtypeOf(left)) {
                // right is a subset of left, so right is in the intersection 
                return right;
            } 
            return None; 
        }
 
        /// 
        /// Convert particle occurrance range into cardinality
        /// 
        private XmlQueryCardinality CardinalityOfParticle(XmlSchemaParticle particle) { 
            if (particle.MinOccurs == decimal.Zero) {
                if (particle.MaxOccurs == decimal.Zero) { 
                    return XmlQueryCardinality.Zero; 
                }
                else if (particle.MaxOccurs == decimal.One) { 
                    return XmlQueryCardinality.ZeroOrOne;
                }
                else {
                    return XmlQueryCardinality.ZeroOrMore; 
                }
            } 
            else { 
                if (particle.MaxOccurs == decimal.One) {
                    return XmlQueryCardinality.One; 
                }
                else {
                    return XmlQueryCardinality.OneOrMore;
                } 
            }
        } 
    #endif 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK