The Labs \ Source Viewer \ SSCLI \ System.Xml.Xsl \ ChoiceType

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlQueryTypeFactory.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. //------------------------------------------------------------------------------
  15. using System;
  16. using System.Xml;
  17. using System.Xml.XPath;
  18. using System.Xml.Schema;
  19. using System.Collections.Generic;
  20. using System.Diagnostics;
  21. using System.Globalization;
  22. namespace System.Xml.Xsl
  23. {
  24.     using TF = XmlQueryTypeFactory;
  25.    
  26.     /// <summary>
  27.     /// This class is the only way to create concrete instances of the abstract XmlQueryType class.
  28.     /// Once basic types have been created, they can be combined and transformed in various ways.
  29.     /// </summary>
  30.     static internal class XmlQueryTypeFactory
  31.     {
  32.         //-----------------------------------------------
  33.         // Type Construction Operators
  34.         //-----------------------------------------------
  35.        
  36.         /// <summary>
  37.         /// Create an XmlQueryType from an XmlTypeCode.
  38.         /// </summary>
  39.         /// <param name="code">the type code of the item</param>
  40.         /// <param name="isStrict">true if the dynamic type is guaranteed to match the static type exactly</param>
  41.         /// <returns>the atomic value type</returns>
  42.         public static XmlQueryType Type(XmlTypeCode code, bool isStrict)
  43.         {
  44.             return ItemType.Create(code, isStrict);
  45.         }
  46.        
  47.         /// <summary>
  48.         /// Create an XmlQueryType from an Xsd simple type (where variety can be Atomic, List, or Union).
  49.         /// </summary>
  50.         /// <param name="schemaType">the simple Xsd schema type of the atomic value</param>
  51.         /// <param name="isStrict">true if the dynamic type is guaranteed to match the static type exactly</param>
  52.         /// <returns>the atomic value type</returns>
  53.         public static XmlQueryType Type(XmlSchemaSimpleType schemaType, bool isStrict)
  54.         {
  55.             if (schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic) {
  56.                 if (schemaType == DatatypeImplementation.AnySimpleType)
  57.                     return AnyAtomicTypeS;
  58.                
  59.                 return ItemType.Create(schemaType, isStrict);
  60.             }
  61.            
  62.             // Skip restrictions. It is safe to do that because this is a list or union, so it's not a build in type
  63.             while (schemaType.DerivedBy == XmlSchemaDerivationMethod.Restriction)
  64.                 schemaType = (XmlSchemaSimpleType)schemaType.BaseXmlSchemaType;
  65.            
  66.             // Convert Xsd list
  67.             if (schemaType.DerivedBy == XmlSchemaDerivationMethod.List)
  68.                 return PrimeProduct(Type(((XmlSchemaSimpleTypeList)schemaType.Content).BaseItemType, isStrict), XmlQueryCardinality.ZeroOrMore);
  69.            
  70.             // Convert Xsd union
  71.             Debug.Assert(schemaType.DerivedBy == XmlSchemaDerivationMethod.Union);
  72.             XmlSchemaSimpleType[] baseMemberTypes = ((XmlSchemaSimpleTypeUnion)schemaType.Content).BaseMemberTypes;
  73.             XmlQueryType[] queryMemberTypes = new XmlQueryType[baseMemberTypes.Length];
  74.            
  75.             for (int i = 0; i < baseMemberTypes.Length; i++)
  76.                 queryMemberTypes[i] = Type(baseMemberTypes[i], isStrict);
  77.            
  78.             return Choice(queryMemberTypes);
  79.         }
  80.        
  81.         /// <summary>
  82.         /// Construct the union of two XmlQueryTypes
  83.         /// </summary>
  84.         /// <param name="left">the left type</param>
  85.         /// <param name="right">the right type</param>
  86.         /// <returns>the union type</returns>
  87.         public static XmlQueryType Choice(XmlQueryType left, XmlQueryType right)
  88.         {
  89.             return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List<XmlQueryType>(left), right)), left.Cardinality | right.Cardinality);
  90.         }
  91.        
  92.         /// <summary>
  93.         /// Construct the union of several XmlQueryTypes
  94.         /// </summary>
  95.         /// <param name="types">the list of types</param>
  96.         /// <returns>the union type</returns>
  97.         public static XmlQueryType Choice(params XmlQueryType[] types)
  98.         {
  99.             if (types.Length == 0)
  100.                 return None;
  101.             else if (types.Length == 1)
  102.                 return types[0];
  103.            
  104.             // Union each type with next type
  105.             List<XmlQueryType> list = new List<XmlQueryType>(types[0]);
  106.             XmlQueryCardinality card = types[0].Cardinality;
  107.            
  108.             for (int i = 1; i < types.Length; i++) {
  109.                 PrimeChoice(list, types[i]);
  110.                 card |= types[i].Cardinality;
  111.             }
  112.            
  113.             return SequenceType.Create(ChoiceType.Create(list), card);
  114.         }
  115.        
  116.         /// <summary>
  117.         /// Create a Node XmlQueryType which is the choice between several different node kinds.
  118.         /// </summary>
  119.         /// <param name="kinds">the node kinds which will make up the choice</param>
  120.         /// <returns>the node type</returns>
  121.         public static XmlQueryType NodeChoice(XmlNodeKindFlags kinds)
  122.         {
  123.             return ChoiceType.Create(kinds);
  124.         }
  125.        
  126.         /// <summary>
  127.         /// Construct the sequence of two XmlQueryTypes
  128.         /// </summary>
  129.         /// <param name="left">the left type</param>
  130.         /// <param name="right">the right type</param>
  131.         /// <returns>the sequence type</returns>
  132.         public static XmlQueryType Sequence(XmlQueryType left, XmlQueryType right)
  133.         {
  134.             return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List<XmlQueryType>(left), right)), left.Cardinality + right.Cardinality);
  135.         }
  136.        
  137.         #if NEVER
  138.         /// <summary>
  139.         /// Construct the sequence of several XmlQueryTypes
  140.         /// </summary>
  141.         /// <param name="types">the sequence of types</param>
  142.         /// <returns>the sequence type</returns>
  143.         public XmlQueryType Sequence(params XmlQueryType[] types)
  144.         {
  145.             XmlQueryCardinality card = XmlQueryCardinality.Zero;
  146.            
  147.             foreach (XmlQueryType t in types)
  148.                 card += t.Cardinality;
  149.            
  150.             return PrimeProduct(Choice(types), card);
  151.         }
  152.         #endif
  153.        
  154.         /// <summary>
  155.         /// Compute the product of the prime of "t" with cardinality "c".
  156.         /// </summary>
  157.         /// <param name="t">the member type</param>
  158.         /// <param name="c">the cardinality</param>
  159.         /// <returns>the prime type with the indicated cardinality applied</returns>
  160.         public static XmlQueryType PrimeProduct(XmlQueryType t, XmlQueryCardinality c)
  161.         {
  162.             // If cardinality stays the same, then this is a no-op
  163.             if (t.Cardinality == c)
  164.                 return t;
  165.            
  166.             return SequenceType.Create(t.Prime, c);
  167.         }
  168.        
  169.         /// <summary>
  170.         /// Compute a sequence with cardinality *= c.
  171.         /// </summary>
  172.         /// <param name="t">the type to sequence</param>
  173.         /// <param name="c">the cardainality multiplier</param>
  174.         /// <returns>the sequence of t with cardinality *= c</returns>
  175.         public static XmlQueryType Product(XmlQueryType t, XmlQueryCardinality c)
  176.         {
  177.             return PrimeProduct(t, t.Cardinality * c);
  178.         }
  179.        
  180.         /// <summary>
  181.         /// Compute a sequence of zero to some max cardinality.
  182.         /// </summary>
  183.         /// <param name="t">the type to sequence</param>
  184.         /// <param name="c">the upper bound</param>
  185.         /// <returns>the sequence of t from 0 to c</returns>
  186.         public static XmlQueryType AtMost(XmlQueryType t, XmlQueryCardinality c)
  187.         {
  188.             return PrimeProduct(t, c.AtMost());
  189.         }
  190.        
  191.         #region build-in
  192.         //-----------------------------------------------
  193.         // Pre-Created Types
  194.         //
  195.         // Abbreviations:
  196.         // P = Plus (+)
  197.         // Q = Question Mark (?)
  198.         // S = Star (*)
  199.         // X = Exact (IsStrict = true)
  200.         //-----------------------------------------------
  201.        
  202.         public static readonly XmlQueryType None = ChoiceType.None;
  203.         public static readonly XmlQueryType Empty = SequenceType.Zero;
  204.        
  205.         public static readonly XmlQueryType Item = TF.Type(XmlTypeCode.Item, false);
  206.         public static readonly XmlQueryType ItemS = TF.PrimeProduct(Item, XmlQueryCardinality.ZeroOrMore);
  207.         public static readonly XmlQueryType Node = TF.Type(XmlTypeCode.Node, false);
  208.         public static readonly XmlQueryType NodeS = TF.PrimeProduct(Node, XmlQueryCardinality.ZeroOrMore);
  209.         public static readonly XmlQueryType Element = TF.Type(XmlTypeCode.Element, false);
  210.         public static readonly XmlQueryType ElementS = TF.PrimeProduct(Element, XmlQueryCardinality.ZeroOrMore);
  211.         public static readonly XmlQueryType Document = TF.Type(XmlTypeCode.Document, false);
  212.         public static readonly XmlQueryType DocumentS = TF.PrimeProduct(Document, XmlQueryCardinality.ZeroOrMore);
  213.         public static readonly XmlQueryType Attribute = TF.Type(XmlTypeCode.Attribute, false);
  214.         public static readonly XmlQueryType AttributeQ = TF.PrimeProduct(Attribute, XmlQueryCardinality.ZeroOrOne);
  215.         public static readonly XmlQueryType AttributeS = TF.PrimeProduct(Attribute, XmlQueryCardinality.ZeroOrMore);
  216.         public static readonly XmlQueryType Namespace = TF.Type(XmlTypeCode.Namespace, false);
  217.         public static readonly XmlQueryType NamespaceS = TF.PrimeProduct(Namespace, XmlQueryCardinality.ZeroOrMore);
  218.         public static readonly XmlQueryType Text = TF.Type(XmlTypeCode.Text, false);
  219.         public static readonly XmlQueryType TextS = TF.PrimeProduct(Text, XmlQueryCardinality.ZeroOrMore);
  220.         public static readonly XmlQueryType Comment = TF.Type(XmlTypeCode.Comment, false);
  221.         public static readonly XmlQueryType CommentS = TF.PrimeProduct(Comment, XmlQueryCardinality.ZeroOrMore);
  222.         public static readonly XmlQueryType PI = TF.Type(XmlTypeCode.ProcessingInstruction, false);
  223.         public static readonly XmlQueryType PIS = TF.PrimeProduct(PI, XmlQueryCardinality.ZeroOrMore);
  224.         public static readonly XmlQueryType DocumentOrElement = TF.Choice(Document, Element);
  225.         public static readonly XmlQueryType DocumentOrElementQ = TF.PrimeProduct(DocumentOrElement, XmlQueryCardinality.ZeroOrOne);
  226.         public static readonly XmlQueryType DocumentOrElementS = TF.PrimeProduct(DocumentOrElement, XmlQueryCardinality.ZeroOrMore);
  227.         public static readonly XmlQueryType Content = TF.Choice(Element, Comment, PI, Text);
  228.         public static readonly XmlQueryType ContentS = TF.PrimeProduct(Content, XmlQueryCardinality.ZeroOrMore);
  229.         public static readonly XmlQueryType DocumentOrContent = TF.Choice(Document, Content);
  230.         public static readonly XmlQueryType DocumentOrContentS = TF.PrimeProduct(DocumentOrContent, XmlQueryCardinality.ZeroOrMore);
  231.         public static readonly XmlQueryType AttributeOrContent = TF.Choice(Attribute, Content);
  232.         public static readonly XmlQueryType AttributeOrContentS = TF.PrimeProduct(AttributeOrContent, XmlQueryCardinality.ZeroOrMore);
  233.         public static readonly XmlQueryType AnyAtomicType = TF.Type(XmlTypeCode.AnyAtomicType, false);
  234.         public static readonly XmlQueryType AnyAtomicTypeS = TF.PrimeProduct(AnyAtomicType, XmlQueryCardinality.ZeroOrMore);
  235.         public static readonly XmlQueryType String = TF.Type(XmlTypeCode.String, false);
  236.         public static readonly XmlQueryType StringX = TF.Type(XmlTypeCode.String, true);
  237.         public static readonly XmlQueryType StringXS = TF.PrimeProduct(StringX, XmlQueryCardinality.ZeroOrMore);
  238.         public static readonly XmlQueryType Boolean = TF.Type(XmlTypeCode.Boolean, false);
  239.         public static readonly XmlQueryType BooleanX = TF.Type(XmlTypeCode.Boolean, true);
  240.         public static readonly XmlQueryType Int = TF.Type(XmlTypeCode.Int, false);
  241.         public static readonly XmlQueryType IntX = TF.Type(XmlTypeCode.Int, true);
  242.         public static readonly XmlQueryType IntXS = TF.PrimeProduct(IntX, XmlQueryCardinality.ZeroOrMore);
  243.         public static readonly XmlQueryType IntegerX = TF.Type(XmlTypeCode.Integer, true);
  244.         public static readonly XmlQueryType LongX = TF.Type(XmlTypeCode.Long, true);
  245.         public static readonly XmlQueryType DecimalX = TF.Type(XmlTypeCode.Decimal, true);
  246.         public static readonly XmlQueryType FloatX = TF.Type(XmlTypeCode.Float, true);
  247.         public static readonly XmlQueryType Double = TF.Type(XmlTypeCode.Double, false);
  248.         public static readonly XmlQueryType DoubleX = TF.Type(XmlTypeCode.Double, true);
  249.         public static readonly XmlQueryType DateTimeX = TF.Type(XmlTypeCode.DateTime, true);
  250.         public static readonly XmlQueryType QNameX = TF.Type(XmlTypeCode.QName, true);
  251.         public static readonly XmlQueryType UntypedDocument = ItemType.UntypedDocument;
  252.         public static readonly XmlQueryType UntypedElement = ItemType.UntypedElement;
  253.         public static readonly XmlQueryType UntypedAttribute = ItemType.UntypedAttribute;
  254.         public static readonly XmlQueryType UntypedNode = TF.Choice(UntypedDocument, UntypedElement, UntypedAttribute, Namespace, Text, Comment, PI);
  255.         public static readonly XmlQueryType UntypedNodeS = TF.PrimeProduct(UntypedNode, XmlQueryCardinality.ZeroOrMore);
  256.         public static readonly XmlQueryType NodeNotRtf = ItemType.NodeNotRtf;
  257.         public static readonly XmlQueryType NodeNotRtfQ = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrOne);
  258.         public static readonly XmlQueryType NodeNotRtfS = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrMore);
  259.         public static readonly XmlQueryType NodeDodS = TF.PrimeProduct(ItemType.NodeDod, XmlQueryCardinality.ZeroOrMore);
  260.         #endregion
  261.        
  262.         //-----------------------------------------------
  263.         // Helpers
  264.         //-----------------------------------------------
  265.        
  266.         /// <summary>
  267.         /// Construct the union of two lists of prime XmlQueryTypes. Types are added to "accumulator" as necessary to ensure
  268.         /// it contains a superset of "types".
  269.         /// </summary>
  270.         private static List<XmlQueryType> PrimeChoice(List<XmlQueryType> accumulator, IList<XmlQueryType> types)
  271.         {
  272.             foreach (XmlQueryType sourceItem in types) {
  273.                 AddItemToChoice(accumulator, sourceItem);
  274.             }
  275.             return accumulator;
  276.         }
  277.        
  278.         /// <summary>
  279.         /// Adds itemType to a union. Returns false if new item is a subtype of one of the types in the list.
  280.         /// </summary>
  281.         private static void AddItemToChoice(List<XmlQueryType> accumulator, XmlQueryType itemType)
  282.         {
  283.             Debug.Assert(itemType.IsSingleton, "All types should be prime.");
  284.            
  285.             bool addToList = true;
  286.             for (int i = 0; i < accumulator.Count; i++) {
  287.                 // If new prime is a subtype of existing prime, don't add it to the union
  288.                 if (itemType.IsSubtypeOf(accumulator[i])) {
  289.                     return;
  290.                 }
  291.                
  292.                 // If new prime is a subtype of existing prime, then replace the existing prime with new prime
  293.                 if (accumulator[i].IsSubtypeOf(itemType)) {
  294.                     if (addToList) {
  295.                         addToList = false;
  296.                         accumulator[i] = itemType;
  297.                     }
  298.                     else {
  299.                         accumulator.RemoveAt(i);
  300.                         i--;
  301.                     }
  302.                 }
  303.             }
  304.            
  305.             if (addToList) {
  306.                 accumulator.Add(itemType);
  307.             }
  308.         }
  309.        
  310.         #region NodeKindToTypeCode
  311.         /// <summary>
  312.         /// Map XPathNodeType to XmlTypeCode.
  313.         /// </summary>
  314.         private static readonly XmlTypeCode[] NodeKindToTypeCode = {XmlTypeCode.Document, XmlTypeCode.Element, XmlTypeCode.Attribute, XmlTypeCode.Namespace, XmlTypeCode.Text, XmlTypeCode.Text, XmlTypeCode.Text, XmlTypeCode.ProcessingInstruction, XmlTypeCode.Comment, XmlTypeCode.Node
  315.             /* XPathNodeType.Root */            /* XPathNodeType.Element */            /* XPathNodeType.Attribute */            /* XPathNodeType.Namespace */            /* XPathNodeType.Text */            /* XPathNodeType.SignificantWhitespace */            /* XPathNodeType.Whitespace */            /* XPathNodeType.ProcessingInstruction */            /* XPathNodeType.Comment */            /* XPathNodeType.All */        };
  316.         #endregion
  317.        
  318.         //-----------------------------------------------
  319.         // XmlQueryType Implementations
  320.         //-----------------------------------------------
  321.        
  322.         /// <summary>
  323.         /// Implementation of XmlQueryType for singleton types.
  324.         /// </summary>
  325.         private sealed class ItemType : XmlQueryType
  326.         {
  327.             public static readonly XmlQueryType UntypedDocument;
  328.             public static readonly XmlQueryType UntypedElement;
  329.             public static readonly XmlQueryType UntypedAttribute;
  330.             public static readonly XmlQueryType NodeNotRtf;
  331.             public static readonly XmlQueryType NodeDod;
  332.            
  333.             private static XmlQueryType[] BuiltInItemTypes;
  334.             private static XmlQueryType[] BuiltInItemTypesStrict;
  335.            
  336.             private XmlTypeCode code;
  337.             private XmlQualifiedNameTest nameTest;
  338.             private XmlSchemaType schemaType;
  339.             private bool isNillable;
  340.             private XmlNodeKindFlags nodeKinds;
  341.             private bool isStrict;
  342.             private bool isNotRtf;
  343.            
  344.             /// <summary>
  345.             /// Construct arrays of built-in types.
  346.             /// </summary>
  347.             static ItemType()
  348.             {
  349.                 #if DEBUG
  350.                 Array arrEnum = Enum.GetValues(typeof(XmlTypeCode));
  351.                 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.");
  352.                 #endif
  353.                
  354.                 int typeCount = (int)XmlTypeCode.DayTimeDuration + 1;
  355.                
  356.                 BuiltInItemTypes = new XmlQueryType[typeCount];
  357.                 BuiltInItemTypesStrict = new XmlQueryType[typeCount];
  358.                
  359.                 for (int i = 0; i < typeCount; i++) {
  360.                     XmlTypeCode typeCode = (XmlTypeCode)i;
  361.                    
  362.                     switch ((XmlTypeCode)i) {
  363.                         case XmlTypeCode.None:
  364.                             BuiltInItemTypes[i] = ChoiceType.None;
  365.                             BuiltInItemTypesStrict[i] = ChoiceType.None;
  366.                             continue;
  367.                         case XmlTypeCode.Item:
  368.                         case XmlTypeCode.Node:
  369.                            
  370.                             BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, false);
  371.                             BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
  372.                             break;
  373.                         case XmlTypeCode.Document:
  374.                         case XmlTypeCode.Element:
  375.                         case XmlTypeCode.Namespace:
  376.                         case XmlTypeCode.ProcessingInstruction:
  377.                         case XmlTypeCode.Comment:
  378.                         case XmlTypeCode.Text:
  379.                            
  380.                             BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true);
  381.                             BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
  382.                             break;
  383.                         case XmlTypeCode.Attribute:
  384.                            
  385.                             BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnySimpleType, false, false, true);
  386.                             BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
  387.                             break;
  388.                         case XmlTypeCode.AnyAtomicType:
  389.                            
  390.                             BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnyAtomicType, false, false, true);
  391.                             BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
  392.                             break;
  393.                         case XmlTypeCode.UntypedAtomic:
  394.                            
  395.                             // xdt:untypedAtomic is sealed, and therefore always strict
  396.                             BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, true, true);
  397.                             BuiltInItemTypesStrict[i] = BuiltInItemTypes[i];
  398.                             break;
  399.                         default:
  400.                            
  401.                             XmlSchemaType builtInType = XmlSchemaType.GetBuiltInSimpleType(typeCode);
  402.                             BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, false, true);
  403.                             BuiltInItemTypesStrict[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, true, true);
  404.                             break;
  405.                     }
  406.                 }
  407.                
  408.                
  409.                 UntypedDocument = new ItemType(XmlTypeCode.Document, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true);
  410.                 UntypedElement = new ItemType(XmlTypeCode.Element, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true);
  411.                 UntypedAttribute = new ItemType(XmlTypeCode.Attribute, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, false, true);
  412.                 NodeNotRtf = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true);
  413.                 NodeDod = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true);
  414.             }
  415.            
  416.             /// <summary>
  417.             /// Create ItemType from XmlTypeCode.
  418.             /// </summary>
  419.             public static XmlQueryType Create(XmlTypeCode code, bool isStrict)
  420.             {
  421.                 // No objects need to be allocated, as corresponding ItemTypes for all type codes have been statically allocated
  422.                 if (isStrict)
  423.                     return BuiltInItemTypesStrict[(int)code];
  424.                
  425.                 return BuiltInItemTypes[(int)code];
  426.             }
  427.            
  428.             /// <summary>
  429.             /// Create ItemType from Xsd atomic type.
  430.             /// </summary>
  431.             public static XmlQueryType Create(XmlSchemaSimpleType schemaType, bool isStrict)
  432.             {
  433.                 Debug.Assert(schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic, "List or Union Xsd types should have been handled by caller.");
  434.                 XmlTypeCode code = schemaType.Datatype.TypeCode;
  435.                
  436.                 // If schemaType is a built-in type,
  437.                 if (schemaType == XmlSchemaType.GetBuiltInSimpleType(code)) {
  438.                     // Then use statically allocated type
  439.                     return Create(code, isStrict);
  440.                 }
  441.                
  442.                 // Otherwise, create a new type
  443.                 return new ItemType(code, XmlQualifiedNameTest.Wildcard, schemaType, false, isStrict, true);
  444.             }
  445.            
  446.             /// <summary>
  447.             /// Create Document, Element or Attribute with specified name test, content type and nillable.
  448.             /// </summary>
  449.             public static XmlQueryType Create(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable)
  450.             {
  451.                 // If this is a Document, Element, or Attribute,
  452.                 switch (code) {
  453.                     case XmlTypeCode.Document:
  454.                     case XmlTypeCode.Element:
  455.                         if (nameTest.IsWildcard) {
  456.                             // Normalize document(*, xs:anyType), element(*, xs:anyType)
  457.                             if (contentType == XmlSchemaComplexType.AnyType)
  458.                                 return Create(code, false);
  459.                            
  460.                             // Normalize document(xs:untypedAny), element(*, xs:untypedAny)
  461.                             if (contentType == XmlSchemaComplexType.UntypedAnyType) {
  462.                                 Debug.Assert(!isNillable);
  463.                                 if (code == XmlTypeCode.Element)
  464.                                     return UntypedElement;
  465.                                 if (code == XmlTypeCode.Document)
  466.                                     return UntypedDocument;
  467.                             }
  468.                         }
  469.                         // Create new ItemType
  470.                         return new ItemType(code, nameTest, contentType, isNillable, false, true);
  471.                     case XmlTypeCode.Attribute:
  472.                        
  473.                         if (nameTest.IsWildcard) {
  474.                             // Normalize attribute(xs:anySimpleType)
  475.                             if (contentType == DatatypeImplementation.AnySimpleType)
  476.                                 return Create(code, false);
  477.                            
  478.                             // Normalize attribute(xs:untypedAtomic)
  479.                             if (contentType == DatatypeImplementation.UntypedAtomicType)
  480.                                 return UntypedAttribute;
  481.                         }
  482.                         // Create new ItemType
  483.                         return new ItemType(code, nameTest, contentType, isNillable, false, true);
  484.                     default:
  485.                        
  486.                         return Create(code, false);
  487.                    
  488.                 }
  489.             }
  490.            
  491.             /// <summary>
  492.             /// Private constructor. Create methods should be used to create instances.
  493.             /// </summary>
  494.             private ItemType(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType schemaType, bool isNillable, bool isStrict, bool isNotRtf)
  495.             {
  496.                 Debug.Assert(nameTest != null, "nameTest cannot be null");
  497.                 Debug.Assert(schemaType != null, "schemaType cannot be null");
  498.                 this.code = code;
  499.                 this.nameTest = nameTest;
  500.                 this.schemaType = schemaType;
  501.                 this.isNillable = isNillable;
  502.                 this.isStrict = isStrict;
  503.                 this.isNotRtf = isNotRtf;
  504.                
  505.                 Debug.Assert(!IsAtomicValue || schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic);
  506.                
  507.                 switch (code) {
  508.                     case XmlTypeCode.Item:
  509.                         this.nodeKinds = XmlNodeKindFlags.Any;
  510.                         break;
  511.                     case XmlTypeCode.Node:
  512.                         this.nodeKinds = XmlNodeKindFlags.Any;
  513.                         break;
  514.                     case XmlTypeCode.Document:
  515.                         this.nodeKinds = XmlNodeKindFlags.Document;
  516.                         break;
  517.                     case XmlTypeCode.Element:
  518.                         this.nodeKinds = XmlNodeKindFlags.Element;
  519.                         break;
  520.                     case XmlTypeCode.Attribute:
  521.                         this.nodeKinds = XmlNodeKindFlags.Attribute;
  522.                         break;
  523.                     case XmlTypeCode.Namespace:
  524.                         this.nodeKinds = XmlNodeKindFlags.Namespace;
  525.                         break;
  526.                     case XmlTypeCode.ProcessingInstruction:
  527.                         this.nodeKinds = XmlNodeKindFlags.PI;
  528.                         break;
  529.                     case XmlTypeCode.Comment:
  530.                         this.nodeKinds = XmlNodeKindFlags.Comment;
  531.                         break;
  532.                     case XmlTypeCode.Text:
  533.                         this.nodeKinds = XmlNodeKindFlags.Text;
  534.                         break;
  535.                     default:
  536.                         this.nodeKinds = XmlNodeKindFlags.None;
  537.                         break;
  538.                 }
  539.             }
  540.            
  541.             //-----------------------------------------------
  542.             // ItemType, OccurenceIndicator Properties
  543.             //-----------------------------------------------
  544.            
  545.             /// <summary>
  546.             /// Return the TypeCode.
  547.             /// </summary>
  548.             public override XmlTypeCode TypeCode {
  549.                 get { return this.code; }
  550.             }
  551.            
  552.             /// <summary>
  553.             /// Return the NameTest.
  554.             /// </summary>
  555.             public override XmlQualifiedNameTest NameTest {
  556.                 get { return this.nameTest; }
  557.             }
  558.            
  559.             /// <summary>
  560.             /// Return the Xsd schema type. This must be non-null for atomic value types.
  561.             /// </summary>
  562.             public override XmlSchemaType SchemaType {
  563.                 get { return this.schemaType; }
  564.             }
  565.            
  566.             /// <summary>
  567.             /// Return the IsNillable.
  568.             /// </summary>
  569.             public override bool IsNillable {
  570.                 get { return this.isNillable; }
  571.             }
  572.            
  573.             /// <summary>
  574.             /// Since this is always an atomic value type, NodeKinds = None.
  575.             /// </summary>
  576.             public override XmlNodeKindFlags NodeKinds {
  577.                 get { return this.nodeKinds; }
  578.             }
  579.            
  580.             /// <summary>
  581.             /// Return flag indicating whether the dynamic type is guaranteed to be the same as the static type.
  582.             /// </summary>
  583.             public override bool IsStrict {
  584.                 get { return this.isStrict; }
  585.             }
  586.            
  587.             /// <summary>
  588.             /// Return flag indicating whether this is not an Rtf.
  589.             /// </summary>
  590.             public override bool IsNotRtf {
  591.                 get { return this.isNotRtf; }
  592.             }
  593.            
  594.             /// <summary>
  595.             /// Only NodeDod type returns true.
  596.             /// </summary>
  597.             public override bool IsDod {
  598.                 get { return (object)this == (object)NodeDod; }
  599.             }
  600.            
  601.             /// <summary>
  602.             /// Always return cardinality One.
  603.             /// </summary>
  604.             public override XmlQueryCardinality Cardinality {
  605.                 get { return XmlQueryCardinality.One; }
  606.             }
  607.            
  608.             /// <summary>
  609.             /// Prime of atomic value type is itself.
  610.             /// </summary>
  611.             public override XmlQueryType Prime {
  612.                 get { return this; }
  613.             }
  614.            
  615.             /// <summary>
  616.             /// Return the item's converter.
  617.             /// </summary>
  618.             public override XmlValueConverter ClrMapping {
  619.                 get {
  620.                     // Return value converter from XmlSchemaType if type is atomic
  621.                     if (IsAtomicValue)
  622.                         return SchemaType.ValueConverter;
  623.                    
  624.                     // Return node converter if item must be a node
  625.                     if (IsNode)
  626.                         return XmlNodeConverter.Node;
  627.                    
  628.                     // Otherwise return item converter
  629.                     return XmlAnyConverter.Item;
  630.                 }
  631.             }
  632.            
  633.            
  634.             //-----------------------------------------------
  635.             // ListBase implementation
  636.             //-----------------------------------------------
  637.            
  638.             /// <summary>
  639.             /// AtomicValueType is only a composition of itself, rather than other smaller types.
  640.             /// </summary>
  641.             public override int Count {
  642.                 get { return 1; }
  643.             }
  644.            
  645.             /// <summary>
  646.             /// AtomicValueType is only a composition of itself, rather than other smaller types.
  647.             /// </summary>
  648.             public override XmlQueryType this[int index]
  649.             {
  650.                 get {
  651.                     if (index != 0)
  652.                         throw new IndexOutOfRangeException();
  653.                    
  654.                     return this;
  655.                 }
  656.                 set {
  657.                     throw new NotSupportedException();
  658.                 }
  659.             }
  660.         }
  661.        
  662.        
  663.         /// <summary>
  664.         /// Implementation of XmlQueryType that composes a choice of various prime types.
  665.         /// </summary>
  666.         private sealed class ChoiceType : XmlQueryType
  667.         {
  668.             public static readonly XmlQueryType None = new ChoiceType(new List<XmlQueryType>());
  669.            
  670.             private XmlTypeCode code;
  671.             private XmlSchemaType schemaType;
  672.             private XmlNodeKindFlags nodeKinds;
  673.             private List<XmlQueryType> members;
  674.            
  675.             /// <summary>
  676.             /// Create choice between node kinds.
  677.             /// </summary>
  678.             public static XmlQueryType Create(XmlNodeKindFlags nodeKinds)
  679.             {
  680.                 List<XmlQueryType> members;
  681.                
  682.                 // If exactly one kind is set, then create singleton ItemType
  683.                 if (Bits.ExactlyOne((uint)nodeKinds))
  684.                     return ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint)nodeKinds)], false);
  685.                
  686.                 members = new List<XmlQueryType>();
  687.                 while (nodeKinds != XmlNodeKindFlags.None) {
  688.                     members.Add(ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint)nodeKinds)], false));
  689.                    
  690.                     nodeKinds = (XmlNodeKindFlags)Bits.ClearLeast((uint)nodeKinds);
  691.                 }
  692.                
  693.                 return Create(members);
  694.             }
  695.            
  696.             /// <summary>
  697.             /// Create choice containing the specified list of types.
  698.             /// </summary>
  699.             public static XmlQueryType Create(List<XmlQueryType> members)
  700.             {
  701.                 if (members.Count == 0)
  702.                     return None;
  703.                
  704.                 if (members.Count == 1)
  705.                     return members[0];
  706.                
  707.                 return new ChoiceType(members);
  708.             }
  709.            
  710.             /// <summary>
  711.             /// Private constructor. Create methods should be used to create instances.
  712.             /// </summary>
  713.             private ChoiceType(List<XmlQueryType> members)
  714.             {
  715.                 Debug.Assert(members != null && members.Count != 1, "ChoiceType must contain a list with 0 or >1 types.");
  716.                
  717.                 this.members = members;
  718.                
  719.                 // Compute supertype of all member types
  720.                 for (int i = 0; i < members.Count; i++) {
  721.                     XmlQueryType t = members[i];
  722.                     Debug.Assert(t.Cardinality == XmlQueryCardinality.One, "ChoiceType member types must be prime types.");
  723.                    
  724.                     // Summarize the union of member types as a single type
  725.                     if (this.code == XmlTypeCode.None) {
  726.                         // None combined with member type is the member type
  727.                         this.code = t.TypeCode;
  728.                         this.schemaType = t.SchemaType;
  729.                     }
  730.                     else if (IsNode && t.IsNode) {
  731.                         // Node combined with node is node
  732.                         if (this.code == t.TypeCode) {
  733.                             // Element or attribute combined with element or attribute can be summarized as element(*, XmlSchemaComplexType.AnyType) or attribute(*, DatatypeImplementation.AnySimpleType)
  734.                             if (this.code == XmlTypeCode.Element)
  735.                                 this.schemaType = XmlSchemaComplexType.AnyType;
  736.                             else if (this.code == XmlTypeCode.Attribute)
  737.                                 this.schemaType = DatatypeImplementation.AnySimpleType;
  738.                         }
  739.                         else {
  740.                             this.code = XmlTypeCode.Node;
  741.                             this.schemaType = null;
  742.                         }
  743.                     }
  744.                     else if (IsAtomicValue && t.IsAtomicValue) {
  745.                         // Atomic value combined with atomic value is atomic value
  746.                         this.code = XmlTypeCode.AnyAtomicType;
  747.                         this.schemaType = DatatypeImplementation.AnyAtomicType;
  748.                     }
  749.                     else {
  750.                         // Else we'll summarize types as Item
  751.                         this.code = XmlTypeCode.Item;
  752.                         this.schemaType = null;
  753.                     }
  754.                    
  755.                     // Always track union of node kinds
  756.                     this.nodeKinds |= t.NodeKinds;
  757.                 }
  758.             }
  759.            
  760.                 /* None */                /* Document */                /* Element */                /* Attribute */                /* Text */                /* Comment */                /* PI */                /* Namespace */            private static readonly XmlTypeCode[] NodeKindToTypeCode = {XmlTypeCode.None, XmlTypeCode.Document, XmlTypeCode.Element, XmlTypeCode.Attribute, XmlTypeCode.Text, XmlTypeCode.Comment, XmlTypeCode.ProcessingInstruction, XmlTypeCode.Namespace};
  761.            
  762.            
  763.             //-----------------------------------------------
  764.             // ItemType, OccurenceIndicator Properties
  765.             //-----------------------------------------------
  766.            
  767.             /// <summary>
  768.             /// Return a type code which is a supertype of all member types.
  769.             /// </summary>
  770.             public override XmlTypeCode TypeCode {
  771.                 get { return this.code; }
  772.             }
  773.            
  774.             /// <summary>
  775.             /// Return the NameTest.
  776.             /// </summary>
  777.             public override XmlQualifiedNameTest NameTest {
  778.                 get { return XmlQualifiedNameTest.Wildcard; }
  779.             }
  780.            
  781.             /// <summary>
  782.             /// Return an Xsd schema type which is a supertype of all member types.
  783.             /// </summary>
  784.             public override XmlSchemaType SchemaType {
  785.                 get { return this.schemaType; }
  786.             }
  787.            
  788.             /// <summary>
  789.             /// Return the IsNillable.
  790.             /// </summary>
  791.             public override bool IsNillable {
  792.                 get { return false; }
  793.             }
  794.            
  795.             /// <summary>
  796.             /// Return a set of NodeKinds which is the union of all member node kinds.
  797.             /// </summary>
  798.             public override XmlNodeKindFlags NodeKinds {
  799.                 get { return this.nodeKinds; }
  800.             }
  801.            
  802.             /// <summary>
  803.             /// Choice types are always non-strict, except for the empty choice.
  804.             /// </summary>
  805.             public override bool IsStrict {
  806.                 get { return members.Count == 0; }
  807.             }
  808.            
  809.             /// <summary>
  810.             /// Return true if every type in the choice is not an Rtf.
  811.             /// </summary>
  812.             public override bool IsNotRtf {
  813.                 get {
  814.                     for (int i = 0; i < members.Count; i++) {
  815.                         if (!this.members[i].IsNotRtf)
  816.                             return false;
  817.                     }
  818.                     return true;
  819.                 }
  820.             }
  821.            
  822.             /// <summary>
  823.             /// Return true if every type in the choice is in document order with no duplicates.
  824.             /// </summary>
  825.             public override bool IsDod {
  826.                 get {
  827.                     for (int i = 0; i < members.Count; i++) {
  828.                         if (!this.members[i].IsDod)
  829.                             return false;
  830.                     }
  831.                     return true;
  832.                 }
  833.             }
  834.            
  835.             /// <summary>
  836.             /// Always return cardinality none or one.
  837.             /// </summary>
  838.             public override XmlQueryCardinality Cardinality {
  839.                 get { return TypeCode == XmlTypeCode.None ? XmlQueryCardinality.None : XmlQueryCardinality.One; }
  840.             }
  841.            
  842.             /// <summary>
  843.             /// Prime of union type is itself.
  844.             /// </summary>
  845.             public override XmlQueryType Prime {
  846.                 get { return this; }
  847.             }
  848.            
  849.             /// <summary>
  850.             /// Always return the item converter.
  851.             /// </summary>
  852.             public override XmlValueConverter ClrMapping {
  853.                 get {
  854.                     if (this.code == XmlTypeCode.None || this.code == XmlTypeCode.Item)
  855.                         return XmlAnyConverter.Item;
  856.                    
  857.                     if (IsAtomicValue)
  858.                         return SchemaType.ValueConverter;
  859.                    
  860.                     return XmlNodeConverter.Node;
  861.                 }
  862.             }
  863.            
  864.             //-----------------------------------------------
  865.             // ListBase implementation
  866.             //-----------------------------------------------
  867.            
  868.             /// <summary>
  869.             /// Return the number of union member types.
  870.             /// </summary>
  871.             public override int Count {
  872.                 get { return this.members.Count; }
  873.             }
  874.            
  875.             /// <summary>
  876.             /// Return a union member type by index.
  877.             /// </summary>
  878.             public override XmlQueryType this[int index]
  879.             {
  880.                 get { return this.members[index]; }
  881.                 set {
  882.                     throw new NotSupportedException();
  883.                 }
  884.             }
  885.         }
  886.        
  887.        
  888.         /// <summary>
  889.         /// Implementation of XmlQueryType that modifies the cardinality of a composed type.
  890.         /// </summary>
  891.         private sealed class SequenceType : XmlQueryType
  892.         {
  893.             public static readonly XmlQueryType Zero = new SequenceType(ChoiceType.None, XmlQueryCardinality.Zero);
  894.            
  895.             private XmlQueryType prime;
  896.             private XmlQueryCardinality card;
  897.             private XmlValueConverter converter;
  898.            
  899.             /// <summary>
  900.             /// Create sequence type from prime and cardinality.
  901.             /// </summary>
  902.             public static XmlQueryType Create(XmlQueryType prime, XmlQueryCardinality card)
  903.             {
  904.                 Debug.Assert(prime != null, "SequenceType can only modify the cardinality of a non-null XmlQueryType.");
  905.                 Debug.Assert(prime.IsSingleton, "Prime type must have cardinality one.");
  906.                
  907.                 if (prime.TypeCode == XmlTypeCode.None) {
  908.                     // If cardinality includes zero, then return (None, Zero), else return (None, None).
  909.                     return XmlQueryCardinality.Zero <= card ? Zero : None;
  910.                 }
  911.                
  912.                 // Normalize sequences with these cardinalities: None, Zero, One
  913.                
  914.                 if (card == XmlQueryCardinality.None) {
  915.                     return None;
  916.                 }
  917.                 else if (card == XmlQueryCardinality.Zero) {
  918.                     return Zero;
  919.                 }
  920.                 else if (card == XmlQueryCardinality.One) {
  921.                     return prime;
  922.                 }
  923.                
  924.                 return new SequenceType(prime, card);
  925.             }
  926.            
  927.             /// <summary>
  928.             /// Private constructor. Create methods should be used to create instances.
  929.             /// </summary>
  930.             private SequenceType(XmlQueryType prime, XmlQueryCardinality card)
  931.             {
  932.                 this.prime = prime;
  933.                 this.card = card;
  934.             }
  935.            
  936.             //-----------------------------------------------
  937.             // ItemType, OccurenceIndicator Properties
  938.             //-----------------------------------------------
  939.            
  940.             /// <summary>
  941.             /// Return the TypeCode of the prime type.
  942.             /// </summary>
  943.             public override XmlTypeCode TypeCode {
  944.                 get { return this.prime.TypeCode; }
  945.             }
  946.            
  947.             /// <summary>
  948.             /// Return the NameTest of the prime type
  949.             /// </summary>
  950.             public override XmlQualifiedNameTest NameTest {
  951.                 get { return this.prime.NameTest; }
  952.             }
  953.            
  954.             /// <summary>
  955.             /// Return the Xsd schema type of the prime type.
  956.             /// </summary>
  957.             public override XmlSchemaType SchemaType {
  958.                 get { return this.prime.SchemaType; }
  959.             }
  960.            
  961.             /// <summary>
  962.             /// Return the IsNillable of the prime type
  963.             /// </summary>
  964.             public override bool IsNillable {
  965.                 get { return this.prime.IsNillable; }
  966.             }
  967.            
  968.             /// <summary>
  969.             /// Return the NodeKinds of the prime type.
  970.             /// </summary>
  971.             public override XmlNodeKindFlags NodeKinds {
  972.                 get { return this.prime.NodeKinds; }
  973.             }
  974.            
  975.             /// <summary>
  976.             /// Return the IsStrict flag of the prime type.
  977.             /// </summary>
  978.             public override bool IsStrict {
  979.                 get { return this.prime.IsStrict; }
  980.             }
  981.            
  982.             /// <summary>
  983.             /// Return the IsNotRtf flag of the prime type.
  984.             /// </summary>
  985.             public override bool IsNotRtf {
  986.                 get { return this.prime.IsNotRtf; }
  987.             }
  988.            
  989.             /// <summary>
  990.             /// Return the IsDod flag of the prime type.
  991.             /// </summary>
  992.             public override bool IsDod {
  993.                 get { return this.prime.IsDod; }
  994.             }
  995.            
  996.             /// <summary>
  997.             /// Return the modified cardinality.
  998.             /// </summary>
  999.             public override XmlQueryCardinality Cardinality {
  1000.                 get { return this.card; }
  1001.             }
  1002.            
  1003.             /// <summary>
  1004.             /// Return prime of sequence type.
  1005.             /// </summary>
  1006.             public override XmlQueryType Prime {
  1007.                 get { return this.prime; }
  1008.             }
  1009.            
  1010.             /// <summary>
  1011.             /// Return the prime's converter wrapped in a list converter.
  1012.             /// </summary>
  1013.             public override XmlValueConverter ClrMapping {
  1014.                 get {
  1015.                     if (this.converter == null)
  1016.                         this.converter = XmlListConverter.Create(this.prime.ClrMapping);
  1017.                    
  1018.                     return this.converter;
  1019.                 }
  1020.             }
  1021.            
  1022.            
  1023.             //-----------------------------------------------
  1024.             // ListBase implementation
  1025.             //-----------------------------------------------
  1026.            
  1027.             /// <summary>
  1028.             /// Return the Count of the prime type.
  1029.             /// </summary>
  1030.             public override int Count {
  1031.                 get { return this.prime.Count; }
  1032.             }
  1033.            
  1034.             /// <summary>
  1035.             /// Return the parts of the prime type.
  1036.             /// </summary>
  1037.             public override XmlQueryType this[int index]
  1038.             {
  1039.                 get { return this.prime[index]; }
  1040.                 set {
  1041.                     throw new NotSupportedException();
  1042.                 }
  1043.             }
  1044.         }
  1045.        
  1046.         /// <summary>
  1047.         /// Create a Node XmlQueryType having an XSD content type.
  1048.         /// </summary>
  1049.         /// <param name="code">unless kind is Root, Element, or Attribute, "contentType" is ignored</param>
  1050.         /// <param name="contentType">content type of the node</param>
  1051.         /// <returns>the node type</returns>
  1052.         public static XmlQueryType Type(XPathNodeType kind, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable)
  1053.         {
  1054.             return ItemType.Create(NodeKindToTypeCode[(int)kind], nameTest, contentType, isNillable);
  1055.         }
  1056.        
  1057.         #if NEVER // Remove from code since we don't use and FxCop complains. May re-add later.
  1058.         private XmlSchemaSet schemaSet;
  1059.        
  1060.         /// <summary>
  1061.         /// Create an XmlQueryType having an XSD name test, content type and nillable.
  1062.         /// </summary>
  1063.         /// <param name="code">unless code is Document, Element, or Attribute, "contentType" is ignored</param>
  1064.         /// <param name="nameTest">name test on the node</param>
  1065.         /// <param name="contentType">content type of the node</param>
  1066.         /// <param name="isNillable">nillable property</param>
  1067.         /// <returns>the item type</returns>
  1068.         public XmlQueryType Type(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable)
  1069.         {
  1070.             return ItemType.Create(code, nameTest, contentType, isNillable);
  1071.         }
  1072.        
  1073.         /// <summary>
  1074.         /// Create a strict XmlQueryType from the source.
  1075.         /// </summary>
  1076.         /// <param name="source">source type</param>
  1077.         /// <returns>strict type if the source is atomic, the source otherwise</returns>
  1078.         public XmlQueryType StrictType(XmlQueryType source)
  1079.         {
  1080.             if (source.IsAtomicValue && source.Count == 1)
  1081.                 return SequenceType.Create(ItemType.Create((XmlSchemaSimpleType)source.SchemaType, true), source.Cardinality);
  1082.            
  1083.             return source;
  1084.         }
  1085.        
  1086.         /// <summary>
  1087.         /// Create an XmlQueryType from an XmlTypeCode and cardinality.
  1088.         /// </summary>
  1089.         /// <param name="code">the type code of the item</param>
  1090.         /// <param name="card">cardinality</param>
  1091.         /// <returns>build-in type type</returns>
  1092.         public XmlQueryType Type(XmlTypeCode code, XmlQueryCardinality card)
  1093.         {
  1094.             return SequenceType.Create(ItemType.Create(code, false), card);
  1095.         }
  1096.        
  1097.         /// <summary>
  1098.         /// Create an XmlQueryType having an XSD name test, content type, nillable and cardinality.
  1099.         /// </summary>
  1100.         /// <param name="code">unless code is Document, Element, or Attribute, "contentType" is ignored</param>
  1101.         /// <param name="nameTest">name test on the node</param>
  1102.         /// <param name="contentType">content type of the node</param>
  1103.         /// <param name="isNillable">nillable property</param>
  1104.         /// <param name="card">cardinality</param>
  1105.         /// <returns>the item type</returns>
  1106.         public XmlQueryType Type(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable, XmlQueryCardinality card)
  1107.         {
  1108.             return SequenceType.Create(ItemType.Create(code, nameTest, contentType, isNillable), card);
  1109.         }
  1110.        
  1111.         /// <summary>
  1112.         /// Construct the intersection of two XmlQueryTypes
  1113.         /// </summary>
  1114.         /// <param name="left">the left type</param>
  1115.         /// <param name="right">the right type</param>
  1116.         /// <returns>the intersection type</returns>
  1117.         public XmlQueryType Intersect(XmlQueryType left, XmlQueryType right)
  1118.         {
  1119.             return SequenceType.Create(ChoiceType.Create(PrimeIntersect(left, right)), left.Cardinality & right.Cardinality);
  1120.         }
  1121.        
  1122.         /// <summary>
  1123.         /// Construct the intersection of several XmlQueryTypes
  1124.         /// </summary>
  1125.         /// <param name="types">the list of types</param>
  1126.         /// <returns>the intersection type</returns>
  1127.         public XmlQueryType Intersect(params XmlQueryType[] types)
  1128.         {
  1129.             if (types.Length == 0)
  1130.                 return None;
  1131.             else if (types.Length == 1)
  1132.                 return types[0];
  1133.            
  1134.             // Intersect each type with next type
  1135.             List<XmlQueryType> list = PrimeIntersect(types[0], types[1]);
  1136.             XmlQueryCardinality card = types[0].Cardinality & types[1].Cardinality;
  1137.            
  1138.             for (int i = 2; i < types.Length; i++) {
  1139.                 list = PrimeIntersect(list, types[i]);
  1140.                 card &= types[i].Cardinality;
  1141.             }
  1142.            
  1143.             return SequenceType.Create(ChoiceType.Create(list), card);
  1144.         }
  1145.        
  1146.         /// <summary>
  1147.         /// Construct the intersection of two lists of prime XmlQueryTypes.
  1148.         /// </summary>
  1149.         private List<XmlQueryType> PrimeIntersect(IList<XmlQueryType> left, IList<XmlQueryType> right)
  1150.         {
  1151.             List<XmlQueryType> list = new List<XmlQueryType>();
  1152.            
  1153.             foreach (XmlQueryType leftItem in left) {
  1154.                 foreach (XmlQueryType rightItem in right) {
  1155.                     XmlQueryType intersection = IntersectItemTypes(leftItem, rightItem);
  1156.                     // Do not add none1 to a list
  1157.                     if ((object)intersection != (object)None) {
  1158.                         list.Add(intersection);
  1159.                     }
  1160.                 }
  1161.             }
  1162.             return list;
  1163.         }
  1164.        
  1165.         /// <summary>
  1166.         /// Converts type of sequence of items to type of sequnce of atomic value
  1167.         // See http://www.w3.org/TR/2004/xquery-semantics/#jd_data for the detailed description
  1168.         /// </summary>
  1169.         /// <param name="source">source type</param>
  1170.         /// <returns>type of the sequence of atomic values</returns>
  1171.         public XmlQueryType DataOn(XmlQueryType source)
  1172.         {
  1173.             List<XmlQueryType> list = new List<XmlQueryType>();
  1174.             XmlQueryCardinality card = XmlQueryCardinality.None;
  1175.            
  1176.             foreach (XmlQueryType sourceItem in source) {
  1177.                 switch (sourceItem.TypeCode) {
  1178.                     case XmlTypeCode.Item:
  1179.                     case XmlTypeCode.Node:
  1180.                         AddItemToChoice(list, AnyAtomicType);
  1181.                         card = XmlQueryCardinality.ZeroOrMore;
  1182.                         break;
  1183.                     case XmlTypeCode.Document:
  1184.                     case XmlTypeCode.Text:
  1185.                         AddItemToChoice(list, UntypedAtomic);
  1186.                         card |= XmlQueryCardinality.One;
  1187.                         break;
  1188.                     case XmlTypeCode.Comment:
  1189.                     case XmlTypeCode.ProcessingInstruction:
  1190.                         AddItemToChoice(list, String);
  1191.                         card |= XmlQueryCardinality.One;
  1192.                         break;
  1193.                     case XmlTypeCode.Element:
  1194.                     case XmlTypeCode.Attribute:
  1195.                         XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
  1196.                         if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType || sourceSchemaType == DatatypeImplementation.UntypedAtomicType) {
  1197.                             AddItemToChoice(list, UntypedAtomic);
  1198.                             card |= XmlQueryCardinality.One;
  1199.                         }
  1200.                         else if (sourceSchemaType == XmlSchemaComplexType.AnyType || sourceSchemaType == DatatypeImplementation.AnySimpleType) {
  1201.                             AddItemToChoice(list, AnyAtomicType);
  1202.                             card = XmlQueryCardinality.ZeroOrMore;
  1203.                         }
  1204.                         else {
  1205.                             if (sourceSchemaType.Datatype == null) {
  1206.                                 // Complex content adds anyAtomicType* if mixed
  1207.                                 XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceItem.SchemaType;
  1208.                                 if (complexType.ContentType == XmlSchemaContentType.Mixed) {
  1209.                                     AddItemToChoice(list, AnyAtomicType);
  1210.                                     card = XmlQueryCardinality.ZeroOrMore;
  1211.                                 }
  1212.                                 else {
  1213.                                     // Error if mixed is false
  1214.                                     return null;
  1215.                                 }
  1216.                             }
  1217.                             else {
  1218.                                 // Simple content
  1219.                                 XmlSchemaType schemaType = sourceItem.SchemaType;
  1220.                                
  1221.                                 // Go up the tree until it's a simple type
  1222.                                 while (schemaType is XmlSchemaComplexType) {
  1223.                                     schemaType = schemaType.BaseXmlSchemaType;
  1224.                                 }
  1225.                                
  1226.                                 // Calculate XmlQueryType from XmlSchemaSimpleType
  1227.                                 XmlQueryType atomicSeq = Type((XmlSchemaSimpleType)schemaType, false);
  1228.                                
  1229.                                 // Add prime to a choice
  1230.                                 // It doen't have to be a single item!
  1231.                                 PrimeChoice(list, atomicSeq.Prime);
  1232.                                
  1233.                                 // Add cardinality to a choice
  1234.                                 card |= atomicSeq.Cardinality;
  1235.                             }
  1236.                             // Add ? if nillable
  1237.                             if (sourceItem.IsNillable) {
  1238.                                 card *= XmlQueryCardinality.ZeroOrOne;
  1239.                             }
  1240.                         }
  1241.                         break;
  1242.                     case XmlTypeCode.Namespace:
  1243.                         card |= XmlQueryCardinality.Zero;
  1244.                         break;
  1245.                     case XmlTypeCode.None:
  1246.                         break;
  1247.                     default:
  1248.                         Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
  1249.                         AddItemToChoice(list, sourceItem);
  1250.                         card |= XmlQueryCardinality.One;
  1251.                         break;
  1252.                 }
  1253.             }
  1254.             return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
  1255.         }
  1256.        
  1257.         /// <summary>
  1258.         /// Filter type of node sequence with a type (filter)
  1259.         /// </summary>
  1260.         /// <param name="source">source type</param>
  1261.         /// <param name="filter">type filter</param>
  1262.         /// <returns>type of the filtered node sequence</returns>
  1263.         public XmlQueryType FilterOf(XmlQueryType source, XmlQueryType filter)
  1264.         {
  1265.             Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
  1266.             List<XmlQueryType> list = new List<XmlQueryType>();
  1267.             XmlQueryCardinality card = XmlQueryCardinality.None;
  1268.            
  1269.             foreach (XmlQueryType sourceItem in source) {
  1270.                 card |= AddFilteredPrime(list, sourceItem, filter, true);
  1271.             }
  1272.             // Make sure that cardinality is at least Zero
  1273.             return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
  1274.         }
  1275.        
  1276.         /// <summary>
  1277.         /// For the type of node sequence calculate type of children filtered with a type (filter)
  1278.         /// </summary>
  1279.         /// <param name="source">source type</param>
  1280.         /// <param name="filter">type filter</param>
  1281.         /// <returns>type of the children node sequence</returns>
  1282.         public XmlQueryType ChildrenOf(XmlQueryType source, XmlQueryType filter)
  1283.         {
  1284.             Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
  1285.             List<XmlQueryType> list = new List<XmlQueryType>();
  1286.             XmlQueryCardinality card = XmlQueryCardinality.None;
  1287.            
  1288.             foreach (XmlQueryType sourceItem in source) {
  1289.                 switch (sourceItem.TypeCode) {
  1290.                     case XmlTypeCode.Node:
  1291.                     case XmlTypeCode.Document:
  1292.                     case XmlTypeCode.Element:
  1293.                         XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
  1294.                         XmlQueryCardinality itemCard = XmlQueryCardinality.None;
  1295.                         // Only element and document can have children
  1296.                         if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) {
  1297.                             // content of xdt:untypedAny is element(*, xdt:untypedAny)*
  1298.                             itemCard = (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore);
  1299.                             itemCard += AddFilteredPrime(list, Text, filter);
  1300.                         }
  1301.                         else if (sourceSchemaType.Datatype != null) {
  1302.                             // Text is the only child node simple type can have
  1303.                             itemCard = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne;
  1304.                         }
  1305.                         else {
  1306.                             // Complex content
  1307.                             XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType;
  1308.                             itemCard = AddChildParticle(list, complexType.ContentTypeParticle, filter);
  1309.                             if (complexType.ContentType == XmlSchemaContentType.Mixed) {
  1310.                                 itemCard += AddFilteredPrime(list, Text, filter);
  1311.                             }
  1312.                         }
  1313.                         itemCard += AddFilteredPrime(list, PI, filter);
  1314.                         itemCard += AddFilteredPrime(list, Comment, filter);
  1315.                         card |= itemCard;
  1316.                         break;
  1317.                     case XmlTypeCode.Attribute:
  1318.                     case XmlTypeCode.ProcessingInstruction:
  1319.                     case XmlTypeCode.Comment:
  1320.                     case XmlTypeCode.Namespace:
  1321.                     case XmlTypeCode.Text:
  1322.                        
  1323.                         card |= XmlQueryCardinality.Zero;
  1324.                         break;
  1325.                     default:
  1326.                        
  1327.                         Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
  1328.                         return null;
  1329.                 }
  1330.             }
  1331.             // Make sure that cardinality is at least Zero
  1332.             return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
  1333.         }
  1334.        
  1335.         /// <summary>
  1336.         /// For the type of node sequence calculate type of attributes filtered with a type (filter)
  1337.         /// </summary>
  1338.         /// <param name="source">source type</param>
  1339.         /// <param name="filter">type filter</param>
  1340.         /// <returns>type of the children node sequence</returns>
  1341.         public XmlQueryType AttributesOf(XmlQueryType source, XmlQueryType filter)
  1342.         {
  1343.             Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
  1344.             List<XmlQueryType> list = new List<XmlQueryType>();
  1345.             XmlQueryCardinality card = XmlQueryCardinality.None;
  1346.            
  1347.             foreach (XmlQueryType sourceItem in source) {
  1348.                 switch (sourceItem.TypeCode) {
  1349.                     case XmlTypeCode.Node:
  1350.                     case XmlTypeCode.Element:
  1351.                         XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
  1352.                         if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) {
  1353.                             // attfibutes of of xdt:untypedAny are attribute(*, xdt:untypedAtomic)*
  1354.                             card |= AddFilteredPrime(list, UntypedAttribute, filter) * XmlQueryCardinality.ZeroOrOne;
  1355.                         }
  1356.                         else {
  1357.                             // Only complex type can have attributes
  1358.                             XmlSchemaComplexType type = sourceSchemaType as XmlSchemaComplexType;
  1359.                             if (type != null) {
  1360.                                 card |= AddAttributes(list, type.AttributeUses, type.AttributeWildcard, filter);
  1361.                             }
  1362.                         }
  1363.                         break;
  1364.                     case XmlTypeCode.Document:
  1365.                     case XmlTypeCode.Attribute:
  1366.                     case XmlTypeCode.ProcessingInstruction:
  1367.                     case XmlTypeCode.Comment:
  1368.                     case XmlTypeCode.Namespace:
  1369.                     case XmlTypeCode.Text:
  1370.                        
  1371.                         card |= XmlQueryCardinality.Zero;
  1372.                         break;
  1373.                     default:
  1374.                        
  1375.                         Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
  1376.                         return null;
  1377.                 }
  1378.             }
  1379.             // Make sure that cardinality is at least Zero
  1380.             return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
  1381.         }
  1382.        
  1383.         /// <summary>
  1384.         /// For the type of node sequence calculate type of parent filtered with a type (filter)
  1385.         /// </summary>
  1386.         /// <param name="source">source type</param>
  1387.         /// <param name="filter">type filter</param>
  1388.         /// <returns>type of the parent node sequence</returns>
  1389.         public XmlQueryType ParentOf(XmlQueryType source, XmlQueryType filter)
  1390.         {
  1391.             Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
  1392.             List<XmlQueryType> list = new List<XmlQueryType>();
  1393.             XmlQueryCardinality card = XmlQueryCardinality.None;
  1394.            
  1395.             foreach (XmlQueryType sourceItem in source) {
  1396.                 switch (sourceItem.TypeCode) {
  1397.                     case XmlTypeCode.Node:
  1398.                     case XmlTypeCode.ProcessingInstruction:
  1399.                     case XmlTypeCode.Comment:
  1400.                     case XmlTypeCode.Text:
  1401.                     case XmlTypeCode.Element:
  1402.                         if (schemaSet == null) {
  1403.                             card |= AddFilteredPrime(list, UntypedDocument, filter) * XmlQueryCardinality.ZeroOrOne;
  1404.                             card |= AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrOne;
  1405.                         }
  1406.                         else {
  1407.                             card |= AddFilteredPrime(list, Document, filter) * XmlQueryCardinality.ZeroOrOne;
  1408.                             card |= AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrOne;
  1409.                         }
  1410.                         break;
  1411.                     case XmlTypeCode.Namespace:
  1412.                     case XmlTypeCode.Attribute:
  1413.                        
  1414.                         if (schemaSet == null) {
  1415.                             card |= (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrOne);
  1416.                         }
  1417.                         else {
  1418.                             card |= (AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrOne);
  1419.                         }
  1420.                         break;
  1421.                     case XmlTypeCode.Document:
  1422.                        
  1423.                         card |= XmlQueryCardinality.Zero;
  1424.                         break;
  1425.                     default:
  1426.                        
  1427.                         Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
  1428.                         break;
  1429.                 }
  1430.             }
  1431.             // Make sure that cardinality is at least Zero
  1432.             return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
  1433.         }
  1434.        
  1435.         /// <summary>
  1436.         /// For the type of node sequence calculate type of descendants filtered with a type (filter)
  1437.         /// </summary>
  1438.         /// <param name="source">source type</param>
  1439.         /// <param name="filter">type filter</param>
  1440.         /// <returns>type of the descendants node sequence</returns>
  1441.         public XmlQueryType DescendantsOf(XmlQueryType source, XmlQueryType filter)
  1442.         {
  1443.             Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
  1444.             List<XmlQueryType> list = new List<XmlQueryType>();
  1445.             XmlQueryCardinality card = XmlQueryCardinality.None;
  1446.            
  1447.             foreach (XmlQueryType sourceItem in source) {
  1448.                 switch (sourceItem.TypeCode) {
  1449.                     case XmlTypeCode.Node:
  1450.                     case XmlTypeCode.Document:
  1451.                     case XmlTypeCode.Element:
  1452.                         XmlQueryCardinality itemCard = XmlQueryCardinality.None;
  1453.                         if ((filter.NodeKinds & (XmlNodeKindFlags.Element | XmlNodeKindFlags.Text)) != 0) {
  1454.                             Dictionary<XmlQualifiedName, XmlQueryCardinality> allTypes = new Dictionary<XmlQualifiedName, XmlQueryCardinality>();
  1455.                             XmlSchemaType sourceSchemaType = sourceItem.SchemaType;
  1456.                             if (sourceSchemaType == null) {
  1457.                                 Debug.Assert(sourceItem.TypeCode == XmlTypeCode.Node);
  1458.                                 sourceSchemaType = XmlSchemaComplexType.AnyType;
  1459.                             }
  1460.                             itemCard = AddElementOrTextDescendants(list, allTypes, sourceSchemaType, filter);
  1461.                         }
  1462.                         itemCard += AddFilteredPrime(list, PI, filter);
  1463.                         itemCard += AddFilteredPrime(list, Comment, filter);
  1464.                         card |= itemCard;
  1465.                         break;
  1466.                     case XmlTypeCode.Attribute:
  1467.                     case XmlTypeCode.ProcessingInstruction:
  1468.                     case XmlTypeCode.Comment:
  1469.                     case XmlTypeCode.Namespace:
  1470.                     case XmlTypeCode.Text:
  1471.                        
  1472.                         card |= XmlQueryCardinality.Zero;
  1473.                         break;
  1474.                     default:
  1475.                        
  1476.                         Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
  1477.                         break;
  1478.                 }
  1479.             }
  1480.             // Make sure that cardinality is at least Zero
  1481.             return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
  1482.         }
  1483.        
  1484.         /// <summary>
  1485.         /// For the type of node sequence calculate type of ancestor filtered with a type (filter)
  1486.         /// </summary>
  1487.         /// <param name="source">source type</param>
  1488.         /// <param name="filter">type filter</param>
  1489.         /// <returns>type of the ancestor node sequence</returns>
  1490.         public XmlQueryType AncestorsOf(XmlQueryType source, XmlQueryType filter)
  1491.         {
  1492.             Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton);
  1493.             List<XmlQueryType> list = new List<XmlQueryType>();
  1494.             XmlQueryCardinality card = XmlQueryCardinality.None;
  1495.            
  1496.             foreach (XmlQueryType sourceItem in source) {
  1497.                 switch (sourceItem.TypeCode) {
  1498.                     case XmlTypeCode.Node:
  1499.                     case XmlTypeCode.ProcessingInstruction:
  1500.                     case XmlTypeCode.Comment:
  1501.                     case XmlTypeCode.Text:
  1502.                     case XmlTypeCode.Element:
  1503.                     case XmlTypeCode.Namespace:
  1504.                     case XmlTypeCode.Attribute:
  1505.                         if (schemaSet == null) {
  1506.                             card |= (AddFilteredPrime(list, UntypedDocument, filter) * XmlQueryCardinality.ZeroOrOne) + (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore);
  1507.                         }
  1508.                         else {
  1509.                             card |= (AddFilteredPrime(list, Document, filter) * XmlQueryCardinality.ZeroOrOne) + (AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrMore);
  1510.                         }
  1511.                         break;
  1512.                     case XmlTypeCode.Document:
  1513.                        
  1514.                         card |= XmlQueryCardinality.Zero;
  1515.                         break;
  1516.                     default:
  1517.                        
  1518.                         Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node");
  1519.                         break;
  1520.                 }
  1521.             }
  1522.             // Make sure that cardinality is at least Zero
  1523.             return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card);
  1524.         }
  1525.        
  1526.         private XmlQueryCardinality AddAttributes(List<XmlQueryType> list, XmlSchemaObjectTable attributeUses, XmlSchemaAnyAttribute attributeWildcard, XmlQueryType filter)
  1527.         {
  1528.             XmlQueryCardinality card = XmlQueryCardinality.Zero;
  1529.             if (attributeWildcard != null) {
  1530.                 XmlSchemaType attributeSchemaType = attributeWildcard.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? DatatypeImplementation.UntypedAtomicType : DatatypeImplementation.AnySimpleType;
  1531.                
  1532.                 // wildcard will match more then one attribute
  1533.                 switch (attributeWildcard.NamespaceList.Type) {
  1534.                     case NamespaceList.ListType.Set:
  1535.                         foreach (string ns in attributeWildcard.NamespaceList.Enumerate) {
  1536.                             card += AddFilteredPrime(list, CreateAttributeType(ns, false, attributeSchemaType), filter);
  1537.                         }
  1538.                         break;
  1539.                     case NamespaceList.ListType.Other:
  1540.                         card += AddFilteredPrime(list, CreateAttributeType(attributeWildcard.NamespaceList.Excluded, true, attributeSchemaType), filter);
  1541.                         break;
  1542.                     case NamespaceList.ListType.Any:
  1543.                     default:
  1544.                         card += AddFilteredPrime(list, attributeWildcard.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedAttribute : Attribute, filter);
  1545.                         break;
  1546.                 }
  1547.                 // Always optional
  1548.                 card *= XmlQueryCardinality.ZeroOrOne;
  1549.             }
  1550.             foreach (XmlSchemaAttribute attribute in attributeUses.Values) {
  1551.                 XmlQueryCardinality cardAttr = AddFilteredPrime(list, CreateAttributeType(attribute), filter);
  1552.                 if (cardAttr != XmlQueryCardinality.Zero) {
  1553.                     Debug.Assert(cardAttr == XmlQueryCardinality.ZeroOrOne || cardAttr == XmlQueryCardinality.One);
  1554.                     card += (attribute.Use == XmlSchemaUse.Optional ? XmlQueryCardinality.ZeroOrOne : cardAttr);
  1555.                 }
  1556.             }
  1557.             return card;
  1558.         }
  1559.        
  1560.         private XmlQueryType CreateAttributeType(XmlSchemaAttribute attribute)
  1561.         {
  1562.             return ItemType.Create(XmlTypeCode.Attribute, XmlQualifiedNameTest.New(attribute.QualifiedName), attribute.AttributeSchemaType, false);
  1563.         }
  1564.        
  1565.         private XmlQueryType CreateAttributeType(string ns, bool exclude, XmlSchemaType schemaType)
  1566.         {
  1567.             return ItemType.Create(XmlTypeCode.Attribute, XmlQualifiedNameTest.New(ns, exclude), schemaType, false);
  1568.         }
  1569.        
  1570.         private XmlQueryCardinality AddDescendantParticle(List<XmlQueryType> list, Dictionary<XmlQualifiedName, XmlQueryCardinality> allTypes, XmlSchemaParticle particle, XmlQueryType filter)
  1571.         {
  1572.             XmlQueryCardinality card = XmlQueryCardinality.None;
  1573.             XmlSchemaElement element = particle as XmlSchemaElement;
  1574.             if (element != null) {
  1575.                 // Single element
  1576.                 XmlQueryType elementType = CreateElementType(element);
  1577.                
  1578.                 // Add it
  1579.                 card = AddFilteredPrime(list, elementType, filter);
  1580.                
  1581.                 // Descend
  1582.                 card += AddElementOrTextDescendants(list, allTypes, elementType.SchemaType, filter);
  1583.             }
  1584.             else {
  1585.                 XmlSchemaAny any = particle as XmlSchemaAny;
  1586.                 if (any != null) {
  1587.                     // Descendants of any
  1588.                     card = AddFilteredPrime(list, Element, filter);
  1589.                 }
  1590.                 else {
  1591.                     XmlSchemaGroupBase group = particle as XmlSchemaGroupBase;
  1592.                     if (group.Items.Count != 0) {
  1593.                         if (particle is XmlSchemaChoice) {
  1594.                             foreach (XmlSchemaParticle p in group.Items) {
  1595.                                 card |= AddDescendantParticle(list, allTypes, p, filter);
  1596.                             }
  1597.                         }
  1598.                         else {
  1599.                             // Sequence and All
  1600.                             foreach (XmlSchemaParticle p in group.Items) {
  1601.                                 card += AddDescendantParticle(list, allTypes, p, filter);
  1602.                             }
  1603.                         }
  1604.                     }
  1605.                 }
  1606.             }
  1607.             return card * CardinalityOfParticle(particle);
  1608.         }
  1609.        
  1610.         private XmlQueryCardinality AddElementOrTextDescendants(List<XmlQueryType> list, Dictionary<XmlQualifiedName, XmlQueryCardinality> allTypes, XmlSchemaType sourceSchemaType, XmlQueryType filter)
  1611.         {
  1612.             XmlQueryCardinality card = XmlQueryCardinality.None;
  1613.             if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) {
  1614.                 card = AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore;
  1615.                 card += AddFilteredPrime(list, Text, filter);
  1616.             }
  1617.             else if (sourceSchemaType.Datatype != null) {
  1618.                 // Text is the only child node simple content of complext type
  1619.                 card = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne;
  1620.             }
  1621.             else {
  1622.                 // Complex content
  1623.                 XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType;
  1624.                 if (complexType.QualifiedName.IsEmpty || !allTypes.TryGetValue(complexType.QualifiedName, out card)) {
  1625.                     allTypes[complexType.QualifiedName] = XmlQueryCardinality.ZeroOrMore;
  1626.                     // take care of left recursion
  1627.                     card = AddDescendantParticle(list, allTypes, complexType.ContentTypeParticle, filter);
  1628.                     allTypes[complexType.QualifiedName] = card;
  1629.                     //set correct card
  1630.                     if (complexType.ContentType == XmlSchemaContentType.Mixed) {
  1631.                         card += AddFilteredPrime(list, Text, filter);
  1632.                     }
  1633.                 }
  1634.             }
  1635.             return card;
  1636.         }
  1637.        
  1638.         /// <summary>
  1639.         /// Create type based on an XmlSchemaElement
  1640.         /// </summary>
  1641.         private XmlQueryType CreateElementType(XmlSchemaElement element)
  1642.         {
  1643.             return ItemType.Create(XmlTypeCode.Element, XmlQualifiedNameTest.New(element.QualifiedName), element.ElementSchemaType, element.IsNillable);
  1644.         }
  1645.        
  1646.         /// <summary>
  1647.         /// Create type based on a wildcard
  1648.         /// </summary>
  1649.         private XmlQueryType CreateElementType(string ns, bool exclude, XmlSchemaType schemaType)
  1650.         {
  1651.             return ItemType.Create(XmlTypeCode.Element, XmlQualifiedNameTest.New(ns, exclude), schemaType, false);
  1652.         }
  1653.        
  1654.         /// <summary>
  1655.         /// Descend though the content model
  1656.         /// </summary>
  1657.         private XmlQueryCardinality AddChildParticle(List<XmlQueryType> list, XmlSchemaParticle particle, XmlQueryType filter)
  1658.         {
  1659.             XmlQueryCardinality card = XmlQueryCardinality.None;
  1660.             XmlSchemaElement element = particle as XmlSchemaElement;
  1661.             if (element != null) {
  1662.                 // Single element
  1663.                 card = AddFilteredPrime(list, CreateElementType(element), filter);
  1664.             }
  1665.             else {
  1666.                 // XmlSchemaAny matches more then one element
  1667.                 XmlSchemaAny any = particle as XmlSchemaAny;
  1668.                 if (any != null) {
  1669.                     XmlSchemaType elementSchemaType = any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? XmlSchemaComplexType.UntypedAnyType : XmlSchemaComplexType.AnyType;
  1670.                     switch (any.NamespaceList.Type) {
  1671.                         case NamespaceList.ListType.Set:
  1672.                             // Add a separate type for each namespace in the list
  1673.                             foreach (string ns in any.NamespaceList.Enumerate) {
  1674.                                 card |= AddFilteredPrime(list, CreateElementType(ns, false, elementSchemaType), filter);
  1675.                             }
  1676.                             break;
  1677.                         case NamespaceList.ListType.Other:
  1678.                             // Add ##other
  1679.                             card = AddFilteredPrime(list, CreateElementType(any.NamespaceList.Excluded, true, elementSchemaType), filter);
  1680.                             break;
  1681.                         case NamespaceList.ListType.Any:
  1682.                         default:
  1683.                             // Add ##any
  1684.                             card = AddFilteredPrime(list, any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedElement : Element, filter);
  1685.                             break;
  1686.                     }
  1687.                 }
  1688.                 else {
  1689.                     // recurse into particle group
  1690.                     XmlSchemaGroupBase group = particle as XmlSchemaGroupBase;
  1691.                     if (group.Items.Count != 0) {
  1692.                         if (particle is XmlSchemaChoice) {
  1693.                             foreach (XmlSchemaParticle p in group.Items) {
  1694.                                 card |= AddChildParticle(list, p, filter);
  1695.                             }
  1696.                         }
  1697.                         else {
  1698.                             // Sequence and All
  1699.                             foreach (XmlSchemaParticle p in group.Items) {
  1700.                                 card += AddChildParticle(list, p, filter);
  1701.                             }
  1702.                         }
  1703.                     }
  1704.                 }
  1705.             }
  1706.             return card * CardinalityOfParticle(particle);
  1707.         }
  1708.        
  1709.         /// <summary>
  1710.         /// Apply filter an item type, add the result to a list, return cardinality
  1711.         /// </summary>
  1712.         private XmlQueryCardinality AddFilteredPrime(List<XmlQueryType> list, XmlQueryType source, XmlQueryType filter)
  1713.         {
  1714.             return AddFilteredPrime(list, source, filter, false);
  1715.            
  1716.         }
  1717.         private XmlQueryCardinality AddFilteredPrime(List<XmlQueryType> list, XmlQueryType source, XmlQueryType filter, bool forseSingle)
  1718.         {
  1719.             Debug.Assert(source.IsNode && source.IsSingleton);
  1720.             Debug.Assert(filter.IsNode && filter.IsSingleton);
  1721.            
  1722.             // Intersect types
  1723.             XmlQueryType intersection = IntersectItemTypes(source, filter);
  1724.             if ((object)intersection == (object)None) {
  1725.                 return XmlQueryCardinality.Zero;
  1726.             }
  1727.             AddItemToChoice(list, intersection);
  1728.             // In the case of forseSingle - filtering all nodes behave as singletones
  1729.             XmlTypeCode typeCode = (forseSingle ? XmlTypeCode.Node : intersection.TypeCode);
  1730.             switch (typeCode) {
  1731.                 case XmlTypeCode.Node:
  1732.                 case XmlTypeCode.Document:
  1733.                 case XmlTypeCode.Element:
  1734.                     // Filter can result in empty sequence if filter is not wider then source
  1735.                     if (intersection == source)
  1736.                         return XmlQueryCardinality.One;
  1737.                     else
  1738.                         return XmlQueryCardinality.ZeroOrOne;
  1739.                     break;
  1740.                 case XmlTypeCode.Attribute:
  1741.                    
  1742.                     // wildcard attribute matches more then one node
  1743.                     if (!intersection.NameTest.IsSingleName)
  1744.                         return XmlQueryCardinality.ZeroOrMore;
  1745.                     else if (intersection == source)
  1746.                         return XmlQueryCardinality.One;
  1747.                     else
  1748.                         return XmlQueryCardinality.ZeroOrOne;
  1749.                     break;
  1750.                 case XmlTypeCode.Comment:
  1751.                 case XmlTypeCode.Text:
  1752.                 case XmlTypeCode.ProcessingInstruction:
  1753.                 case XmlTypeCode.Namespace:
  1754.                     return XmlQueryCardinality.ZeroOrMore;
  1755.                 default:
  1756.                    
  1757.                     Debug.Assert(false);
  1758.                     return XmlQueryCardinality.None;
  1759.             }
  1760.         }
  1761.        
  1762.         /// <summary>
  1763.         /// Construct the intersection of two lists of prime XmlQueryTypes.
  1764.         /// </summary>
  1765.         private XmlQueryType IntersectItemTypes(XmlQueryType left, XmlQueryType right)
  1766.         {
  1767.             Debug.Assert(left.Count == 1 && left.IsSingleton, "left should be an item");
  1768.             Debug.Assert(right.Count == 1 && right.IsSingleton, "right should be an item");
  1769.             if (left.TypeCode == right.TypeCode && (left.NodeKinds & (XmlNodeKindFlags.Document | XmlNodeKindFlags.Element | XmlNodeKindFlags.Attribute)) != 0) {
  1770.                 if (left.TypeCode == XmlTypeCode.Node) {
  1771.                     return left;
  1772.                 }
  1773.                 // Intersect name tests
  1774.                 XmlQualifiedNameTest nameTest = left.NameTest.Intersect(right.NameTest);
  1775.                
  1776.                 // Intersect types
  1777.                     /* exept:*/                    /* exept:*/                XmlSchemaType type = XmlSchemaType.IsDerivedFrom(left.SchemaType, right.SchemaType, XmlSchemaDerivationMethod.Empty) ? left.SchemaType : XmlSchemaType.IsDerivedFrom(right.SchemaType, left.SchemaType, XmlSchemaDerivationMethod.Empty) ? right.SchemaType : null;
  1778.                 bool isNillable = left.IsNillable && right.IsNillable;
  1779.                
  1780.                 if ((object)nameTest == (object)left.NameTest && type == left.SchemaType && isNillable == left.IsNillable) {
  1781.                     // left is a subtype of right return left
  1782.                     return left;
  1783.                 }
  1784.                 else if ((object)nameTest == (object)right.NameTest && type == right.SchemaType && isNillable == right.IsNillable) {
  1785.                     // right is a subtype of left return right
  1786.                     return right;
  1787.                 }
  1788.                 else if (nameTest != null && type != null) {
  1789.                     // create a new type
  1790.                     return ItemType.Create(left.TypeCode, nameTest, type, isNillable);
  1791.                 }
  1792.             }
  1793.             else if (left.IsSubtypeOf(right)) {
  1794.                 // left is a subset of right, so left is in the intersection
  1795.                 return left;
  1796.             }
  1797.             else if (right.IsSubtypeOf(left)) {
  1798.                 // right is a subset of left, so right is in the intersection
  1799.                 return right;
  1800.             }
  1801.             return None;
  1802.         }
  1803.        
  1804.         /// <summary>
  1805.         /// Convert particle occurrance range into cardinality
  1806.         /// </summary>
  1807.         private XmlQueryCardinality CardinalityOfParticle(XmlSchemaParticle particle)
  1808.         {
  1809.             if (particle.MinOccurs == decimal.Zero) {
  1810.                 if (particle.MaxOccurs == decimal.Zero) {
  1811.                     return XmlQueryCardinality.Zero;
  1812.                 }
  1813.                 else if (particle.MaxOccurs == decimal.One) {
  1814.                     return XmlQueryCardinality.ZeroOrOne;
  1815.                 }
  1816.                 else {
  1817.                     return XmlQueryCardinality.ZeroOrMore;
  1818.                 }
  1819.             }
  1820.             else {
  1821.                 if (particle.MaxOccurs == decimal.One) {
  1822.                     return XmlQueryCardinality.One;
  1823.                 }
  1824.                 else {
  1825.                     return XmlQueryCardinality.OneOrMore;
  1826.                 }
  1827.             }
  1828.         }
  1829.         #endif
  1830.     }
  1831. }

Developer Fusion