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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="XmlQueryType.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.Schema;
  18. using System.Collections.Generic;
  19. using System.Diagnostics;
  20. using System.Text;
  21. namespace System.Xml.Xsl
  22. {
  23.    
  24.     /// <summary>
  25.     /// XmlQueryType contains static type information that describes the structure and possible values of dynamic
  26.     /// instances of the Xml data model.
  27.     ///
  28.     /// Every XmlQueryType is composed of a Prime type and a cardinality. The Prime type itself may be a union
  29.     /// between several item types. The XmlQueryType IList<XmlQueryType/> implementation allows callers
  30.     /// to enumerate the item types. Other properties expose other information about the type.
  31.     /// </summary>
  32.     internal abstract class XmlQueryType : ListBase<XmlQueryType>
  33.     {
  34.         private static readonly BitMatrix TypeCodeDerivation;
  35.         private int hashCode;
  36.        
  37.        
  38.         //-----------------------------------------------
  39.         // Static Constructor
  40.         //-----------------------------------------------
  41.         static XmlQueryType()
  42.         {
  43.             TypeCodeDerivation = new BitMatrix(BaseTypeCodes.Length);
  44.            
  45.             // Build derivation matrix
  46.             for (int i = 0; i < BaseTypeCodes.Length; i++) {
  47.                 int nextAncestor = i;
  48.                
  49.                 while (true) {
  50.                     TypeCodeDerivation[i, nextAncestor] = true;
  51.                     if ((int)BaseTypeCodes[nextAncestor] == nextAncestor)
  52.                         break;
  53.                    
  54.                     nextAncestor = (int)BaseTypeCodes[nextAncestor];
  55.                 }
  56.             }
  57.         }
  58.        
  59.        
  60.         //-----------------------------------------------
  61.         // ItemType, OccurrenceIndicator Properties
  62.         //-----------------------------------------------
  63.        
  64.         /// <summary>
  65.         /// Static data type code. The dynamic type is guaranteed to be this type or a subtype of this code.
  66.         /// This type code includes support for XQuery types that are not part of Xsd, such as Item,
  67.         /// Node, AnyAtomicType, and Comment.
  68.         /// </summary>
  69.         public abstract XmlTypeCode TypeCode {
  70.             get;
  71.         }
  72.        
  73.         /// <summary>
  74.         /// Set of alowed names for element, document{element}, attribute and PI
  75.         /// Returns XmlQualifiedName.Wildcard for all other types
  76.         /// </summary>
  77.         public abstract XmlQualifiedNameTest NameTest {
  78.             get;
  79.         }
  80.        
  81.         /// <summary>
  82.         /// Static Xsd schema type. The dynamic type is guaranteed to be this type or a subtype of this type.
  83.         /// SchemaType will follow these rules:
  84.         /// 1. If TypeCode is an atomic type code, then SchemaType will be the corresponding non-null simple type
  85.         /// 2. If TypeCode is Element or Attribute, then SchemaType will be the non-null content type
  86.         /// 3. If TypeCode is Item, Node, Comment, PI, Text, Document, Namespacce, None, then SchemaType will be AnyType
  87.         /// </summary>
  88.         public abstract XmlSchemaType SchemaType {
  89.             get;
  90.         }
  91.        
  92.         /// <summary>
  93.         /// Permits the element or document{element} node to have the nilled property.
  94.         /// Returns false for all other types
  95.         /// </summary>
  96.         public abstract bool IsNillable {
  97.             get;
  98.         }
  99.        
  100.         /// <summary>
  101.         /// This property is always XmlNodeKindFlags.None unless TypeCode = XmlTypeCode.Node, in which case this
  102.         /// property lists all node kinds that instances of this type may be.
  103.         /// </summary>
  104.         public abstract XmlNodeKindFlags NodeKinds {
  105.             get;
  106.         }
  107.        
  108.         /// <summary>
  109.         /// If IsStrict is true, then the dynamic type is guaranteed to be the exact same as the static type, and
  110.         /// will therefore never be a subtype of the static type.
  111.         /// </summary>
  112.         public abstract bool IsStrict {
  113.             get;
  114.         }
  115.        
  116.         /// <summary>
  117.         /// This property specifies the possible cardinalities that instances of this type may have.
  118.         /// </summary>
  119.         public abstract XmlQueryCardinality Cardinality {
  120.             get;
  121.         }
  122.        
  123.         /// <summary>
  124.         /// This property returns this type's Prime type, which is always cardinality One.
  125.         /// </summary>
  126.         public abstract XmlQueryType Prime {
  127.             get;
  128.         }
  129.        
  130.         /// <summary>
  131.         /// True if dynamic data type of all items in this sequence is guaranteed to be not a subtype of Rtf.
  132.         /// </summary>
  133.         public abstract bool IsNotRtf {
  134.             get;
  135.         }
  136.        
  137.         /// <summary>
  138.         /// True if items in the sequence are guaranteed to be in document order, with no duplicates.
  139.         /// </summary>
  140.         public abstract bool IsDod {
  141.             get;
  142.         }
  143.        
  144.         /// <summary>
  145.         /// The XmlValueConverter maps each XmlQueryType to various Clr types which are capable of representing it.
  146.         /// </summary>
  147.         public abstract XmlValueConverter ClrMapping {
  148.             get;
  149.         }
  150.        
  151.        
  152.         //-----------------------------------------------
  153.         // Type Operations
  154.         //-----------------------------------------------
  155.        
  156.         /// <summary>
  157.         /// Returns true if every possible dynamic instance of this type is also an instance of "baseType".
  158.         /// </summary>
  159.         public bool IsSubtypeOf(XmlQueryType baseType)
  160.         {
  161.             XmlQueryType thisPrime;
  162.             XmlQueryType basePrime;
  163.            
  164.             // Check cardinality sub-typing rules
  165.             if (!(Cardinality <= baseType.Cardinality))
  166.                 return false;
  167.            
  168.             // Check early for common case that two types are the same object
  169.             thisPrime = Prime;
  170.             basePrime = baseType.Prime;
  171.             if ((object)thisPrime == (object)basePrime)
  172.                 return true;
  173.            
  174.             // Check early for common case that two prime types are item types
  175.             if (thisPrime.Count == 1 && basePrime.Count == 1)
  176.                 return thisPrime.IsSubtypeOfItemType(basePrime);
  177.            
  178.             // Check that each item type in this type is a subtype of some item type in "baseType"
  179.             foreach (XmlQueryType thisItem in thisPrime) {
  180.                 bool match = false;
  181.                
  182.                 foreach (XmlQueryType baseItem in basePrime) {
  183.                     if (thisItem.IsSubtypeOfItemType(baseItem)) {
  184.                         match = true;
  185.                         break;
  186.                     }
  187.                 }
  188.                
  189.                 if (match == false)
  190.                     return false;
  191.             }
  192.            
  193.             return true;
  194.         }
  195.        
  196.         /// <summary>
  197.         /// Returns true if a dynamic instance (type None never has an instance) of this type can never be a subtype of "baseType".
  198.         /// </summary>
  199.         public bool NeverSubtypeOf(XmlQueryType baseType)
  200.         {
  201.             // Check cardinalities
  202.             if (Cardinality.NeverSubset(baseType.Cardinality))
  203.                 return true;
  204.            
  205.             // If both this type and "other" type might be empty, it doesn't matter what the prime types are
  206.             if (MaybeEmpty && baseType.MaybeEmpty)
  207.                 return false;
  208.            
  209.             // None is subtype of every other type
  210.             if (Count == 0)
  211.                 return false;
  212.            
  213.             // Check item types
  214.             foreach (XmlQueryType typThis in this) {
  215.                 foreach (XmlQueryType typThat in baseType) {
  216.                     if (typThis.HasIntersectionItemType(typThat))
  217.                         return false;
  218.                 }
  219.             }
  220.            
  221.             return true;
  222.         }
  223.        
  224.         /// <summary>
  225.         /// Strongly-typed Equals that returns true if this type and "that" type are equivalent.
  226.         /// </summary>
  227.         public bool Equals(XmlQueryType that)
  228.         {
  229.             if (that == null)
  230.                 return false;
  231.            
  232.             // Check cardinality
  233.             if (Cardinality != that.Cardinality)
  234.                 return false;
  235.            
  236.             // Check early for common case that two types are the same object
  237.             XmlQueryType thisPrime = Prime;
  238.             XmlQueryType thatPrime = that.Prime;
  239.             if ((object)thisPrime == (object)thatPrime)
  240.                 return true;
  241.            
  242.             // Check that count of item types is equal
  243.             if (thisPrime.Count != thatPrime.Count)
  244.                 return false;
  245.            
  246.             // Check early for common case that two prime types are item types
  247.             if (thisPrime.Count == 1) {
  248.                 return (thisPrime.TypeCode == thatPrime.TypeCode && thisPrime.NameTest == thatPrime.NameTest && thisPrime.SchemaType == thatPrime.SchemaType && thisPrime.IsStrict == thatPrime.IsStrict && thisPrime.IsNotRtf == thatPrime.IsNotRtf);
  249.             }
  250.            
  251.            
  252.             // Check that each item type in this type is equal to some item type in "baseType"
  253.             // (string | int) should be the same type as (int | string)
  254.             foreach (XmlQueryType thisItem in this) {
  255.                 bool match = false;
  256.                
  257.                 foreach (XmlQueryType thatItem in that) {
  258.                     if (thisItem.TypeCode == thatItem.TypeCode && thisItem.NameTest == thatItem.NameTest && thisItem.SchemaType == thatItem.SchemaType && thisItem.IsStrict == thatItem.IsStrict && thisItem.IsNotRtf == thatItem.IsNotRtf) {
  259.                         // Found match so proceed to next type
  260.                         match = true;
  261.                         break;
  262.                     }
  263.                 }
  264.                
  265.                 if (match == false)
  266.                     return false;
  267.             }
  268.            
  269.             return true;
  270.         }
  271.        
  272.         /// <summary>
  273.         /// Overload == operator to call Equals rather than do reference equality.
  274.         /// </summary>
  275.         public static bool operator ==(XmlQueryType left, XmlQueryType right)
  276.         {
  277.             if ((object)left == null)
  278.                 return ((object)right == null);
  279.            
  280.             return left.Equals(right);
  281.         }
  282.        
  283.         /// <summary>
  284.         /// Overload != operator to call Equals rather than do reference inequality.
  285.         /// </summary>
  286.         public static bool operator !=(XmlQueryType left, XmlQueryType right)
  287.         {
  288.             if ((object)left == null)
  289.                 return ((object)right != null);
  290.            
  291.             return !left.Equals(right);
  292.         }
  293.        
  294.        
  295.         //-----------------------------------------------
  296.         // Convenience Properties
  297.         //-----------------------------------------------
  298.        
  299.         /// <summary>
  300.         /// True if dynamic cardinality of this sequence is guaranteed to be 0.
  301.         /// </summary>
  302.         public bool IsEmpty {
  303.             get { return Cardinality <= XmlQueryCardinality.Zero; }
  304.         }
  305.        
  306.         /// <summary>
  307.         /// True if dynamic cardinality of this sequence is guaranteed to be 1.
  308.         /// </summary>
  309.         public bool IsSingleton {
  310.             get { return Cardinality <= XmlQueryCardinality.One; }
  311.         }
  312.        
  313.         /// <summary>
  314.         /// True if dynamic cardinality of this sequence might be 0.
  315.         /// </summary>
  316.         public bool MaybeEmpty {
  317.             get { return XmlQueryCardinality.Zero <= Cardinality; }
  318.         }
  319.        
  320.         /// <summary>
  321.         /// True if dynamic cardinality of this sequence might be >1.
  322.         /// </summary>
  323.         public bool MaybeMany {
  324.             get { return XmlQueryCardinality.More <= Cardinality; }
  325.         }
  326.        
  327.         /// <summary>
  328.         /// True if dynamic data type of all items in this sequence is guaranteed to be a subtype of Node.
  329.         /// Equivalent to calling IsSubtypeOf(TypeFactory.NodeS).
  330.         /// </summary>
  331.         public bool IsNode {
  332.             get { return (TypeCodeToFlags[(int)TypeCode] & TypeFlags.IsNode) != 0; }
  333.         }
  334.        
  335.         /// <summary>
  336.         /// True if dynamic data type of all items in this sequence is guaranteed to be a subtype of AnyAtomicType.
  337.         /// Equivalent to calling IsSubtypeOf(TypeFactory.AnyAtomicTypeS).
  338.         /// </summary>
  339.         public bool IsAtomicValue {
  340.             get { return (TypeCodeToFlags[(int)TypeCode] & TypeFlags.IsAtomicValue) != 0; }
  341.         }
  342.        
  343.         /// <summary>
  344.         /// True if dynamic data type of all items in this sequence is guaranteed to be a subtype of Decimal, Double, or Float.
  345.         /// Equivalent to calling IsSubtypeOf(TypeFactory.NumericS).
  346.         /// </summary>
  347.         public bool IsNumeric {
  348.             get { return (TypeCodeToFlags[(int)TypeCode] & TypeFlags.IsNumeric) != 0; }
  349.         }
  350.        
  351.        
  352.         //-----------------------------------------------
  353.         // System.Object implementation
  354.         //-----------------------------------------------
  355.        
  356.         /// <summary>
  357.         /// True if "obj" is an XmlQueryType, and this type is the exact same static type.
  358.         /// </summary>
  359.         public override bool Equals(object obj)
  360.         {
  361.             XmlQueryType that = obj as XmlQueryType;
  362.            
  363.             if (that == null)
  364.                 return false;
  365.            
  366.             return Equals(that);
  367.         }
  368.        
  369.         /// <summary>
  370.         /// Return hash code of this instance.
  371.         /// </summary>
  372.         public override int GetHashCode()
  373.         {
  374.             if (this.hashCode == 0) {
  375.                 int hash;
  376.                 XmlSchemaType schemaType;
  377.                
  378.                 hash = (int)TypeCode;
  379.                
  380.                 schemaType = SchemaType;
  381.                 if (schemaType != null)
  382.                     hash += (hash << 7) ^ schemaType.GetHashCode();
  383.                
  384.                 hash += (hash << 7) ^ (int)NodeKinds;
  385.                 hash += (hash << 7) ^ Cardinality.GetHashCode();
  386.                 hash += (hash << 7) ^ (IsStrict ? 1 : 0);
  387.                
  388.                 // Mix hash code a bit more
  389.                 hash -= hash >> 17;
  390.                 hash -= hash >> 11;
  391.                 hash -= hash >> 5;
  392.                
  393.                 // Save hashcode. Don't save 0, so that it won't ever be recomputed.
  394.                 this.hashCode = (hash == 0) ? 1 : hash;
  395.             }
  396.            
  397.             return this.hashCode;
  398.         }
  399.        
  400.         /// <summary>
  401.         /// Return a user-friendly string representation of the XmlQueryType.
  402.         /// </summary>
  403.         public override string ToString()
  404.         {
  405.             return ToString("G");
  406.         }
  407.        
  408.         /// <summary>
  409.         /// Return a string representation of the XmlQueryType using the specified format. The following formats are
  410.         /// supported:
  411.         ///
  412.         /// "G" (General): This is the default mode, and is used if no other format is recognized. This format is
  413.         /// easier to read than the canonical format, since it excludes redundant information.
  414.         /// (e.g. element instead of element(*, xs:anyType))
  415.         ///
  416.         /// "X" (XQuery): Return the canonical XQuery representation, which excludes Qil specific information and
  417.         /// includes extra, redundant information, such as fully specified types.
  418.         /// (e.g. element(*, xs:anyType) instead of element)
  419.         ///
  420.         /// "S" (Serialized): This format is used to serialize parts of the type which can be serialized easily, in
  421.         /// a format that is easy to parse. Only the cardinality, type code, and strictness flag
  422.         /// are serialized. User-defined type information and element/attribute content types
  423.         /// are lost.
  424.         /// (e.g. One;Attribute|String|Int;true)
  425.         ///
  426.         /// </summary>
  427.         public string ToString(string format)
  428.         {
  429.             string[] sa;
  430.             StringBuilder sb;
  431.             bool isXQ;
  432.            
  433.             if (format == "S") {
  434.                 sb = new StringBuilder();
  435.                 sb.Append(Cardinality.ToString(format));
  436.                 sb.Append(';');
  437.                
  438.                 for (int i = 0; i < Count; i++) {
  439.                     if (i != 0)
  440.                         sb.Append("|");
  441.                     sb.Append(this[i].TypeCode.ToString());
  442.                 }
  443.                
  444.                 sb.Append(';');
  445.                 sb.Append(IsStrict);
  446.                 return sb.ToString();
  447.             }
  448.            
  449.             isXQ = (format == "X");
  450.            
  451.             if (Cardinality == XmlQueryCardinality.None) {
  452.                 return "none";
  453.             }
  454.             else if (Cardinality == XmlQueryCardinality.Zero) {
  455.                 return "empty";
  456.             }
  457.            
  458.             switch (Count) {
  459.                 case 0:
  460.                     // This assert depends on the way we are going to represent None
  461.                     // Debug.Assert(false);
  462.                     return "none" + Cardinality.ToString();
  463.                 case 1:
  464.                     return this[0].ItemTypeToString(isXQ) + Cardinality.ToString();
  465.             }
  466.            
  467.             sa = new string[Count];
  468.             for (int i = 0; i < Count; i++)
  469.                 sa[i] = this[i].ItemTypeToString(isXQ);
  470.            
  471.             Array.Sort(sa);
  472.            
  473.             sb = new StringBuilder();
  474.             sb.Append("(");
  475.             sb.Append(sa[0]);
  476.             for (int i = 1; i < sa.Length; i++) {
  477.                 sb.Append(" | ");
  478.                 sb.Append(sa[i]);
  479.             }
  480.            
  481.             sb.Append(")");
  482.             sb.Append(Cardinality.ToString());
  483.             return sb.ToString();
  484.         }
  485.        
  486.        
  487.         //-----------------------------------------------
  488.         // Helpers
  489.         //-----------------------------------------------
  490.        
  491.         /// <summary>
  492.         /// Returns true if this item type is a subtype of another item type.
  493.         /// </summary>
  494.         private bool IsSubtypeOfItemType(XmlQueryType baseType)
  495.         {
  496.             Debug.Assert(Count == 1 && IsSingleton, "This method should only be called for item types.");
  497.             Debug.Assert(baseType.Count == 1 && baseType.IsSingleton, "This method should only be called for item types.");
  498.             XmlSchemaType baseSchemaType = baseType.SchemaType;
  499.            
  500.             if (TypeCode != baseType.TypeCode) {
  501.                 // If "baseType" is strict, then IsSubtypeOf must be false
  502.                 if (baseType.IsStrict)
  503.                     return false;
  504.                
  505.                 // If type codes are not the same, then IsSubtypeOf can return true *only* if "baseType" is a built-in type
  506.                 XmlSchemaType builtInType = XmlSchemaType.GetBuiltInSimpleType(baseType.TypeCode);
  507.                 if (builtInType != null && baseSchemaType != builtInType)
  508.                     return false;
  509.                
  510.                 // Now check whether TypeCode is derived from baseType.TypeCode
  511.                 return TypeCodeDerivation[TypeCode, baseType.TypeCode];
  512.             }
  513.             else if (baseType.IsStrict) {
  514.                 // only atomic values can be strict
  515.                 Debug.Assert(IsAtomicValue && baseType.IsAtomicValue);
  516.                
  517.                 // If schema types are not the same, then IsSubtype is false if "baseType" is strict
  518.                 return IsStrict && SchemaType == baseSchemaType;
  519.             }
  520.             else {
  521.                 // Otherwise, check derivation tree
  522.                     /* exept:*/                return (IsNotRtf || !baseType.IsNotRtf) && (IsDod || !baseType.IsDod) && NameTest.IsSubsetOf(baseType.NameTest) && (baseSchemaType == XmlSchemaComplexType.AnyType || XmlSchemaType.IsDerivedFrom(SchemaType, baseSchemaType, XmlSchemaDerivationMethod.Empty)) && (!IsNillable || baseType.IsNillable);
  523.             }
  524.         }
  525.        
  526.         /// <summary>
  527.         /// Returns true if the intersection between this item type and "other" item type is not empty.
  528.         /// </summary>
  529.         private bool HasIntersectionItemType(XmlQueryType other)
  530.         {
  531.             Debug.Assert(this.Count == 1 && this.IsSingleton, "this should be an item");
  532.             Debug.Assert(other.Count == 1 && other.IsSingleton, "other should be an item");
  533.            
  534.             if (this.TypeCode == other.TypeCode && (this.NodeKinds & (XmlNodeKindFlags.Document | XmlNodeKindFlags.Element | XmlNodeKindFlags.Attribute)) != 0) {
  535.                 if (this.TypeCode == XmlTypeCode.Node)
  536.                     return true;
  537.                
  538.                 // Intersect name tests
  539.                 if (!this.NameTest.HasIntersection(other.NameTest))
  540.                     return false;
  541.                
  542.                 if (!XmlSchemaType.IsDerivedFrom(this.SchemaType, other.SchemaType, XmlSchemaDerivationMethod.Empty) && !XmlSchemaType.IsDerivedFrom(other.SchemaType, this.SchemaType, XmlSchemaDerivationMethod.Empty))/* exept:*//* exept:*/ {
  543.                     return false;
  544.                 }
  545.                
  546.                 return true;
  547.             }
  548.             else if (this.IsSubtypeOf(other) || other.IsSubtypeOf(this)) {
  549.                 return true;
  550.             }
  551.            
  552.             return false;
  553.         }
  554.        
  555.         /// <summary>
  556.         /// Return the string representation of an item type (cannot be a union or a sequence).
  557.         /// </summary>
  558.         private string ItemTypeToString(bool isXQ)
  559.         {
  560.             string s;
  561.             Debug.Assert(Count == 1, "Do not pass a Union type to this method.");
  562.             Debug.Assert(IsSingleton, "Do not pass a Sequence type to this method.");
  563.            
  564.             if (IsNode) {
  565.                 // Map TypeCode to string
  566.                 s = TypeNames[(int)TypeCode];
  567.                
  568.                 switch (TypeCode) {
  569.                     case XmlTypeCode.Document:
  570.                         if (!isXQ)
  571.                             goto case XmlTypeCode.Element;
  572.                        
  573.                         s += "{(element" + NameAndType(true) + "?&text?&comment?&processing-instruction?)*}";
  574.                         break;
  575.                     case XmlTypeCode.Element:
  576.                     case XmlTypeCode.Attribute:
  577.                        
  578.                         s += NameAndType(isXQ);
  579.                         break;
  580.                 }
  581.             }
  582.             else if (SchemaType != XmlSchemaComplexType.AnyType) {
  583.                 // Get QualifiedName from SchemaType
  584.                 if (SchemaType.QualifiedName.IsEmpty)
  585.                     s = "<:" + TypeNames[(int)TypeCode];
  586.                 else
  587.                     s = QNameToString(SchemaType.QualifiedName);
  588.             }
  589.             else {
  590.                 // Map TypeCode to string
  591.                 s = TypeNames[(int)TypeCode];
  592.             }
  593.            
  594.             if (!isXQ && IsStrict)
  595.                 s += "=";
  596.            
  597.             return s;
  598.         }
  599.        
  600.         /// <summary>
  601.         /// Return "(name-test, type-name)" for this type. If isXQ is false, normalize xs:anySimpleType and
  602.         /// xs:anyType to "*".
  603.         /// </summary>
  604.         private string NameAndType(bool isXQ)
  605.         {
  606.             string nodeName = NameTest.ToString();
  607.             string typeName = "*";
  608.            
  609.             if (SchemaType.QualifiedName.IsEmpty) {
  610.                 typeName = "typeof(" + nodeName + ")";
  611.             }
  612.             else {
  613.                 if (isXQ || (SchemaType != XmlSchemaComplexType.AnyType && SchemaType != DatatypeImplementation.AnySimpleType))
  614.                     typeName = QNameToString(SchemaType.QualifiedName);
  615.             }
  616.            
  617.             if (IsNillable) {
  618.                 typeName += " nillable";
  619.             }
  620.            
  621.             // Normalize "(*, *)" to ""
  622.             if (nodeName == "*" && typeName == "*")
  623.                 return "";
  624.            
  625.             return "(" + nodeName + ", " + typeName + ")";
  626.         }
  627.        
  628.         /// <summary>
  629.         /// Convert an XmlQualifiedName to a string, using somewhat different rules than XmlQualifiedName.ToString():
  630.         /// 1. Empty QNames are assumed to be wildcard names, so return "*"
  631.         /// 2. Recognize the built-in xs: and xdt: namespaces and print the short prefix rather than the long namespace
  632.         /// 3. Use brace characters "{", "}" around the namespace portion of the QName
  633.         /// </summary>
  634.         private static string QNameToString(XmlQualifiedName name)
  635.         {
  636.             if (name.IsEmpty) {
  637.                 return "*";
  638.             }
  639.             else if (name.Namespace.Length == 0) {
  640.                 return name.Name;
  641.             }
  642.             else if (name.Namespace == XmlReservedNs.NsXs) {
  643.                 return "xs:" + name.Name;
  644.             }
  645.             else if (name.Namespace == XmlReservedNs.NsXQueryDataType) {
  646.                 return "xdt:" + name.Name;
  647.             }
  648.             else {
  649.                 return "{" + name.Namespace + "}" + name.Name;
  650.             }
  651.         }
  652.        
  653.         #region TypeFlags
  654.         private enum TypeFlags
  655.         {
  656.             None = 0,
  657.             IsNode = 1,
  658.             IsAtomicValue = 2,
  659.             IsNumeric = 4
  660.         }
  661.         #endregion
  662.        
  663.         #region TypeCodeToFlags
  664.         private static readonly TypeFlags[] TypeCodeToFlags = {TypeFlags.IsNode | TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.None, TypeFlags.IsNode, TypeFlags.IsNode, TypeFlags.IsNode, TypeFlags.IsNode, TypeFlags.IsNode, TypeFlags.IsNode, TypeFlags.IsNode, TypeFlags.IsNode,
  665.         TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue,
  666.         TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue,
  667.         TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue,
  668.         TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric,
  669.             /* XmlTypeCode.None                  */            /* XmlTypeCode.Item                  */            /* XmlTypeCode.Node                  */            /* XmlTypeCode.Document              */            /* XmlTypeCode.Element              */            /* XmlTypeCode.Attribute            */            /* XmlTypeCode.Namespace            */            /* XmlTypeCode.ProcessingInstruction */            /* XmlTypeCode.Comment              */            /* XmlTypeCode.Text                  */            /* XmlTypeCode.AnyAtomicType        */            /* XmlTypeCode.UntypedAtomic        */            /* XmlTypeCode.String                */            /* XmlTypeCode.Boolean              */            /* XmlTypeCode.Decimal              */            /* XmlTypeCode.Float                */            /* XmlTypeCode.Double                */            /* XmlTypeCode.Duration              */            /* XmlTypeCode.DateTime              */            /* XmlTypeCode.Time                  */            /* XmlTypeCode.Date                  */            /* XmlTypeCode.GYearMonth            */            /* XmlTypeCode.GYear                */            /* XmlTypeCode.GMonthDay            */            /* XmlTypeCode.GDay                  */            /* XmlTypeCode.GMonth                */            /* XmlTypeCode.HexBinary            */            /* XmlTypeCode.Base64Binary          */            /* XmlTypeCode.AnyUri                */            /* XmlTypeCode.QName                */            /* XmlTypeCode.Notation              */            /* XmlTypeCode.NormalizedString      */            /* XmlTypeCode.Token                */            /* XmlTypeCode.Language              */            /* XmlTypeCode.NmToken              */            /* XmlTypeCode.Name                  */            /* XmlTypeCode.NCName                */            /* XmlTypeCode.Id                    */            /* XmlTypeCode.Idref                */            /* XmlTypeCode.Entity                */            /* XmlTypeCode.Integer              */            /* XmlTypeCode.NonPositiveInteger    */            /* XmlTypeCode.NegativeInteger      */            /* XmlTypeCode.Long                  */            /* XmlTypeCode.Int                  */            /* XmlTypeCode.Short                */            /* XmlTypeCode.Byte                  */            /* XmlTypeCode.NonNegativeInteger    */            /* XmlTypeCode.UnsignedLong          */            /* XmlTypeCode.UnsignedInt          */            /* XmlTypeCode.UnsignedShort        */            /* XmlTypeCode.UnsignedByte          */            /* XmlTypeCode.PositiveInteger      */            /* XmlTypeCode.YearMonthDuration    */            /* XmlTypeCode.DayTimeDuration      */        TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue | TypeFlags.IsNumeric, TypeFlags.IsAtomicValue, TypeFlags.IsAtomicValue};
  670.        
  671.         private static readonly XmlTypeCode[] BaseTypeCodes = {XmlTypeCode.None, XmlTypeCode.Item, XmlTypeCode.Item, XmlTypeCode.Node, XmlTypeCode.Node, XmlTypeCode.Node, XmlTypeCode.Node, XmlTypeCode.Node, XmlTypeCode.Node, XmlTypeCode.Node,
  672.         XmlTypeCode.Item, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType,
  673.         XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType, XmlTypeCode.AnyAtomicType,
  674.         XmlTypeCode.AnyAtomicType, XmlTypeCode.String, XmlTypeCode.NormalizedString, XmlTypeCode.Token, XmlTypeCode.Token, XmlTypeCode.Token, XmlTypeCode.Name, XmlTypeCode.NCName, XmlTypeCode.NCName, XmlTypeCode.NCName,
  675.         XmlTypeCode.Decimal, XmlTypeCode.Integer, XmlTypeCode.NonPositiveInteger, XmlTypeCode.Integer, XmlTypeCode.Long, XmlTypeCode.Int, XmlTypeCode.Short, XmlTypeCode.Integer, XmlTypeCode.NonNegativeInteger, XmlTypeCode.UnsignedLong,
  676.             /* None                        */            /* Item                        */            /* Node                        */            /* Document                    */            /* Element                    */            /* Attribute                  */            /* Namespace                  */            /* ProcessingInstruction      */            /* Comment                    */            /* Text                        */            /* AnyAtomicType              */            /* UntypedAtomic              */            /* String                      */            /* Boolean                    */            /* Decimal                    */            /* Float                      */            /* Double                      */            /* Duration                    */            /* DateTime                    */            /* Time                        */            /* Date                        */            /* GYearMonth                  */            /* GYear                      */            /* GMonthDay                  */            /* GDay                        */            /* GMonth                      */            /* HexBinary                  */            /* Base64Binary                */            /* AnyUri                      */            /* QName                      */            /* Notation                    */            /* NormalizedString            */            /* Token                      */            /* Language                    */            /* NmToken                    */            /* Name                        */            /* NCName                      */            /* Id                          */            /* Idref                      */            /* Entity                      */            /* Integer                    */            /* NonPositiveInteger          */            /* NegativeInteger            */            /* Long                        */            /* Int                        */            /* Short                      */            /* Byte                        */            /* NonNegativeInteger          */            /* UnsignedLong                */            /* UnsignedInt                */            /* UnsignedShort              */            /* UnsignedByte                */            /* PositiveInteger            */            /* YearMonthDuration          */            /* DayTimeDuration            */        XmlTypeCode.UnsignedInt, XmlTypeCode.UnsignedShort, XmlTypeCode.NonNegativeInteger, XmlTypeCode.Duration, XmlTypeCode.Duration};
  677.        
  678.         private static readonly string[] TypeNames = {"none", "item", "node", "document", "element", "attribute", "namespace", "processing-instruction", "comment", "text",
  679.         "xdt:anyAtomicType", "xdt:untypedAtomic", "xs:string", "xs:boolean", "xs:decimal", "xs:float", "xs:double", "xs:duration", "xs:dateTime", "xs:time",
  680.         "xs:date", "xs:gYearMonth", "xs:gYear", "xs:gMonthDay", "xs:gDay", "xs:gMonth", "xs:hexBinary", "xs:base64Binary", "xs:anyUri", "xs:QName",
  681.         "xs:NOTATION", "xs:normalizedString", "xs:token", "xs:language", "xs:NMTOKEN", "xs:Name", "xs:NCName", "xs:ID", "xs:IDREF", "xs:ENTITY",
  682.         "xs:integer", "xs:nonPositiveInteger", "xs:negativeInteger", "xs:long", "xs:int", "xs:short", "xs:byte", "xs:nonNegativeInteger", "xs:unsignedLong", "xs:unsignedInt",
  683.             /* None                        */            /* Item                        */            /* Node                        */            /* Document                    */            /* Element                    */            /* Attribute                  */            /* Namespace                  */            /* ProcessingInstruction      */            /* Comment                    */            /* Text                        */            /* AnyAtomicType              */            /* UntypedAtomic              */            /* String                      */            /* Boolean                    */            /* Decimal                    */            /* Float                      */            /* Double                      */            /* Duration                    */            /* DateTime                    */            /* Time                        */            /* Date                        */            /* GYearMonth                  */            /* GYear                      */            /* GMonthDay                  */            /* GDay                        */            /* GMonth                      */            /* HexBinary                  */            /* Base64Binary                */            /* AnyUri                      */            /* QName                      */            /* Notation                    */            /* NormalizedString            */            /* Token                      */            /* Language                    */            /* NmToken                    */            /* Name                        */            /* NCName                      */            /* Id                          */            /* Idref                      */            /* Entity                      */            /* Integer                    */            /* NonPositiveInteger          */            /* NegativeInteger            */            /* Long                        */            /* Int                        */            /* Short                      */            /* Byte                        */            /* NonNegativeInteger          */            /* UnsignedLong                */            /* UnsignedInt                */            /* UnsignedShort              */            /* UnsignedByte                */            /* PositiveInteger            */            /* YearMonthDuration          */            /* DayTimeDuration            */        "xs:unsignedShort", "xs:unsignedByte", "xs:positiveInteger", "xdt:yearMonthDuration", "xdt:dayTimeDuration"};
  684.         #endregion
  685.        
  686.         /// <summary>
  687.         /// Implements an NxN bit matrix.
  688.         /// </summary>
  689.         private sealed class BitMatrix
  690.         {
  691.             private ulong[] bits;
  692.            
  693.             /// <summary>
  694.             /// Create NxN bit matrix, where N = count.
  695.             /// </summary>
  696.             public BitMatrix(int count)
  697.             {
  698.                 Debug.Assert(count < 64, "BitMatrix currently only handles up to 64x64 matrix.");
  699.                 bits = new ulong[count];
  700.             }
  701.            
  702.             // /// <summary>
  703.             // /// Return the number of rows and columns in the matrix.
  704.             // /// </summary>
  705.             // public int Size {
  706.             // get { return bits.Length; }
  707.             // }
  708.             //
  709.             /// <summary>
  710.             /// Get or set a bit in the matrix at position (index1, index2).
  711.             /// </summary>
  712.             public bool this[int index1, int index2]
  713.             {
  714.                 get {
  715.                     Debug.Assert(index1 < bits.Length && index2 < bits.Length, "Index out of range.");
  716.                     return (bits[index1] & ((ulong)1 << index2)) != 0;
  717.                 }
  718.                 set {
  719.                     Debug.Assert(index1 < bits.Length && index2 < bits.Length, "Index out of range.");
  720.                     if (value == true) {
  721.                         bits[index1] |= (ulong)1 << index2;
  722.                     }
  723.                     else {
  724.                         bits[index1] &= ~((ulong)1 << index2);
  725.                     }
  726.                 }
  727.             }
  728.            
  729.             /// <summary>
  730.             /// Strongly typed indexer.
  731.             /// </summary>
  732.             public bool this[XmlTypeCode index1, XmlTypeCode index2]
  733.             {
  734.                 get { return this[(int)index1, (int)index2]; }
  735.             }
  736.             // set {
  737.             // this[(int)index1, (int)index2] = value;
  738.             // }
  739.         }
  740.     }
  741. }

Developer Fusion