Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / XmlUtils / System / Xml / Xsl / XmlQueryTypeFactory.cs / 1 / XmlQueryTypeFactory.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //----------------------------------------------------------------------------- using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Xml.Schema; using System.Xml.XPath; namespace System.Xml.Xsl { using TF = XmlQueryTypeFactory; ////// This class is the only way to create concrete instances of the abstract XmlQueryType class. /// Once basic types have been created, they can be combined and transformed in various ways. /// internal static class XmlQueryTypeFactory { //----------------------------------------------- // Type Construction Operators //----------------------------------------------- ////// Create an XmlQueryType from an XmlTypeCode. /// /// the type code of the item /// true if the dynamic type is guaranteed to match the static type exactly ///the atomic value type public static XmlQueryType Type(XmlTypeCode code, bool isStrict) { return ItemType.Create(code, isStrict); } ////// Create an XmlQueryType from an Xsd simple type (where variety can be Atomic, List, or Union). /// /// the simple Xsd schema type of the atomic value /// true if the dynamic type is guaranteed to match the static type exactly ///the atomic value type public static XmlQueryType Type(XmlSchemaSimpleType schemaType, bool isStrict) { if (schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic) { // We must special-case xs:anySimpleType because it is broken in Xsd and is sometimes treated as // an atomic value and sometimes as a list value. In XQuery, it always maps to xdt:anyAtomicType*. if (schemaType == DatatypeImplementation.AnySimpleType) return AnyAtomicTypeS; return ItemType.Create(schemaType, isStrict); } // Skip restrictions. It is safe to do that because this is a list or union, so it's not a build in type while (schemaType.DerivedBy == XmlSchemaDerivationMethod.Restriction) schemaType = (XmlSchemaSimpleType) schemaType.BaseXmlSchemaType; // Convert Xsd list if (schemaType.DerivedBy == XmlSchemaDerivationMethod.List) return PrimeProduct(Type(((XmlSchemaSimpleTypeList) schemaType.Content).BaseItemType, isStrict), XmlQueryCardinality.ZeroOrMore); // Convert Xsd union Debug.Assert(schemaType.DerivedBy == XmlSchemaDerivationMethod.Union); XmlSchemaSimpleType[] baseMemberTypes = ((XmlSchemaSimpleTypeUnion) schemaType.Content).BaseMemberTypes; XmlQueryType[] queryMemberTypes = new XmlQueryType[baseMemberTypes.Length]; for (int i = 0; i < baseMemberTypes.Length; i++) queryMemberTypes[i] = Type(baseMemberTypes[i], isStrict); return Choice(queryMemberTypes); } ////// Construct the union of two XmlQueryTypes /// /// the left type /// the right type ///the union type public static XmlQueryType Choice(XmlQueryType left, XmlQueryType right) { return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List(left), right)), left.Cardinality | right.Cardinality); } /// /// Construct the union of several XmlQueryTypes /// /// the list of types ///the union type public static XmlQueryType Choice(params XmlQueryType[] types) { if (types.Length == 0) return None; else if (types.Length == 1) return types[0]; // Union each type with next type Listlist = new List (types[0]); XmlQueryCardinality card = types[0].Cardinality; for (int i = 1; i < types.Length; i++) { PrimeChoice(list, types[i]); card |= types[i].Cardinality; } return SequenceType.Create(ChoiceType.Create(list), card); } /// /// Create a Node XmlQueryType which is the choice between several different node kinds. /// /// the node kinds which will make up the choice ///the node type public static XmlQueryType NodeChoice(XmlNodeKindFlags kinds) { return ChoiceType.Create(kinds); } ////// Construct the sequence of two XmlQueryTypes /// /// the left type /// the right type ///the sequence type public static XmlQueryType Sequence(XmlQueryType left, XmlQueryType right) { return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List(left), right)), left.Cardinality + right.Cardinality); } #if NEVER /// /// Construct the sequence of several XmlQueryTypes /// /// the sequence of types ///the sequence type public XmlQueryType Sequence(params XmlQueryType[] types) { XmlQueryCardinality card = XmlQueryCardinality.Zero; foreach (XmlQueryType t in types) card += t.Cardinality; return PrimeProduct(Choice(types), card); } #endif ////// Compute the product of the prime of "t" with cardinality "c". /// /// the member type /// the cardinality ///the prime type with the indicated cardinality applied public static XmlQueryType PrimeProduct(XmlQueryType t, XmlQueryCardinality c) { // If cardinality stays the same, then this is a no-op if (t.Cardinality == c && !t.IsDod) return t; return SequenceType.Create(t.Prime, c); } ////// Compute a sequence with cardinality *= c. /// /// the type to sequence /// the cardinality multiplier ///the sequence of t with cardinality *= c public static XmlQueryType Product(XmlQueryType t, XmlQueryCardinality c) { return PrimeProduct(t, t.Cardinality * c); } ////// Compute a sequence of zero to some max cardinality. /// /// the type to sequence /// the upper bound ///the sequence of t from 0 to c public static XmlQueryType AtMost(XmlQueryType t, XmlQueryCardinality c) { return PrimeProduct(t, c.AtMost()); } #region Built-in types //----------------------------------------------- // Pre-Created Types // // Abbreviations: // P = Plus (+) // Q = Question Mark (?) // S = Star (*) // X = Exact (IsStrict = true) //----------------------------------------------- public static readonly XmlQueryType None = ChoiceType.None; public static readonly XmlQueryType Empty = SequenceType.Zero; public static readonly XmlQueryType Item = TF.Type(XmlTypeCode.Item, false); public static readonly XmlQueryType ItemS = TF.PrimeProduct(Item, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Node = TF.Type(XmlTypeCode.Node, false); public static readonly XmlQueryType NodeS = TF.PrimeProduct(Node, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Element = TF.Type(XmlTypeCode.Element, false); public static readonly XmlQueryType ElementS = TF.PrimeProduct(Element, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Document = TF.Type(XmlTypeCode.Document, false); public static readonly XmlQueryType DocumentS = TF.PrimeProduct(Document, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Attribute = TF.Type(XmlTypeCode.Attribute, false); public static readonly XmlQueryType AttributeQ = TF.PrimeProduct(Attribute, XmlQueryCardinality.ZeroOrOne); public static readonly XmlQueryType AttributeS = TF.PrimeProduct(Attribute, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Namespace = TF.Type(XmlTypeCode.Namespace, false); public static readonly XmlQueryType NamespaceS = TF.PrimeProduct(Namespace, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Text = TF.Type(XmlTypeCode.Text, false); public static readonly XmlQueryType TextS = TF.PrimeProduct(Text, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Comment = TF.Type(XmlTypeCode.Comment, false); public static readonly XmlQueryType CommentS = TF.PrimeProduct(Comment, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType PI = TF.Type(XmlTypeCode.ProcessingInstruction, false); public static readonly XmlQueryType PIS = TF.PrimeProduct(PI, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType DocumentOrElement = TF.Choice(Document, Element); public static readonly XmlQueryType DocumentOrElementQ = TF.PrimeProduct(DocumentOrElement, XmlQueryCardinality.ZeroOrOne); public static readonly XmlQueryType DocumentOrElementS = TF.PrimeProduct(DocumentOrElement, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Content = TF.Choice(Element, Comment, PI, Text); public static readonly XmlQueryType ContentS = TF.PrimeProduct(Content, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType DocumentOrContent = TF.Choice(Document, Content); public static readonly XmlQueryType DocumentOrContentS = TF.PrimeProduct(DocumentOrContent, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType AttributeOrContent = TF.Choice(Attribute, Content); public static readonly XmlQueryType AttributeOrContentS = TF.PrimeProduct(AttributeOrContent, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType AnyAtomicType = TF.Type(XmlTypeCode.AnyAtomicType, false); public static readonly XmlQueryType AnyAtomicTypeS = TF.PrimeProduct(AnyAtomicType, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType String = TF.Type(XmlTypeCode.String, false); public static readonly XmlQueryType StringX = TF.Type(XmlTypeCode.String, true); public static readonly XmlQueryType StringXS = TF.PrimeProduct(StringX, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Boolean = TF.Type(XmlTypeCode.Boolean, false); public static readonly XmlQueryType BooleanX = TF.Type(XmlTypeCode.Boolean, true); public static readonly XmlQueryType Int = TF.Type(XmlTypeCode.Int, false); public static readonly XmlQueryType IntX = TF.Type(XmlTypeCode.Int, true); public static readonly XmlQueryType IntXS = TF.PrimeProduct(IntX, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType IntegerX = TF.Type(XmlTypeCode.Integer, true); public static readonly XmlQueryType LongX = TF.Type(XmlTypeCode.Long, true); public static readonly XmlQueryType DecimalX = TF.Type(XmlTypeCode.Decimal, true); public static readonly XmlQueryType FloatX = TF.Type(XmlTypeCode.Float, true); public static readonly XmlQueryType Double = TF.Type(XmlTypeCode.Double, false); public static readonly XmlQueryType DoubleX = TF.Type(XmlTypeCode.Double, true); public static readonly XmlQueryType DateTimeX = TF.Type(XmlTypeCode.DateTime, true); public static readonly XmlQueryType QNameX = TF.Type(XmlTypeCode.QName, true); public static readonly XmlQueryType UntypedDocument = ItemType.UntypedDocument; public static readonly XmlQueryType UntypedElement = ItemType.UntypedElement; public static readonly XmlQueryType UntypedAttribute = ItemType.UntypedAttribute; public static readonly XmlQueryType UntypedNode = TF.Choice(UntypedDocument, UntypedElement, UntypedAttribute, Namespace, Text, Comment, PI); public static readonly XmlQueryType UntypedNodeS = TF.PrimeProduct(UntypedNode, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType NodeNotRtf = ItemType.NodeNotRtf; public static readonly XmlQueryType NodeNotRtfQ = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrOne); public static readonly XmlQueryType NodeNotRtfS = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType NodeDodS = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrMore); #endregion //----------------------------------------------- // Helpers //----------------------------------------------- ////// Construct the union of two lists of prime XmlQueryTypes. Types are added to "accumulator" as necessary to ensure /// it contains a superset of "types". /// private static ListPrimeChoice(List accumulator, IList types) { foreach (XmlQueryType sourceItem in types) { AddItemToChoice(accumulator, sourceItem); } return accumulator; } /// /// Adds itemType to a union. Returns false if new item is a subtype of one of the types in the list. /// private static void AddItemToChoice(Listaccumulator, XmlQueryType itemType) { Debug.Assert(itemType.IsSingleton, "All types should be prime."); bool addToList = true; for (int i = 0; i < accumulator.Count; i++) { // If new prime is a subtype of existing prime, don't add it to the union if (itemType.IsSubtypeOf(accumulator[i])) { return; } // If new prime is a subtype of existing prime, then replace the existing prime with new prime if (accumulator[i].IsSubtypeOf(itemType)) { if (addToList) { addToList = false; accumulator[i] = itemType; } else { accumulator.RemoveAt(i); i --; } } } if (addToList) { accumulator.Add(itemType); } } #region NodeKindToTypeCode /// /// Map XPathNodeType to XmlTypeCode. /// private static readonly XmlTypeCode[] NodeKindToTypeCode = { /* XPathNodeType.Root */ XmlTypeCode.Document, /* XPathNodeType.Element */ XmlTypeCode.Element, /* XPathNodeType.Attribute */ XmlTypeCode.Attribute, /* XPathNodeType.Namespace */ XmlTypeCode.Namespace, /* XPathNodeType.Text */ XmlTypeCode.Text, /* XPathNodeType.SignificantWhitespace */ XmlTypeCode.Text, /* XPathNodeType.Whitespace */ XmlTypeCode.Text, /* XPathNodeType.ProcessingInstruction */ XmlTypeCode.ProcessingInstruction, /* XPathNodeType.Comment */ XmlTypeCode.Comment, /* XPathNodeType.All */ XmlTypeCode.Node, }; #endregion //----------------------------------------------- // XmlQueryType Implementations //----------------------------------------------- ////// Implementation of XmlQueryType for singleton types. /// private sealed class ItemType : XmlQueryType { // If you add new types here, add them to SpecialBuiltInItemTypes as well public static readonly XmlQueryType UntypedDocument; public static readonly XmlQueryType UntypedElement; public static readonly XmlQueryType UntypedAttribute; public static readonly XmlQueryType NodeNotRtf; public static readonly XmlQueryType NodeDod; private static XmlQueryType[] BuiltInItemTypes; private static XmlQueryType[] BuiltInItemTypesStrict; private static XmlQueryType[] SpecialBuiltInItemTypes; private XmlTypeCode code; private XmlQualifiedNameTest nameTest; private XmlSchemaType schemaType; private bool isNillable; private XmlNodeKindFlags nodeKinds; private bool isStrict; private bool isNotRtf; ////// Construct arrays of built-in types. /// static ItemType() { #if DEBUG Array arrEnum = Enum.GetValues(typeof(XmlTypeCode)); Debug.Assert((XmlTypeCode) arrEnum.GetValue(arrEnum.Length - 1) == XmlTypeCode.DayTimeDuration, "DayTimeDuration is no longer the last item in XmlTypeCode. This code expects it to be."); #endif int typeCount = (int) XmlTypeCode.DayTimeDuration + 1; BuiltInItemTypes = new XmlQueryType[typeCount]; BuiltInItemTypesStrict = new XmlQueryType[typeCount]; for (int i = 0; i < typeCount; i++) { XmlTypeCode typeCode = (XmlTypeCode)i; switch ((XmlTypeCode) i) { case XmlTypeCode.None: BuiltInItemTypes[i] = ChoiceType.None; BuiltInItemTypesStrict[i] = ChoiceType.None; continue; case XmlTypeCode.Item: case XmlTypeCode.Node: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, false); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.Document: case XmlTypeCode.Element: case XmlTypeCode.Namespace: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Text: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.Attribute: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnySimpleType, false, false, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.AnyAtomicType: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnyAtomicType, false, false, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.UntypedAtomic: // xdt:untypedAtomic is sealed, and therefore always strict BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, true, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; default: XmlSchemaType builtInType = XmlSchemaType.GetBuiltInSimpleType(typeCode); BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, false, true); BuiltInItemTypesStrict[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, true, true); break; } } UntypedDocument = new ItemType(XmlTypeCode.Document, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true); UntypedElement = new ItemType(XmlTypeCode.Element, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true); UntypedAttribute = new ItemType(XmlTypeCode.Attribute, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, false, true); NodeNotRtf = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true); NodeDod = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true); SpecialBuiltInItemTypes = new XmlQueryType[4] { UntypedDocument, UntypedElement, UntypedAttribute, NodeNotRtf }; } ////// Create ItemType from XmlTypeCode. /// public static XmlQueryType Create(XmlTypeCode code, bool isStrict) { // No objects need to be allocated, as corresponding ItemTypes for all type codes have been statically allocated if (isStrict) return BuiltInItemTypesStrict[(int) code]; return BuiltInItemTypes[(int) code]; } ////// Create ItemType from Xsd atomic type. /// public static XmlQueryType Create(XmlSchemaSimpleType schemaType, bool isStrict) { Debug.Assert(schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic, "List or Union Xsd types should have been handled by caller."); XmlTypeCode code = schemaType.Datatype.TypeCode; // If schemaType is a built-in type, if (schemaType == XmlSchemaType.GetBuiltInSimpleType(code)) { // Then use statically allocated type return Create(code, isStrict); } // Otherwise, create a new type return new ItemType(code, XmlQualifiedNameTest.Wildcard, schemaType, false, isStrict, true); } ////// Create Document, Element or Attribute with specified name test, content type and nillable. /// public static XmlQueryType Create(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) { // If this is a Document, Element, or Attribute, switch (code) { case XmlTypeCode.Document: case XmlTypeCode.Element: if (nameTest.IsWildcard) { // Normalize document(*, xs:anyType), element(*, xs:anyType) if (contentType == XmlSchemaComplexType.AnyType) return Create(code, false); // Normalize document(xs:untypedAny), element(*, xs:untypedAny) if (contentType == XmlSchemaComplexType.UntypedAnyType) { Debug.Assert(!isNillable); if (code == XmlTypeCode.Element) return UntypedElement; if (code == XmlTypeCode.Document) return UntypedDocument; } } // Create new ItemType return new ItemType(code, nameTest, contentType, isNillable, false, true); case XmlTypeCode.Attribute: if (nameTest.IsWildcard) { // Normalize attribute(xs:anySimpleType) if (contentType == DatatypeImplementation.AnySimpleType) return Create(code, false); // Normalize attribute(xs:untypedAtomic) if (contentType == DatatypeImplementation.UntypedAtomicType) return UntypedAttribute; } // Create new ItemType return new ItemType(code, nameTest, contentType, isNillable, false, true); default: return Create(code, false); } } ////// Private constructor. Create methods should be used to create instances. /// private ItemType(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType schemaType, bool isNillable, bool isStrict, bool isNotRtf) { Debug.Assert(nameTest != null, "nameTest cannot be null"); Debug.Assert(schemaType != null, "schemaType cannot be null"); this.code = code; this.nameTest = nameTest; this.schemaType = schemaType; this.isNillable = isNillable; this.isStrict = isStrict; this.isNotRtf = isNotRtf; Debug.Assert(!IsAtomicValue || schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic); switch (code) { case XmlTypeCode.Item: this.nodeKinds = XmlNodeKindFlags.Any; break; case XmlTypeCode.Node: this.nodeKinds = XmlNodeKindFlags.Any; break; case XmlTypeCode.Document: this.nodeKinds = XmlNodeKindFlags.Document; break; case XmlTypeCode.Element: this.nodeKinds = XmlNodeKindFlags.Element; break; case XmlTypeCode.Attribute: this.nodeKinds = XmlNodeKindFlags.Attribute; break; case XmlTypeCode.Namespace: this.nodeKinds = XmlNodeKindFlags.Namespace; break; case XmlTypeCode.ProcessingInstruction: this.nodeKinds = XmlNodeKindFlags.PI; break; case XmlTypeCode.Comment: this.nodeKinds = XmlNodeKindFlags.Comment; break; case XmlTypeCode.Text: this.nodeKinds = XmlNodeKindFlags.Text; break; default: this.nodeKinds = XmlNodeKindFlags.None; break; } } //----------------------------------------------- // Serialization //----------------------------------------------- ////// Serialize the object to BinaryWriter. /// public override void GetObjectData(BinaryWriter writer) { sbyte code = (sbyte) this.code; for (int idx = 0; idx < SpecialBuiltInItemTypes.Length; idx++) { if ((object) this == (object) SpecialBuiltInItemTypes[idx]) { code = (sbyte) ~idx; break; } } writer.Write(code); if (0 <= code) { Debug.Assert((object) this == (object) Create(this.code, this.isStrict), "Unknown type"); writer.Write(this.isStrict); } } ////// Deserialize the object from BinaryReader. /// public static XmlQueryType Create(BinaryReader reader) { sbyte code = reader.ReadSByte(); if (0 <= code) return Create((XmlTypeCode) code, /*isStrict:*/reader.ReadBoolean()); else return SpecialBuiltInItemTypes[~code]; } //----------------------------------------------- // ItemType, OccurenceIndicator Properties //----------------------------------------------- ////// Return the TypeCode. /// public override XmlTypeCode TypeCode { get { return this.code; } } ////// Return the NameTest. /// public override XmlQualifiedNameTest NameTest { get { return this.nameTest; } } ////// Return the Xsd schema type. This must be non-null for atomic value types. /// public override XmlSchemaType SchemaType { get { return this.schemaType; } } ////// Return the IsNillable. /// public override bool IsNillable { get { return this.isNillable; } } ////// Since this is always an atomic value type, NodeKinds = None. /// public override XmlNodeKindFlags NodeKinds { get { return this.nodeKinds; } } ////// Return flag indicating whether the dynamic type is guaranteed to be the same as the static type. /// public override bool IsStrict { get { return this.isStrict; } } ////// Return flag indicating whether this is not an Rtf. /// public override bool IsNotRtf { get { return this.isNotRtf; } } ////// Only NodeDod type returns true. /// public override bool IsDod { get { return (object) this == (object) NodeDod; } } ////// Always return cardinality One. /// public override XmlQueryCardinality Cardinality { get { return XmlQueryCardinality.One; } } ////// Prime of atomic value type is itself. /// public override XmlQueryType Prime { get { return this; } } ////// Return the item's converter. /// public override XmlValueConverter ClrMapping { get { // Return value converter from XmlSchemaType if type is atomic if (IsAtomicValue) return SchemaType.ValueConverter; // Return node converter if item must be a node if (IsNode) return XmlNodeConverter.Node; // Otherwise return item converter return XmlAnyConverter.Item; } } //----------------------------------------------- // ListBase implementation //----------------------------------------------- ////// AtomicValueType is only a composition of itself, rather than other smaller types. /// public override int Count { get { return 1; } } ////// AtomicValueType is only a composition of itself, rather than other smaller types. /// public override XmlQueryType this[int index] { get { if (index != 0) throw new IndexOutOfRangeException(); return this; } set { throw new NotSupportedException(); } } } ////// Implementation of XmlQueryType that composes a choice of various prime types. /// private sealed class ChoiceType : XmlQueryType { public static readonly XmlQueryType None = new ChoiceType(new List()); private XmlTypeCode code; private XmlSchemaType schemaType; private XmlNodeKindFlags nodeKinds; private List members; /// /// Create choice between node kinds. /// public static XmlQueryType Create(XmlNodeKindFlags nodeKinds) { Listmembers; // If exactly one kind is set, then create singleton ItemType if (Bits.ExactlyOne((uint) nodeKinds)) return ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint) nodeKinds)], false); members = new List (); while (nodeKinds != XmlNodeKindFlags.None) { members.Add(ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint) nodeKinds)], false)); nodeKinds = (XmlNodeKindFlags) Bits.ClearLeast((uint) nodeKinds); } return Create(members); } /// /// Create choice containing the specified list of types. /// public static XmlQueryType Create(Listmembers) { if (members.Count == 0) return None; if (members.Count == 1) return members[0]; return new ChoiceType(members); } /// /// Private constructor. Create methods should be used to create instances. /// private ChoiceType(Listmembers) { Debug.Assert(members != null && members.Count != 1, "ChoiceType must contain a list with 0 or >1 types."); this.members = members; // Compute supertype of all member types for (int i = 0; i < members.Count; i++) { XmlQueryType t = members[i]; Debug.Assert(t.Cardinality == XmlQueryCardinality.One, "ChoiceType member types must be prime types."); // Summarize the union of member types as a single type if (this.code == XmlTypeCode.None) { // None combined with member type is the member type this.code = t.TypeCode; this.schemaType = t.SchemaType; } else if (IsNode && t.IsNode) { // Node combined with node is node if (this.code == t.TypeCode) { // Element or attribute combined with element or attribute can be summarized as element(*, XmlSchemaComplexType.AnyType) or attribute(*, DatatypeImplementation.AnySimpleType) if (this.code == XmlTypeCode.Element) this.schemaType = XmlSchemaComplexType.AnyType; else if (this.code == XmlTypeCode.Attribute) this.schemaType = DatatypeImplementation.AnySimpleType; } else { this.code = XmlTypeCode.Node; this.schemaType = null; } } else if (IsAtomicValue && t.IsAtomicValue) { // Atomic value combined with atomic value is atomic value this.code = XmlTypeCode.AnyAtomicType; this.schemaType = DatatypeImplementation.AnyAtomicType; } else { // Else we'll summarize types as Item this.code = XmlTypeCode.Item; this.schemaType = null; } // Always track union of node kinds this.nodeKinds |= t.NodeKinds; } } private static readonly XmlTypeCode[] NodeKindToTypeCode = { /* None */ XmlTypeCode.None, /* Document */ XmlTypeCode.Document, /* Element */ XmlTypeCode.Element, /* Attribute */ XmlTypeCode.Attribute, /* Text */ XmlTypeCode.Text, /* Comment */ XmlTypeCode.Comment, /* PI */ XmlTypeCode.ProcessingInstruction, /* Namespace */ XmlTypeCode.Namespace, }; //----------------------------------------------- // Serialization //----------------------------------------------- /// /// Serialize the object to BinaryWriter. /// public override void GetObjectData(BinaryWriter writer) { writer.Write(this.members.Count); for (int i = 0; i < this.members.Count; i++) { TF.Serialize(writer, this.members[i]); } } ////// Deserialize the object from BinaryReader. /// public static XmlQueryType Create(BinaryReader reader) { int length = reader.ReadInt32(); Listmembers = new List (length); for (int i = 0; i < length; i++) { members.Add(TF.Deserialize(reader)); } return Create(members); } //----------------------------------------------- // ItemType, OccurenceIndicator Properties //----------------------------------------------- /// /// Return a type code which is a supertype of all member types. /// public override XmlTypeCode TypeCode { get { return this.code; } } ////// Return the NameTest. /// public override XmlQualifiedNameTest NameTest { get { return XmlQualifiedNameTest.Wildcard; } } ////// Return an Xsd schema type which is a supertype of all member types. /// public override XmlSchemaType SchemaType { get { return this.schemaType; } } ////// Return the IsNillable. /// public override bool IsNillable { get { return false; } } ////// Return a set of NodeKinds which is the union of all member node kinds. /// public override XmlNodeKindFlags NodeKinds { get { return this.nodeKinds; } } ////// Choice types are always non-strict, except for the empty choice. /// public override bool IsStrict { get { return members.Count == 0; } } ////// Return true if every type in the choice is not an Rtf. /// public override bool IsNotRtf { get { for (int i = 0; i < members.Count; i++) { if (!this.members[i].IsNotRtf) return false; } return true; } } ////// Return true if every type in the choice is in document order with no duplicates. /// public override bool IsDod { get { for (int i = 0; i < members.Count; i++) { if (!this.members[i].IsDod) return false; } return true; } } ////// Always return cardinality none or one. /// public override XmlQueryCardinality Cardinality { get { return TypeCode == XmlTypeCode.None ? XmlQueryCardinality.None : XmlQueryCardinality.One; } } ////// Prime of union type is itself. /// public override XmlQueryType Prime { get { return this; } } ////// Always return the item converter. /// public override XmlValueConverter ClrMapping { get { if (this.code == XmlTypeCode.None || this.code == XmlTypeCode.Item) return XmlAnyConverter.Item; if (IsAtomicValue) return SchemaType.ValueConverter; return XmlNodeConverter.Node; } } //----------------------------------------------- // ListBase implementation //----------------------------------------------- ////// Return the number of union member types. /// public override int Count { get { return this.members.Count; } } ////// Return a union member type by index. /// public override XmlQueryType this[int index] { get { return this.members[index]; } set { throw new NotSupportedException(); } } } ////// Implementation of XmlQueryType that modifies the cardinality of a composed type. /// private sealed class SequenceType : XmlQueryType { public static readonly XmlQueryType Zero = new SequenceType(ChoiceType.None, XmlQueryCardinality.Zero); private XmlQueryType prime; private XmlQueryCardinality card; private XmlValueConverter converter; ////// Create sequence type from prime and cardinality. /// public static XmlQueryType Create(XmlQueryType prime, XmlQueryCardinality card) { Debug.Assert(prime != null, "SequenceType can only modify the cardinality of a non-null XmlQueryType."); Debug.Assert(prime.IsSingleton, "Prime type must have cardinality one."); if (prime.TypeCode == XmlTypeCode.None) { // If cardinality includes zero, then return (None, Zero), else return (None, None). return XmlQueryCardinality.Zero <= card ? Zero : None; } // Normalize sequences with these cardinalities: None, Zero, One if (card == XmlQueryCardinality.None) { return None; } else if (card == XmlQueryCardinality.Zero) { return Zero; } else if (card == XmlQueryCardinality.One) { return prime; } return new SequenceType(prime, card); } ////// Private constructor. Create methods should be used to create instances. /// private SequenceType(XmlQueryType prime, XmlQueryCardinality card) { this.prime = prime; this.card = card; } //----------------------------------------------- // Serialization //----------------------------------------------- ////// Serialize the object to BinaryWriter. /// public override void GetObjectData(BinaryWriter writer) { writer.Write(this.IsDod); if (this.IsDod) return; TF.Serialize(writer, this.prime); this.card.GetObjectData(writer); } ////// Deserialize the object from BinaryReader. /// public static XmlQueryType Create(BinaryReader reader) { if (reader.ReadBoolean()) return TF.NodeDodS; XmlQueryType prime = TF.Deserialize(reader); XmlQueryCardinality card = new XmlQueryCardinality(reader); return Create(prime, card); } //----------------------------------------------- // ItemType, OccurenceIndicator Properties //----------------------------------------------- ////// Return the TypeCode of the prime type. /// public override XmlTypeCode TypeCode { get { return this.prime.TypeCode; } } ////// Return the NameTest of the prime type /// public override XmlQualifiedNameTest NameTest { get { return this.prime.NameTest; } } ////// Return the Xsd schema type of the prime type. /// public override XmlSchemaType SchemaType { get { return this.prime.SchemaType; } } ////// Return the IsNillable of the prime type /// public override bool IsNillable { get { return this.prime.IsNillable; } } ////// Return the NodeKinds of the prime type. /// public override XmlNodeKindFlags NodeKinds { get { return this.prime.NodeKinds; } } ////// Return the IsStrict flag of the prime type. /// public override bool IsStrict { get { return this.prime.IsStrict; } } ////// Return the IsNotRtf flag of the prime type. /// public override bool IsNotRtf { get { return this.prime.IsNotRtf; } } ////// Return the IsDod flag of the prime type. /// public override bool IsDod { get { return (object) this == (object) NodeDodS; } } ////// Return the modified cardinality. /// public override XmlQueryCardinality Cardinality { get { return this.card; } } ////// Return prime of sequence type. /// public override XmlQueryType Prime { get { return this.prime; } } ////// Return the prime's converter wrapped in a list converter. /// public override XmlValueConverter ClrMapping { get { if (this.converter == null) this.converter = XmlListConverter.Create(this.prime.ClrMapping); return this.converter; } } //----------------------------------------------- // ListBase implementation //----------------------------------------------- ////// Return the Count of the prime type. /// public override int Count { get { return this.prime.Count; } } ////// Return the parts of the prime type. /// public override XmlQueryType this[int index] { get { return this.prime[index]; } set { throw new NotSupportedException(); } } } ////// Create a Node XmlQueryType having an XSD content type. /// /// unless kind is Root, Element, or Attribute, "contentType" is ignored /// content type of the node ///the node type public static XmlQueryType Type(XPathNodeType kind, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) { return ItemType.Create(NodeKindToTypeCode[(int)kind], nameTest, contentType, isNillable); } #region Serialization ////// Check if the given type can be serialized. /// [Conditional("DEBUG")] public static void CheckSerializability(XmlQueryType type) { type.GetObjectData(new BinaryWriter(Stream.Null)); } ////// Serialize XmlQueryType to BinaryWriter. /// public static void Serialize(BinaryWriter writer, XmlQueryType type) { sbyte subtypeId; if (type.GetType() == typeof(ItemType)) subtypeId = 0; else if (type.GetType() == typeof(ChoiceType)) subtypeId = 1; else if (type.GetType() == typeof(SequenceType)) subtypeId = 2; else { Debug.Fail("Don't know how to serialize " + type.GetType().ToString()); subtypeId = -1; } writer.Write(subtypeId); type.GetObjectData(writer); } ////// Deserialize XmlQueryType from BinaryReader. /// public static XmlQueryType Deserialize(BinaryReader reader) { switch (reader.ReadByte()) { case 0: return ItemType.Create(reader); case 1: return ChoiceType.Create(reader); case 2: return SequenceType.Create(reader); default: Debug.Fail("Unexpected XmlQueryType's subtype id"); return null; } } #endregion #if NEVER // Remove from code since we don't use and FxCop complains. May re-add later. private XmlSchemaSet schemaSet; ////// Create an XmlQueryType having an XSD name test, content type and nillable. /// /// unless code is Document, Element, or Attribute, "contentType" is ignored /// name test on the node /// content type of the node /// nillable property ///the item type public XmlQueryType Type(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) { return ItemType.Create(code, nameTest, contentType, isNillable); } ////// Create a strict XmlQueryType from the source. /// /// source type ///strict type if the source is atomic, the source otherwise public XmlQueryType StrictType(XmlQueryType source) { if (source.IsAtomicValue && source.Count == 1) return SequenceType.Create(ItemType.Create((XmlSchemaSimpleType)source.SchemaType, true), source.Cardinality); return source; } ////// Create an XmlQueryType from an XmlTypeCode and cardinality. /// /// the type code of the item /// cardinality ///build-in type type public XmlQueryType Type(XmlTypeCode code, XmlQueryCardinality card) { return SequenceType.Create(ItemType.Create(code, false), card); } ////// Create an XmlQueryType having an XSD name test, content type, nillable and cardinality. /// /// unless code is Document, Element, or Attribute, "contentType" is ignored /// name test on the node /// content type of the node /// nillable property /// cardinality ///the item type public XmlQueryType Type(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable, XmlQueryCardinality card) { return SequenceType.Create(ItemType.Create(code, nameTest, contentType, isNillable), card); } ////// Construct the intersection of two XmlQueryTypes /// /// the left type /// the right type ///the intersection type public XmlQueryType Intersect(XmlQueryType left, XmlQueryType right) { return SequenceType.Create(ChoiceType.Create(PrimeIntersect(left, right)), left.Cardinality & right.Cardinality); } ////// Construct the intersection of several XmlQueryTypes /// /// the list of types ///the intersection type public XmlQueryType Intersect(params XmlQueryType[] types) { if (types.Length == 0) return None; else if (types.Length == 1) return types[0]; // Intersect each type with next type Listlist = PrimeIntersect(types[0], types[1]); XmlQueryCardinality card = types[0].Cardinality & types[1].Cardinality; for (int i = 2; i < types.Length; i++) { list = PrimeIntersect(list, types[i]); card &= types[i].Cardinality; } return SequenceType.Create(ChoiceType.Create(list), card); } /// /// Construct the intersection of two lists of prime XmlQueryTypes. /// private ListPrimeIntersect(IList left, IList right) { List list = new List (); foreach (XmlQueryType leftItem in left) { foreach (XmlQueryType rightItem in right) { XmlQueryType intersection = IntersectItemTypes(leftItem, rightItem); // Do not add none1 to a list if ((object)intersection != (object)None) { list.Add(intersection); } } } return list; } /// /// Converts type of sequence of items to type of sequnce of atomic value // See http://www.w3.org/TR/2004/xquery-semantics/#jd_data for the detailed description /// /// source type ///type of the sequence of atomic values public XmlQueryType DataOn(XmlQueryType source) { Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Item: case XmlTypeCode.Node: AddItemToChoice(list, AnyAtomicType); card = XmlQueryCardinality.ZeroOrMore; break; case XmlTypeCode.Document: case XmlTypeCode.Text: AddItemToChoice(list, UntypedAtomic); card |= XmlQueryCardinality.One; break; case XmlTypeCode.Comment: case XmlTypeCode.ProcessingInstruction: AddItemToChoice(list, String); card |= XmlQueryCardinality.One; break; case XmlTypeCode.Element: case XmlTypeCode.Attribute: XmlSchemaType sourceSchemaType = sourceItem.SchemaType; if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType || sourceSchemaType == DatatypeImplementation.UntypedAtomicType) { AddItemToChoice(list, UntypedAtomic); card |= XmlQueryCardinality.One; } else if (sourceSchemaType == XmlSchemaComplexType.AnyType || sourceSchemaType == DatatypeImplementation.AnySimpleType) { AddItemToChoice(list, AnyAtomicType); card = XmlQueryCardinality.ZeroOrMore; } else { if (sourceSchemaType.Datatype == null) { // Complex content adds anyAtomicType* if mixed XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceItem.SchemaType; if (complexType.ContentType == XmlSchemaContentType.Mixed) { AddItemToChoice(list, AnyAtomicType); card = XmlQueryCardinality.ZeroOrMore; } else { // Error if mixed is false return null; } } else { // Simple content XmlSchemaType schemaType = sourceItem.SchemaType; // Go up the tree until it's a simple type while (schemaType is XmlSchemaComplexType) { schemaType = schemaType.BaseXmlSchemaType; } // Calculate XmlQueryType from XmlSchemaSimpleType XmlQueryType atomicSeq = Type((XmlSchemaSimpleType)schemaType, false); // Add prime to a choice // It doen't have to be a single item! PrimeChoice(list, atomicSeq.Prime); // Add cardinality to a choice card |= atomicSeq.Cardinality; } // Add ? if nillable if (sourceItem.IsNillable) { card *= XmlQueryCardinality.ZeroOrOne; } } break; case XmlTypeCode.Namespace: card |= XmlQueryCardinality.Zero; break; case XmlTypeCode.None: break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); AddItemToChoice(list, sourceItem); card |= XmlQueryCardinality.One; break; } } return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// Filter type of node sequence with a type (filter) /// /// source type /// type filter ///type of the filtered node sequence public XmlQueryType FilterOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { card |= AddFilteredPrime(list, sourceItem, filter, true); } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// For the type of node sequence calculate type of children filtered with a type (filter) /// /// source type /// type filter ///type of the children node sequence public XmlQueryType ChildrenOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Node: case XmlTypeCode.Document: case XmlTypeCode.Element: XmlSchemaType sourceSchemaType = sourceItem.SchemaType; XmlQueryCardinality itemCard = XmlQueryCardinality.None; // Only element and document can have children if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { // content of xdt:untypedAny is element(*, xdt:untypedAny)* itemCard = (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore); itemCard += AddFilteredPrime(list, Text, filter); } else if (sourceSchemaType.Datatype != null) { // Text is the only child node simple type can have itemCard = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne; } else { // Complex content XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType; itemCard = AddChildParticle(list, complexType.ContentTypeParticle, filter); if (complexType.ContentType == XmlSchemaContentType.Mixed) { itemCard += AddFilteredPrime(list, Text, filter); } } itemCard += AddFilteredPrime(list, PI, filter); itemCard += AddFilteredPrime(list, Comment, filter); card |= itemCard; break; case XmlTypeCode.Attribute: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Namespace: case XmlTypeCode.Text: card |= XmlQueryCardinality.Zero; break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); return null; } } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// For the type of node sequence calculate type of attributes filtered with a type (filter) /// /// source type /// type filter ///type of the children node sequence public XmlQueryType AttributesOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Node: case XmlTypeCode.Element: XmlSchemaType sourceSchemaType = sourceItem.SchemaType; if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { // attfibutes of of xdt:untypedAny are attribute(*, xdt:untypedAtomic)* card |= AddFilteredPrime(list, UntypedAttribute, filter) * XmlQueryCardinality.ZeroOrOne; } else { // Only complex type can have attributes XmlSchemaComplexType type = sourceSchemaType as XmlSchemaComplexType; if (type != null) { card |= AddAttributes(list, type.AttributeUses, type.AttributeWildcard, filter); } } break; case XmlTypeCode.Document: case XmlTypeCode.Attribute: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Namespace: case XmlTypeCode.Text: card |= XmlQueryCardinality.Zero; break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); return null; } } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// For the type of node sequence calculate type of parent filtered with a type (filter) /// /// source type /// type filter ///type of the parent node sequence public XmlQueryType ParentOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Node: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Text: case XmlTypeCode.Element: if (schemaSet == null) { card |= AddFilteredPrime(list, UntypedDocument, filter) * XmlQueryCardinality.ZeroOrOne; card |= AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrOne; } else { card |= AddFilteredPrime(list, Document, filter) * XmlQueryCardinality.ZeroOrOne; card |= AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrOne; } break; case XmlTypeCode.Namespace: case XmlTypeCode.Attribute: if (schemaSet == null) { card |= (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrOne); } else { card |= (AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrOne); } break; case XmlTypeCode.Document: card |= XmlQueryCardinality.Zero; break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); break; } } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// For the type of node sequence calculate type of descendants filtered with a type (filter) /// /// source type /// type filter ///type of the descendants node sequence public XmlQueryType DescendantsOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Node: case XmlTypeCode.Document: case XmlTypeCode.Element: XmlQueryCardinality itemCard = XmlQueryCardinality.None; if ((filter.NodeKinds & (XmlNodeKindFlags.Element | XmlNodeKindFlags.Text)) != 0) { Dictionary allTypes = new Dictionary (); XmlSchemaType sourceSchemaType = sourceItem.SchemaType; if (sourceSchemaType == null) { Debug.Assert(sourceItem.TypeCode == XmlTypeCode.Node); sourceSchemaType = XmlSchemaComplexType.AnyType; } itemCard = AddElementOrTextDescendants(list, allTypes, sourceSchemaType, filter); } itemCard += AddFilteredPrime(list, PI, filter); itemCard += AddFilteredPrime(list, Comment, filter); card |= itemCard; break; case XmlTypeCode.Attribute: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Namespace: case XmlTypeCode.Text: card |= XmlQueryCardinality.Zero; break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); break; } } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// For the type of node sequence calculate type of ancestor filtered with a type (filter) /// /// source type /// type filter ///type of the ancestor node sequence public XmlQueryType AncestorsOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Node: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Text: case XmlTypeCode.Element: case XmlTypeCode.Namespace: case XmlTypeCode.Attribute: if (schemaSet == null) { card |= (AddFilteredPrime(list, UntypedDocument, filter) * XmlQueryCardinality.ZeroOrOne) + (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore); } else { card |= (AddFilteredPrime(list, Document, filter) * XmlQueryCardinality.ZeroOrOne) + (AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrMore); } break; case XmlTypeCode.Document: card |= XmlQueryCardinality.Zero; break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); break; } } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } private XmlQueryCardinality AddAttributes(List list, XmlSchemaObjectTable attributeUses, XmlSchemaAnyAttribute attributeWildcard, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.Zero; if (attributeWildcard != null) { XmlSchemaType attributeSchemaType = attributeWildcard.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? DatatypeImplementation.UntypedAtomicType : DatatypeImplementation.AnySimpleType; // wildcard will match more then one attribute switch (attributeWildcard.NamespaceList.Type) { case NamespaceList.ListType.Set: foreach (string ns in attributeWildcard.NamespaceList.Enumerate) { card += AddFilteredPrime(list, CreateAttributeType(ns, false, attributeSchemaType), filter); } break; case NamespaceList.ListType.Other: card += AddFilteredPrime(list, CreateAttributeType(attributeWildcard.NamespaceList.Excluded, true, attributeSchemaType), filter); break; case NamespaceList.ListType.Any: default: card += AddFilteredPrime(list, attributeWildcard.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedAttribute : Attribute, filter); break; } // Always optional card *= XmlQueryCardinality.ZeroOrOne; } foreach (XmlSchemaAttribute attribute in attributeUses.Values) { XmlQueryCardinality cardAttr = AddFilteredPrime(list, CreateAttributeType(attribute), filter); if (cardAttr != XmlQueryCardinality.Zero) { Debug.Assert(cardAttr == XmlQueryCardinality.ZeroOrOne || cardAttr == XmlQueryCardinality.One); card += (attribute.Use == XmlSchemaUse.Optional ? XmlQueryCardinality.ZeroOrOne : cardAttr); } } return card; } private XmlQueryType CreateAttributeType(XmlSchemaAttribute attribute) { return ItemType.Create(XmlTypeCode.Attribute, XmlQualifiedNameTest.New(attribute.QualifiedName), attribute.AttributeSchemaType, false); } private XmlQueryType CreateAttributeType(string ns, bool exclude, XmlSchemaType schemaType) { return ItemType.Create(XmlTypeCode.Attribute, XmlQualifiedNameTest.New(ns, exclude), schemaType, false); } private XmlQueryCardinality AddDescendantParticle(List list, Dictionary allTypes, XmlSchemaParticle particle, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.None; XmlSchemaElement element = particle as XmlSchemaElement; if (element != null) { // Single element XmlQueryType elementType = CreateElementType(element); // Add it card = AddFilteredPrime(list, elementType, filter); // Descend card += AddElementOrTextDescendants(list, allTypes, elementType.SchemaType, filter); } else { XmlSchemaAny any = particle as XmlSchemaAny; if (any != null) { // Descendants of any card = AddFilteredPrime(list, Element, filter); } else { XmlSchemaGroupBase group = particle as XmlSchemaGroupBase; if (group.Items.Count != 0) { if (particle is XmlSchemaChoice) { foreach (XmlSchemaParticle p in group.Items) { card |= AddDescendantParticle(list, allTypes, p, filter); } } else { // Sequence and All foreach (XmlSchemaParticle p in group.Items) { card += AddDescendantParticle(list, allTypes, p, filter); } } } } } return card * CardinalityOfParticle(particle); } private XmlQueryCardinality AddElementOrTextDescendants(List list, Dictionary allTypes, XmlSchemaType sourceSchemaType, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.None; if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { card = AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore; card += AddFilteredPrime(list, Text, filter); } else if (sourceSchemaType.Datatype != null) { // Text is the only child node simple content of complext type card = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne; } else { // Complex content XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType; if (complexType.QualifiedName.IsEmpty || !allTypes.TryGetValue(complexType.QualifiedName, out card)) { allTypes[complexType.QualifiedName] = XmlQueryCardinality.ZeroOrMore; // take care of left recursion card = AddDescendantParticle(list, allTypes, complexType.ContentTypeParticle, filter); allTypes[complexType.QualifiedName] = card; //set correct card if (complexType.ContentType == XmlSchemaContentType.Mixed) { card += AddFilteredPrime(list, Text, filter); } } } return card; } /// /// Create type based on an XmlSchemaElement /// private XmlQueryType CreateElementType(XmlSchemaElement element) { return ItemType.Create(XmlTypeCode.Element, XmlQualifiedNameTest.New(element.QualifiedName), element.ElementSchemaType, element.IsNillable); } ////// Create type based on a wildcard /// private XmlQueryType CreateElementType(string ns, bool exclude, XmlSchemaType schemaType) { return ItemType.Create(XmlTypeCode.Element, XmlQualifiedNameTest.New(ns, exclude), schemaType, false); } ////// Descend though the content model /// private XmlQueryCardinality AddChildParticle(Listlist, XmlSchemaParticle particle, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.None; XmlSchemaElement element = particle as XmlSchemaElement; if (element != null) { // Single element card = AddFilteredPrime(list, CreateElementType(element), filter); } else { // XmlSchemaAny matches more then one element XmlSchemaAny any = particle as XmlSchemaAny; if (any != null) { XmlSchemaType elementSchemaType = any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? XmlSchemaComplexType.UntypedAnyType : XmlSchemaComplexType.AnyType; switch (any.NamespaceList.Type) { case NamespaceList.ListType.Set: // Add a separate type for each namespace in the list foreach (string ns in any.NamespaceList.Enumerate) { card |= AddFilteredPrime(list, CreateElementType(ns, false, elementSchemaType), filter); } break; case NamespaceList.ListType.Other: // Add ##other card = AddFilteredPrime(list, CreateElementType(any.NamespaceList.Excluded, true, elementSchemaType), filter); break; case NamespaceList.ListType.Any: default: // Add ##any card = AddFilteredPrime(list, any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedElement : Element, filter); break; } } else { // recurse into particle group XmlSchemaGroupBase group = particle as XmlSchemaGroupBase; if (group.Items.Count != 0) { if (particle is XmlSchemaChoice) { foreach (XmlSchemaParticle p in group.Items) { card |= AddChildParticle(list, p, filter); } } else { // Sequence and All foreach (XmlSchemaParticle p in group.Items) { card += AddChildParticle(list, p, filter); } } } } } return card * CardinalityOfParticle(particle); } /// /// Apply filter an item type, add the result to a list, return cardinality /// private XmlQueryCardinality AddFilteredPrime(Listlist, XmlQueryType source, XmlQueryType filter) { return AddFilteredPrime(list, source, filter, false); } private XmlQueryCardinality AddFilteredPrime(List list, XmlQueryType source, XmlQueryType filter, bool forseSingle) { Debug.Assert(source.IsNode && source.IsSingleton); Debug.Assert(filter.IsNode && filter.IsSingleton); // Intersect types XmlQueryType intersection = IntersectItemTypes(source, filter); if ((object)intersection == (object)None) { return XmlQueryCardinality.Zero; } AddItemToChoice(list, intersection); // In the case of forseSingle - filtering all nodes behave as singletones XmlTypeCode typeCode = (forseSingle ? XmlTypeCode.Node : intersection.TypeCode); switch (typeCode) { case XmlTypeCode.Node: case XmlTypeCode.Document: case XmlTypeCode.Element: // Filter can result in empty sequence if filter is not wider then source if (intersection == source) return XmlQueryCardinality.One; else return XmlQueryCardinality.ZeroOrOne; case XmlTypeCode.Attribute: // wildcard attribute matches more then one node if (!intersection.NameTest.IsSingleName) return XmlQueryCardinality.ZeroOrMore; else if (intersection == source) return XmlQueryCardinality.One; else return XmlQueryCardinality.ZeroOrOne; case XmlTypeCode.Comment: case XmlTypeCode.Text: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Namespace: return XmlQueryCardinality.ZeroOrMore; default: Debug.Assert(false); return XmlQueryCardinality.None; } } /// /// Construct the intersection of two lists of prime XmlQueryTypes. /// private XmlQueryType IntersectItemTypes(XmlQueryType left, XmlQueryType right) { Debug.Assert(left.Count == 1 && left.IsSingleton, "left should be an item"); Debug.Assert(right.Count == 1 && right.IsSingleton, "right should be an item"); if (left.TypeCode == right.TypeCode && (left.NodeKinds & (XmlNodeKindFlags.Document | XmlNodeKindFlags.Element | XmlNodeKindFlags.Attribute)) != 0) { if (left.TypeCode == XmlTypeCode.Node) { return left; } // Intersect name tests XmlQualifiedNameTest nameTest = left.NameTest.Intersect(right.NameTest); // Intersect types XmlSchemaType type = XmlSchemaType.IsDerivedFrom(left.SchemaType, right.SchemaType, /* exept:*/XmlSchemaDerivationMethod.Empty) ? left.SchemaType : XmlSchemaType.IsDerivedFrom(right.SchemaType, left.SchemaType, /* exept:*/XmlSchemaDerivationMethod.Empty) ? right.SchemaType : null; bool isNillable = left.IsNillable && right.IsNillable; if ((object)nameTest == (object)left.NameTest && type == left.SchemaType && isNillable == left.IsNillable) { // left is a subtype of right return left return left; } else if ((object)nameTest == (object)right.NameTest && type == right.SchemaType && isNillable == right.IsNillable) { // right is a subtype of left return right return right; } else if (nameTest != null && type != null) { // create a new type return ItemType.Create(left.TypeCode, nameTest, type, isNillable); } } else if (left.IsSubtypeOf(right)) { // left is a subset of right, so left is in the intersection return left; } else if (right.IsSubtypeOf(left)) { // right is a subset of left, so right is in the intersection return right; } return None; } ////// Convert particle occurrance range into cardinality /// private XmlQueryCardinality CardinalityOfParticle(XmlSchemaParticle particle) { if (particle.MinOccurs == decimal.Zero) { if (particle.MaxOccurs == decimal.Zero) { return XmlQueryCardinality.Zero; } else if (particle.MaxOccurs == decimal.One) { return XmlQueryCardinality.ZeroOrOne; } else { return XmlQueryCardinality.ZeroOrMore; } } else { if (particle.MaxOccurs == decimal.One) { return XmlQueryCardinality.One; } else { return XmlQueryCardinality.OneOrMore; } } } #endif } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //[....] //----------------------------------------------------------------------------- using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Xml.Schema; using System.Xml.XPath; namespace System.Xml.Xsl { using TF = XmlQueryTypeFactory; ////// This class is the only way to create concrete instances of the abstract XmlQueryType class. /// Once basic types have been created, they can be combined and transformed in various ways. /// internal static class XmlQueryTypeFactory { //----------------------------------------------- // Type Construction Operators //----------------------------------------------- ////// Create an XmlQueryType from an XmlTypeCode. /// /// the type code of the item /// true if the dynamic type is guaranteed to match the static type exactly ///the atomic value type public static XmlQueryType Type(XmlTypeCode code, bool isStrict) { return ItemType.Create(code, isStrict); } ////// Create an XmlQueryType from an Xsd simple type (where variety can be Atomic, List, or Union). /// /// the simple Xsd schema type of the atomic value /// true if the dynamic type is guaranteed to match the static type exactly ///the atomic value type public static XmlQueryType Type(XmlSchemaSimpleType schemaType, bool isStrict) { if (schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic) { // We must special-case xs:anySimpleType because it is broken in Xsd and is sometimes treated as // an atomic value and sometimes as a list value. In XQuery, it always maps to xdt:anyAtomicType*. if (schemaType == DatatypeImplementation.AnySimpleType) return AnyAtomicTypeS; return ItemType.Create(schemaType, isStrict); } // Skip restrictions. It is safe to do that because this is a list or union, so it's not a build in type while (schemaType.DerivedBy == XmlSchemaDerivationMethod.Restriction) schemaType = (XmlSchemaSimpleType) schemaType.BaseXmlSchemaType; // Convert Xsd list if (schemaType.DerivedBy == XmlSchemaDerivationMethod.List) return PrimeProduct(Type(((XmlSchemaSimpleTypeList) schemaType.Content).BaseItemType, isStrict), XmlQueryCardinality.ZeroOrMore); // Convert Xsd union Debug.Assert(schemaType.DerivedBy == XmlSchemaDerivationMethod.Union); XmlSchemaSimpleType[] baseMemberTypes = ((XmlSchemaSimpleTypeUnion) schemaType.Content).BaseMemberTypes; XmlQueryType[] queryMemberTypes = new XmlQueryType[baseMemberTypes.Length]; for (int i = 0; i < baseMemberTypes.Length; i++) queryMemberTypes[i] = Type(baseMemberTypes[i], isStrict); return Choice(queryMemberTypes); } ////// Construct the union of two XmlQueryTypes /// /// the left type /// the right type ///the union type public static XmlQueryType Choice(XmlQueryType left, XmlQueryType right) { return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List(left), right)), left.Cardinality | right.Cardinality); } /// /// Construct the union of several XmlQueryTypes /// /// the list of types ///the union type public static XmlQueryType Choice(params XmlQueryType[] types) { if (types.Length == 0) return None; else if (types.Length == 1) return types[0]; // Union each type with next type Listlist = new List (types[0]); XmlQueryCardinality card = types[0].Cardinality; for (int i = 1; i < types.Length; i++) { PrimeChoice(list, types[i]); card |= types[i].Cardinality; } return SequenceType.Create(ChoiceType.Create(list), card); } /// /// Create a Node XmlQueryType which is the choice between several different node kinds. /// /// the node kinds which will make up the choice ///the node type public static XmlQueryType NodeChoice(XmlNodeKindFlags kinds) { return ChoiceType.Create(kinds); } ////// Construct the sequence of two XmlQueryTypes /// /// the left type /// the right type ///the sequence type public static XmlQueryType Sequence(XmlQueryType left, XmlQueryType right) { return SequenceType.Create(ChoiceType.Create(PrimeChoice(new List(left), right)), left.Cardinality + right.Cardinality); } #if NEVER /// /// Construct the sequence of several XmlQueryTypes /// /// the sequence of types ///the sequence type public XmlQueryType Sequence(params XmlQueryType[] types) { XmlQueryCardinality card = XmlQueryCardinality.Zero; foreach (XmlQueryType t in types) card += t.Cardinality; return PrimeProduct(Choice(types), card); } #endif ////// Compute the product of the prime of "t" with cardinality "c". /// /// the member type /// the cardinality ///the prime type with the indicated cardinality applied public static XmlQueryType PrimeProduct(XmlQueryType t, XmlQueryCardinality c) { // If cardinality stays the same, then this is a no-op if (t.Cardinality == c && !t.IsDod) return t; return SequenceType.Create(t.Prime, c); } ////// Compute a sequence with cardinality *= c. /// /// the type to sequence /// the cardinality multiplier ///the sequence of t with cardinality *= c public static XmlQueryType Product(XmlQueryType t, XmlQueryCardinality c) { return PrimeProduct(t, t.Cardinality * c); } ////// Compute a sequence of zero to some max cardinality. /// /// the type to sequence /// the upper bound ///the sequence of t from 0 to c public static XmlQueryType AtMost(XmlQueryType t, XmlQueryCardinality c) { return PrimeProduct(t, c.AtMost()); } #region Built-in types //----------------------------------------------- // Pre-Created Types // // Abbreviations: // P = Plus (+) // Q = Question Mark (?) // S = Star (*) // X = Exact (IsStrict = true) //----------------------------------------------- public static readonly XmlQueryType None = ChoiceType.None; public static readonly XmlQueryType Empty = SequenceType.Zero; public static readonly XmlQueryType Item = TF.Type(XmlTypeCode.Item, false); public static readonly XmlQueryType ItemS = TF.PrimeProduct(Item, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Node = TF.Type(XmlTypeCode.Node, false); public static readonly XmlQueryType NodeS = TF.PrimeProduct(Node, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Element = TF.Type(XmlTypeCode.Element, false); public static readonly XmlQueryType ElementS = TF.PrimeProduct(Element, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Document = TF.Type(XmlTypeCode.Document, false); public static readonly XmlQueryType DocumentS = TF.PrimeProduct(Document, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Attribute = TF.Type(XmlTypeCode.Attribute, false); public static readonly XmlQueryType AttributeQ = TF.PrimeProduct(Attribute, XmlQueryCardinality.ZeroOrOne); public static readonly XmlQueryType AttributeS = TF.PrimeProduct(Attribute, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Namespace = TF.Type(XmlTypeCode.Namespace, false); public static readonly XmlQueryType NamespaceS = TF.PrimeProduct(Namespace, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Text = TF.Type(XmlTypeCode.Text, false); public static readonly XmlQueryType TextS = TF.PrimeProduct(Text, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Comment = TF.Type(XmlTypeCode.Comment, false); public static readonly XmlQueryType CommentS = TF.PrimeProduct(Comment, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType PI = TF.Type(XmlTypeCode.ProcessingInstruction, false); public static readonly XmlQueryType PIS = TF.PrimeProduct(PI, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType DocumentOrElement = TF.Choice(Document, Element); public static readonly XmlQueryType DocumentOrElementQ = TF.PrimeProduct(DocumentOrElement, XmlQueryCardinality.ZeroOrOne); public static readonly XmlQueryType DocumentOrElementS = TF.PrimeProduct(DocumentOrElement, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Content = TF.Choice(Element, Comment, PI, Text); public static readonly XmlQueryType ContentS = TF.PrimeProduct(Content, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType DocumentOrContent = TF.Choice(Document, Content); public static readonly XmlQueryType DocumentOrContentS = TF.PrimeProduct(DocumentOrContent, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType AttributeOrContent = TF.Choice(Attribute, Content); public static readonly XmlQueryType AttributeOrContentS = TF.PrimeProduct(AttributeOrContent, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType AnyAtomicType = TF.Type(XmlTypeCode.AnyAtomicType, false); public static readonly XmlQueryType AnyAtomicTypeS = TF.PrimeProduct(AnyAtomicType, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType String = TF.Type(XmlTypeCode.String, false); public static readonly XmlQueryType StringX = TF.Type(XmlTypeCode.String, true); public static readonly XmlQueryType StringXS = TF.PrimeProduct(StringX, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType Boolean = TF.Type(XmlTypeCode.Boolean, false); public static readonly XmlQueryType BooleanX = TF.Type(XmlTypeCode.Boolean, true); public static readonly XmlQueryType Int = TF.Type(XmlTypeCode.Int, false); public static readonly XmlQueryType IntX = TF.Type(XmlTypeCode.Int, true); public static readonly XmlQueryType IntXS = TF.PrimeProduct(IntX, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType IntegerX = TF.Type(XmlTypeCode.Integer, true); public static readonly XmlQueryType LongX = TF.Type(XmlTypeCode.Long, true); public static readonly XmlQueryType DecimalX = TF.Type(XmlTypeCode.Decimal, true); public static readonly XmlQueryType FloatX = TF.Type(XmlTypeCode.Float, true); public static readonly XmlQueryType Double = TF.Type(XmlTypeCode.Double, false); public static readonly XmlQueryType DoubleX = TF.Type(XmlTypeCode.Double, true); public static readonly XmlQueryType DateTimeX = TF.Type(XmlTypeCode.DateTime, true); public static readonly XmlQueryType QNameX = TF.Type(XmlTypeCode.QName, true); public static readonly XmlQueryType UntypedDocument = ItemType.UntypedDocument; public static readonly XmlQueryType UntypedElement = ItemType.UntypedElement; public static readonly XmlQueryType UntypedAttribute = ItemType.UntypedAttribute; public static readonly XmlQueryType UntypedNode = TF.Choice(UntypedDocument, UntypedElement, UntypedAttribute, Namespace, Text, Comment, PI); public static readonly XmlQueryType UntypedNodeS = TF.PrimeProduct(UntypedNode, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType NodeNotRtf = ItemType.NodeNotRtf; public static readonly XmlQueryType NodeNotRtfQ = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrOne); public static readonly XmlQueryType NodeNotRtfS = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrMore); public static readonly XmlQueryType NodeDodS = TF.PrimeProduct(NodeNotRtf, XmlQueryCardinality.ZeroOrMore); #endregion //----------------------------------------------- // Helpers //----------------------------------------------- ////// Construct the union of two lists of prime XmlQueryTypes. Types are added to "accumulator" as necessary to ensure /// it contains a superset of "types". /// private static ListPrimeChoice(List accumulator, IList types) { foreach (XmlQueryType sourceItem in types) { AddItemToChoice(accumulator, sourceItem); } return accumulator; } /// /// Adds itemType to a union. Returns false if new item is a subtype of one of the types in the list. /// private static void AddItemToChoice(Listaccumulator, XmlQueryType itemType) { Debug.Assert(itemType.IsSingleton, "All types should be prime."); bool addToList = true; for (int i = 0; i < accumulator.Count; i++) { // If new prime is a subtype of existing prime, don't add it to the union if (itemType.IsSubtypeOf(accumulator[i])) { return; } // If new prime is a subtype of existing prime, then replace the existing prime with new prime if (accumulator[i].IsSubtypeOf(itemType)) { if (addToList) { addToList = false; accumulator[i] = itemType; } else { accumulator.RemoveAt(i); i --; } } } if (addToList) { accumulator.Add(itemType); } } #region NodeKindToTypeCode /// /// Map XPathNodeType to XmlTypeCode. /// private static readonly XmlTypeCode[] NodeKindToTypeCode = { /* XPathNodeType.Root */ XmlTypeCode.Document, /* XPathNodeType.Element */ XmlTypeCode.Element, /* XPathNodeType.Attribute */ XmlTypeCode.Attribute, /* XPathNodeType.Namespace */ XmlTypeCode.Namespace, /* XPathNodeType.Text */ XmlTypeCode.Text, /* XPathNodeType.SignificantWhitespace */ XmlTypeCode.Text, /* XPathNodeType.Whitespace */ XmlTypeCode.Text, /* XPathNodeType.ProcessingInstruction */ XmlTypeCode.ProcessingInstruction, /* XPathNodeType.Comment */ XmlTypeCode.Comment, /* XPathNodeType.All */ XmlTypeCode.Node, }; #endregion //----------------------------------------------- // XmlQueryType Implementations //----------------------------------------------- ////// Implementation of XmlQueryType for singleton types. /// private sealed class ItemType : XmlQueryType { // If you add new types here, add them to SpecialBuiltInItemTypes as well public static readonly XmlQueryType UntypedDocument; public static readonly XmlQueryType UntypedElement; public static readonly XmlQueryType UntypedAttribute; public static readonly XmlQueryType NodeNotRtf; public static readonly XmlQueryType NodeDod; private static XmlQueryType[] BuiltInItemTypes; private static XmlQueryType[] BuiltInItemTypesStrict; private static XmlQueryType[] SpecialBuiltInItemTypes; private XmlTypeCode code; private XmlQualifiedNameTest nameTest; private XmlSchemaType schemaType; private bool isNillable; private XmlNodeKindFlags nodeKinds; private bool isStrict; private bool isNotRtf; ////// Construct arrays of built-in types. /// static ItemType() { #if DEBUG Array arrEnum = Enum.GetValues(typeof(XmlTypeCode)); Debug.Assert((XmlTypeCode) arrEnum.GetValue(arrEnum.Length - 1) == XmlTypeCode.DayTimeDuration, "DayTimeDuration is no longer the last item in XmlTypeCode. This code expects it to be."); #endif int typeCount = (int) XmlTypeCode.DayTimeDuration + 1; BuiltInItemTypes = new XmlQueryType[typeCount]; BuiltInItemTypesStrict = new XmlQueryType[typeCount]; for (int i = 0; i < typeCount; i++) { XmlTypeCode typeCode = (XmlTypeCode)i; switch ((XmlTypeCode) i) { case XmlTypeCode.None: BuiltInItemTypes[i] = ChoiceType.None; BuiltInItemTypesStrict[i] = ChoiceType.None; continue; case XmlTypeCode.Item: case XmlTypeCode.Node: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, false); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.Document: case XmlTypeCode.Element: case XmlTypeCode.Namespace: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Text: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.Attribute: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnySimpleType, false, false, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.AnyAtomicType: BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.AnyAtomicType, false, false, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; case XmlTypeCode.UntypedAtomic: // xdt:untypedAtomic is sealed, and therefore always strict BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, true, true); BuiltInItemTypesStrict[i] = BuiltInItemTypes[i]; break; default: XmlSchemaType builtInType = XmlSchemaType.GetBuiltInSimpleType(typeCode); BuiltInItemTypes[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, false, true); BuiltInItemTypesStrict[i] = new ItemType(typeCode, XmlQualifiedNameTest.Wildcard, builtInType, false, true, true); break; } } UntypedDocument = new ItemType(XmlTypeCode.Document, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true); UntypedElement = new ItemType(XmlTypeCode.Element, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.UntypedAnyType, false, false, true); UntypedAttribute = new ItemType(XmlTypeCode.Attribute, XmlQualifiedNameTest.Wildcard, DatatypeImplementation.UntypedAtomicType, false, false, true); NodeNotRtf = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true); NodeDod = new ItemType(XmlTypeCode.Node, XmlQualifiedNameTest.Wildcard, XmlSchemaComplexType.AnyType, false, false, true); SpecialBuiltInItemTypes = new XmlQueryType[4] { UntypedDocument, UntypedElement, UntypedAttribute, NodeNotRtf }; } ////// Create ItemType from XmlTypeCode. /// public static XmlQueryType Create(XmlTypeCode code, bool isStrict) { // No objects need to be allocated, as corresponding ItemTypes for all type codes have been statically allocated if (isStrict) return BuiltInItemTypesStrict[(int) code]; return BuiltInItemTypes[(int) code]; } ////// Create ItemType from Xsd atomic type. /// public static XmlQueryType Create(XmlSchemaSimpleType schemaType, bool isStrict) { Debug.Assert(schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic, "List or Union Xsd types should have been handled by caller."); XmlTypeCode code = schemaType.Datatype.TypeCode; // If schemaType is a built-in type, if (schemaType == XmlSchemaType.GetBuiltInSimpleType(code)) { // Then use statically allocated type return Create(code, isStrict); } // Otherwise, create a new type return new ItemType(code, XmlQualifiedNameTest.Wildcard, schemaType, false, isStrict, true); } ////// Create Document, Element or Attribute with specified name test, content type and nillable. /// public static XmlQueryType Create(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) { // If this is a Document, Element, or Attribute, switch (code) { case XmlTypeCode.Document: case XmlTypeCode.Element: if (nameTest.IsWildcard) { // Normalize document(*, xs:anyType), element(*, xs:anyType) if (contentType == XmlSchemaComplexType.AnyType) return Create(code, false); // Normalize document(xs:untypedAny), element(*, xs:untypedAny) if (contentType == XmlSchemaComplexType.UntypedAnyType) { Debug.Assert(!isNillable); if (code == XmlTypeCode.Element) return UntypedElement; if (code == XmlTypeCode.Document) return UntypedDocument; } } // Create new ItemType return new ItemType(code, nameTest, contentType, isNillable, false, true); case XmlTypeCode.Attribute: if (nameTest.IsWildcard) { // Normalize attribute(xs:anySimpleType) if (contentType == DatatypeImplementation.AnySimpleType) return Create(code, false); // Normalize attribute(xs:untypedAtomic) if (contentType == DatatypeImplementation.UntypedAtomicType) return UntypedAttribute; } // Create new ItemType return new ItemType(code, nameTest, contentType, isNillable, false, true); default: return Create(code, false); } } ////// Private constructor. Create methods should be used to create instances. /// private ItemType(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType schemaType, bool isNillable, bool isStrict, bool isNotRtf) { Debug.Assert(nameTest != null, "nameTest cannot be null"); Debug.Assert(schemaType != null, "schemaType cannot be null"); this.code = code; this.nameTest = nameTest; this.schemaType = schemaType; this.isNillable = isNillable; this.isStrict = isStrict; this.isNotRtf = isNotRtf; Debug.Assert(!IsAtomicValue || schemaType.Datatype.Variety == XmlSchemaDatatypeVariety.Atomic); switch (code) { case XmlTypeCode.Item: this.nodeKinds = XmlNodeKindFlags.Any; break; case XmlTypeCode.Node: this.nodeKinds = XmlNodeKindFlags.Any; break; case XmlTypeCode.Document: this.nodeKinds = XmlNodeKindFlags.Document; break; case XmlTypeCode.Element: this.nodeKinds = XmlNodeKindFlags.Element; break; case XmlTypeCode.Attribute: this.nodeKinds = XmlNodeKindFlags.Attribute; break; case XmlTypeCode.Namespace: this.nodeKinds = XmlNodeKindFlags.Namespace; break; case XmlTypeCode.ProcessingInstruction: this.nodeKinds = XmlNodeKindFlags.PI; break; case XmlTypeCode.Comment: this.nodeKinds = XmlNodeKindFlags.Comment; break; case XmlTypeCode.Text: this.nodeKinds = XmlNodeKindFlags.Text; break; default: this.nodeKinds = XmlNodeKindFlags.None; break; } } //----------------------------------------------- // Serialization //----------------------------------------------- ////// Serialize the object to BinaryWriter. /// public override void GetObjectData(BinaryWriter writer) { sbyte code = (sbyte) this.code; for (int idx = 0; idx < SpecialBuiltInItemTypes.Length; idx++) { if ((object) this == (object) SpecialBuiltInItemTypes[idx]) { code = (sbyte) ~idx; break; } } writer.Write(code); if (0 <= code) { Debug.Assert((object) this == (object) Create(this.code, this.isStrict), "Unknown type"); writer.Write(this.isStrict); } } ////// Deserialize the object from BinaryReader. /// public static XmlQueryType Create(BinaryReader reader) { sbyte code = reader.ReadSByte(); if (0 <= code) return Create((XmlTypeCode) code, /*isStrict:*/reader.ReadBoolean()); else return SpecialBuiltInItemTypes[~code]; } //----------------------------------------------- // ItemType, OccurenceIndicator Properties //----------------------------------------------- ////// Return the TypeCode. /// public override XmlTypeCode TypeCode { get { return this.code; } } ////// Return the NameTest. /// public override XmlQualifiedNameTest NameTest { get { return this.nameTest; } } ////// Return the Xsd schema type. This must be non-null for atomic value types. /// public override XmlSchemaType SchemaType { get { return this.schemaType; } } ////// Return the IsNillable. /// public override bool IsNillable { get { return this.isNillable; } } ////// Since this is always an atomic value type, NodeKinds = None. /// public override XmlNodeKindFlags NodeKinds { get { return this.nodeKinds; } } ////// Return flag indicating whether the dynamic type is guaranteed to be the same as the static type. /// public override bool IsStrict { get { return this.isStrict; } } ////// Return flag indicating whether this is not an Rtf. /// public override bool IsNotRtf { get { return this.isNotRtf; } } ////// Only NodeDod type returns true. /// public override bool IsDod { get { return (object) this == (object) NodeDod; } } ////// Always return cardinality One. /// public override XmlQueryCardinality Cardinality { get { return XmlQueryCardinality.One; } } ////// Prime of atomic value type is itself. /// public override XmlQueryType Prime { get { return this; } } ////// Return the item's converter. /// public override XmlValueConverter ClrMapping { get { // Return value converter from XmlSchemaType if type is atomic if (IsAtomicValue) return SchemaType.ValueConverter; // Return node converter if item must be a node if (IsNode) return XmlNodeConverter.Node; // Otherwise return item converter return XmlAnyConverter.Item; } } //----------------------------------------------- // ListBase implementation //----------------------------------------------- ////// AtomicValueType is only a composition of itself, rather than other smaller types. /// public override int Count { get { return 1; } } ////// AtomicValueType is only a composition of itself, rather than other smaller types. /// public override XmlQueryType this[int index] { get { if (index != 0) throw new IndexOutOfRangeException(); return this; } set { throw new NotSupportedException(); } } } ////// Implementation of XmlQueryType that composes a choice of various prime types. /// private sealed class ChoiceType : XmlQueryType { public static readonly XmlQueryType None = new ChoiceType(new List()); private XmlTypeCode code; private XmlSchemaType schemaType; private XmlNodeKindFlags nodeKinds; private List members; /// /// Create choice between node kinds. /// public static XmlQueryType Create(XmlNodeKindFlags nodeKinds) { Listmembers; // If exactly one kind is set, then create singleton ItemType if (Bits.ExactlyOne((uint) nodeKinds)) return ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint) nodeKinds)], false); members = new List (); while (nodeKinds != XmlNodeKindFlags.None) { members.Add(ItemType.Create(NodeKindToTypeCode[Bits.LeastPosition((uint) nodeKinds)], false)); nodeKinds = (XmlNodeKindFlags) Bits.ClearLeast((uint) nodeKinds); } return Create(members); } /// /// Create choice containing the specified list of types. /// public static XmlQueryType Create(Listmembers) { if (members.Count == 0) return None; if (members.Count == 1) return members[0]; return new ChoiceType(members); } /// /// Private constructor. Create methods should be used to create instances. /// private ChoiceType(Listmembers) { Debug.Assert(members != null && members.Count != 1, "ChoiceType must contain a list with 0 or >1 types."); this.members = members; // Compute supertype of all member types for (int i = 0; i < members.Count; i++) { XmlQueryType t = members[i]; Debug.Assert(t.Cardinality == XmlQueryCardinality.One, "ChoiceType member types must be prime types."); // Summarize the union of member types as a single type if (this.code == XmlTypeCode.None) { // None combined with member type is the member type this.code = t.TypeCode; this.schemaType = t.SchemaType; } else if (IsNode && t.IsNode) { // Node combined with node is node if (this.code == t.TypeCode) { // Element or attribute combined with element or attribute can be summarized as element(*, XmlSchemaComplexType.AnyType) or attribute(*, DatatypeImplementation.AnySimpleType) if (this.code == XmlTypeCode.Element) this.schemaType = XmlSchemaComplexType.AnyType; else if (this.code == XmlTypeCode.Attribute) this.schemaType = DatatypeImplementation.AnySimpleType; } else { this.code = XmlTypeCode.Node; this.schemaType = null; } } else if (IsAtomicValue && t.IsAtomicValue) { // Atomic value combined with atomic value is atomic value this.code = XmlTypeCode.AnyAtomicType; this.schemaType = DatatypeImplementation.AnyAtomicType; } else { // Else we'll summarize types as Item this.code = XmlTypeCode.Item; this.schemaType = null; } // Always track union of node kinds this.nodeKinds |= t.NodeKinds; } } private static readonly XmlTypeCode[] NodeKindToTypeCode = { /* None */ XmlTypeCode.None, /* Document */ XmlTypeCode.Document, /* Element */ XmlTypeCode.Element, /* Attribute */ XmlTypeCode.Attribute, /* Text */ XmlTypeCode.Text, /* Comment */ XmlTypeCode.Comment, /* PI */ XmlTypeCode.ProcessingInstruction, /* Namespace */ XmlTypeCode.Namespace, }; //----------------------------------------------- // Serialization //----------------------------------------------- /// /// Serialize the object to BinaryWriter. /// public override void GetObjectData(BinaryWriter writer) { writer.Write(this.members.Count); for (int i = 0; i < this.members.Count; i++) { TF.Serialize(writer, this.members[i]); } } ////// Deserialize the object from BinaryReader. /// public static XmlQueryType Create(BinaryReader reader) { int length = reader.ReadInt32(); Listmembers = new List (length); for (int i = 0; i < length; i++) { members.Add(TF.Deserialize(reader)); } return Create(members); } //----------------------------------------------- // ItemType, OccurenceIndicator Properties //----------------------------------------------- /// /// Return a type code which is a supertype of all member types. /// public override XmlTypeCode TypeCode { get { return this.code; } } ////// Return the NameTest. /// public override XmlQualifiedNameTest NameTest { get { return XmlQualifiedNameTest.Wildcard; } } ////// Return an Xsd schema type which is a supertype of all member types. /// public override XmlSchemaType SchemaType { get { return this.schemaType; } } ////// Return the IsNillable. /// public override bool IsNillable { get { return false; } } ////// Return a set of NodeKinds which is the union of all member node kinds. /// public override XmlNodeKindFlags NodeKinds { get { return this.nodeKinds; } } ////// Choice types are always non-strict, except for the empty choice. /// public override bool IsStrict { get { return members.Count == 0; } } ////// Return true if every type in the choice is not an Rtf. /// public override bool IsNotRtf { get { for (int i = 0; i < members.Count; i++) { if (!this.members[i].IsNotRtf) return false; } return true; } } ////// Return true if every type in the choice is in document order with no duplicates. /// public override bool IsDod { get { for (int i = 0; i < members.Count; i++) { if (!this.members[i].IsDod) return false; } return true; } } ////// Always return cardinality none or one. /// public override XmlQueryCardinality Cardinality { get { return TypeCode == XmlTypeCode.None ? XmlQueryCardinality.None : XmlQueryCardinality.One; } } ////// Prime of union type is itself. /// public override XmlQueryType Prime { get { return this; } } ////// Always return the item converter. /// public override XmlValueConverter ClrMapping { get { if (this.code == XmlTypeCode.None || this.code == XmlTypeCode.Item) return XmlAnyConverter.Item; if (IsAtomicValue) return SchemaType.ValueConverter; return XmlNodeConverter.Node; } } //----------------------------------------------- // ListBase implementation //----------------------------------------------- ////// Return the number of union member types. /// public override int Count { get { return this.members.Count; } } ////// Return a union member type by index. /// public override XmlQueryType this[int index] { get { return this.members[index]; } set { throw new NotSupportedException(); } } } ////// Implementation of XmlQueryType that modifies the cardinality of a composed type. /// private sealed class SequenceType : XmlQueryType { public static readonly XmlQueryType Zero = new SequenceType(ChoiceType.None, XmlQueryCardinality.Zero); private XmlQueryType prime; private XmlQueryCardinality card; private XmlValueConverter converter; ////// Create sequence type from prime and cardinality. /// public static XmlQueryType Create(XmlQueryType prime, XmlQueryCardinality card) { Debug.Assert(prime != null, "SequenceType can only modify the cardinality of a non-null XmlQueryType."); Debug.Assert(prime.IsSingleton, "Prime type must have cardinality one."); if (prime.TypeCode == XmlTypeCode.None) { // If cardinality includes zero, then return (None, Zero), else return (None, None). return XmlQueryCardinality.Zero <= card ? Zero : None; } // Normalize sequences with these cardinalities: None, Zero, One if (card == XmlQueryCardinality.None) { return None; } else if (card == XmlQueryCardinality.Zero) { return Zero; } else if (card == XmlQueryCardinality.One) { return prime; } return new SequenceType(prime, card); } ////// Private constructor. Create methods should be used to create instances. /// private SequenceType(XmlQueryType prime, XmlQueryCardinality card) { this.prime = prime; this.card = card; } //----------------------------------------------- // Serialization //----------------------------------------------- ////// Serialize the object to BinaryWriter. /// public override void GetObjectData(BinaryWriter writer) { writer.Write(this.IsDod); if (this.IsDod) return; TF.Serialize(writer, this.prime); this.card.GetObjectData(writer); } ////// Deserialize the object from BinaryReader. /// public static XmlQueryType Create(BinaryReader reader) { if (reader.ReadBoolean()) return TF.NodeDodS; XmlQueryType prime = TF.Deserialize(reader); XmlQueryCardinality card = new XmlQueryCardinality(reader); return Create(prime, card); } //----------------------------------------------- // ItemType, OccurenceIndicator Properties //----------------------------------------------- ////// Return the TypeCode of the prime type. /// public override XmlTypeCode TypeCode { get { return this.prime.TypeCode; } } ////// Return the NameTest of the prime type /// public override XmlQualifiedNameTest NameTest { get { return this.prime.NameTest; } } ////// Return the Xsd schema type of the prime type. /// public override XmlSchemaType SchemaType { get { return this.prime.SchemaType; } } ////// Return the IsNillable of the prime type /// public override bool IsNillable { get { return this.prime.IsNillable; } } ////// Return the NodeKinds of the prime type. /// public override XmlNodeKindFlags NodeKinds { get { return this.prime.NodeKinds; } } ////// Return the IsStrict flag of the prime type. /// public override bool IsStrict { get { return this.prime.IsStrict; } } ////// Return the IsNotRtf flag of the prime type. /// public override bool IsNotRtf { get { return this.prime.IsNotRtf; } } ////// Return the IsDod flag of the prime type. /// public override bool IsDod { get { return (object) this == (object) NodeDodS; } } ////// Return the modified cardinality. /// public override XmlQueryCardinality Cardinality { get { return this.card; } } ////// Return prime of sequence type. /// public override XmlQueryType Prime { get { return this.prime; } } ////// Return the prime's converter wrapped in a list converter. /// public override XmlValueConverter ClrMapping { get { if (this.converter == null) this.converter = XmlListConverter.Create(this.prime.ClrMapping); return this.converter; } } //----------------------------------------------- // ListBase implementation //----------------------------------------------- ////// Return the Count of the prime type. /// public override int Count { get { return this.prime.Count; } } ////// Return the parts of the prime type. /// public override XmlQueryType this[int index] { get { return this.prime[index]; } set { throw new NotSupportedException(); } } } ////// Create a Node XmlQueryType having an XSD content type. /// /// unless kind is Root, Element, or Attribute, "contentType" is ignored /// content type of the node ///the node type public static XmlQueryType Type(XPathNodeType kind, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) { return ItemType.Create(NodeKindToTypeCode[(int)kind], nameTest, contentType, isNillable); } #region Serialization ////// Check if the given type can be serialized. /// [Conditional("DEBUG")] public static void CheckSerializability(XmlQueryType type) { type.GetObjectData(new BinaryWriter(Stream.Null)); } ////// Serialize XmlQueryType to BinaryWriter. /// public static void Serialize(BinaryWriter writer, XmlQueryType type) { sbyte subtypeId; if (type.GetType() == typeof(ItemType)) subtypeId = 0; else if (type.GetType() == typeof(ChoiceType)) subtypeId = 1; else if (type.GetType() == typeof(SequenceType)) subtypeId = 2; else { Debug.Fail("Don't know how to serialize " + type.GetType().ToString()); subtypeId = -1; } writer.Write(subtypeId); type.GetObjectData(writer); } ////// Deserialize XmlQueryType from BinaryReader. /// public static XmlQueryType Deserialize(BinaryReader reader) { switch (reader.ReadByte()) { case 0: return ItemType.Create(reader); case 1: return ChoiceType.Create(reader); case 2: return SequenceType.Create(reader); default: Debug.Fail("Unexpected XmlQueryType's subtype id"); return null; } } #endregion #if NEVER // Remove from code since we don't use and FxCop complains. May re-add later. private XmlSchemaSet schemaSet; ////// Create an XmlQueryType having an XSD name test, content type and nillable. /// /// unless code is Document, Element, or Attribute, "contentType" is ignored /// name test on the node /// content type of the node /// nillable property ///the item type public XmlQueryType Type(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable) { return ItemType.Create(code, nameTest, contentType, isNillable); } ////// Create a strict XmlQueryType from the source. /// /// source type ///strict type if the source is atomic, the source otherwise public XmlQueryType StrictType(XmlQueryType source) { if (source.IsAtomicValue && source.Count == 1) return SequenceType.Create(ItemType.Create((XmlSchemaSimpleType)source.SchemaType, true), source.Cardinality); return source; } ////// Create an XmlQueryType from an XmlTypeCode and cardinality. /// /// the type code of the item /// cardinality ///build-in type type public XmlQueryType Type(XmlTypeCode code, XmlQueryCardinality card) { return SequenceType.Create(ItemType.Create(code, false), card); } ////// Create an XmlQueryType having an XSD name test, content type, nillable and cardinality. /// /// unless code is Document, Element, or Attribute, "contentType" is ignored /// name test on the node /// content type of the node /// nillable property /// cardinality ///the item type public XmlQueryType Type(XmlTypeCode code, XmlQualifiedNameTest nameTest, XmlSchemaType contentType, bool isNillable, XmlQueryCardinality card) { return SequenceType.Create(ItemType.Create(code, nameTest, contentType, isNillable), card); } ////// Construct the intersection of two XmlQueryTypes /// /// the left type /// the right type ///the intersection type public XmlQueryType Intersect(XmlQueryType left, XmlQueryType right) { return SequenceType.Create(ChoiceType.Create(PrimeIntersect(left, right)), left.Cardinality & right.Cardinality); } ////// Construct the intersection of several XmlQueryTypes /// /// the list of types ///the intersection type public XmlQueryType Intersect(params XmlQueryType[] types) { if (types.Length == 0) return None; else if (types.Length == 1) return types[0]; // Intersect each type with next type Listlist = PrimeIntersect(types[0], types[1]); XmlQueryCardinality card = types[0].Cardinality & types[1].Cardinality; for (int i = 2; i < types.Length; i++) { list = PrimeIntersect(list, types[i]); card &= types[i].Cardinality; } return SequenceType.Create(ChoiceType.Create(list), card); } /// /// Construct the intersection of two lists of prime XmlQueryTypes. /// private ListPrimeIntersect(IList left, IList right) { List list = new List (); foreach (XmlQueryType leftItem in left) { foreach (XmlQueryType rightItem in right) { XmlQueryType intersection = IntersectItemTypes(leftItem, rightItem); // Do not add none1 to a list if ((object)intersection != (object)None) { list.Add(intersection); } } } return list; } /// /// Converts type of sequence of items to type of sequnce of atomic value // See http://www.w3.org/TR/2004/xquery-semantics/#jd_data for the detailed description /// /// source type ///type of the sequence of atomic values public XmlQueryType DataOn(XmlQueryType source) { Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Item: case XmlTypeCode.Node: AddItemToChoice(list, AnyAtomicType); card = XmlQueryCardinality.ZeroOrMore; break; case XmlTypeCode.Document: case XmlTypeCode.Text: AddItemToChoice(list, UntypedAtomic); card |= XmlQueryCardinality.One; break; case XmlTypeCode.Comment: case XmlTypeCode.ProcessingInstruction: AddItemToChoice(list, String); card |= XmlQueryCardinality.One; break; case XmlTypeCode.Element: case XmlTypeCode.Attribute: XmlSchemaType sourceSchemaType = sourceItem.SchemaType; if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType || sourceSchemaType == DatatypeImplementation.UntypedAtomicType) { AddItemToChoice(list, UntypedAtomic); card |= XmlQueryCardinality.One; } else if (sourceSchemaType == XmlSchemaComplexType.AnyType || sourceSchemaType == DatatypeImplementation.AnySimpleType) { AddItemToChoice(list, AnyAtomicType); card = XmlQueryCardinality.ZeroOrMore; } else { if (sourceSchemaType.Datatype == null) { // Complex content adds anyAtomicType* if mixed XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceItem.SchemaType; if (complexType.ContentType == XmlSchemaContentType.Mixed) { AddItemToChoice(list, AnyAtomicType); card = XmlQueryCardinality.ZeroOrMore; } else { // Error if mixed is false return null; } } else { // Simple content XmlSchemaType schemaType = sourceItem.SchemaType; // Go up the tree until it's a simple type while (schemaType is XmlSchemaComplexType) { schemaType = schemaType.BaseXmlSchemaType; } // Calculate XmlQueryType from XmlSchemaSimpleType XmlQueryType atomicSeq = Type((XmlSchemaSimpleType)schemaType, false); // Add prime to a choice // It doen't have to be a single item! PrimeChoice(list, atomicSeq.Prime); // Add cardinality to a choice card |= atomicSeq.Cardinality; } // Add ? if nillable if (sourceItem.IsNillable) { card *= XmlQueryCardinality.ZeroOrOne; } } break; case XmlTypeCode.Namespace: card |= XmlQueryCardinality.Zero; break; case XmlTypeCode.None: break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); AddItemToChoice(list, sourceItem); card |= XmlQueryCardinality.One; break; } } return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// Filter type of node sequence with a type (filter) /// /// source type /// type filter ///type of the filtered node sequence public XmlQueryType FilterOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { card |= AddFilteredPrime(list, sourceItem, filter, true); } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// For the type of node sequence calculate type of children filtered with a type (filter) /// /// source type /// type filter ///type of the children node sequence public XmlQueryType ChildrenOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Node: case XmlTypeCode.Document: case XmlTypeCode.Element: XmlSchemaType sourceSchemaType = sourceItem.SchemaType; XmlQueryCardinality itemCard = XmlQueryCardinality.None; // Only element and document can have children if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { // content of xdt:untypedAny is element(*, xdt:untypedAny)* itemCard = (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore); itemCard += AddFilteredPrime(list, Text, filter); } else if (sourceSchemaType.Datatype != null) { // Text is the only child node simple type can have itemCard = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne; } else { // Complex content XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType; itemCard = AddChildParticle(list, complexType.ContentTypeParticle, filter); if (complexType.ContentType == XmlSchemaContentType.Mixed) { itemCard += AddFilteredPrime(list, Text, filter); } } itemCard += AddFilteredPrime(list, PI, filter); itemCard += AddFilteredPrime(list, Comment, filter); card |= itemCard; break; case XmlTypeCode.Attribute: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Namespace: case XmlTypeCode.Text: card |= XmlQueryCardinality.Zero; break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); return null; } } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// For the type of node sequence calculate type of attributes filtered with a type (filter) /// /// source type /// type filter ///type of the children node sequence public XmlQueryType AttributesOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Node: case XmlTypeCode.Element: XmlSchemaType sourceSchemaType = sourceItem.SchemaType; if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { // attfibutes of of xdt:untypedAny are attribute(*, xdt:untypedAtomic)* card |= AddFilteredPrime(list, UntypedAttribute, filter) * XmlQueryCardinality.ZeroOrOne; } else { // Only complex type can have attributes XmlSchemaComplexType type = sourceSchemaType as XmlSchemaComplexType; if (type != null) { card |= AddAttributes(list, type.AttributeUses, type.AttributeWildcard, filter); } } break; case XmlTypeCode.Document: case XmlTypeCode.Attribute: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Namespace: case XmlTypeCode.Text: card |= XmlQueryCardinality.Zero; break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); return null; } } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// For the type of node sequence calculate type of parent filtered with a type (filter) /// /// source type /// type filter ///type of the parent node sequence public XmlQueryType ParentOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Node: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Text: case XmlTypeCode.Element: if (schemaSet == null) { card |= AddFilteredPrime(list, UntypedDocument, filter) * XmlQueryCardinality.ZeroOrOne; card |= AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrOne; } else { card |= AddFilteredPrime(list, Document, filter) * XmlQueryCardinality.ZeroOrOne; card |= AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrOne; } break; case XmlTypeCode.Namespace: case XmlTypeCode.Attribute: if (schemaSet == null) { card |= (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrOne); } else { card |= (AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrOne); } break; case XmlTypeCode.Document: card |= XmlQueryCardinality.Zero; break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); break; } } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// For the type of node sequence calculate type of descendants filtered with a type (filter) /// /// source type /// type filter ///type of the descendants node sequence public XmlQueryType DescendantsOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Node: case XmlTypeCode.Document: case XmlTypeCode.Element: XmlQueryCardinality itemCard = XmlQueryCardinality.None; if ((filter.NodeKinds & (XmlNodeKindFlags.Element | XmlNodeKindFlags.Text)) != 0) { Dictionary allTypes = new Dictionary (); XmlSchemaType sourceSchemaType = sourceItem.SchemaType; if (sourceSchemaType == null) { Debug.Assert(sourceItem.TypeCode == XmlTypeCode.Node); sourceSchemaType = XmlSchemaComplexType.AnyType; } itemCard = AddElementOrTextDescendants(list, allTypes, sourceSchemaType, filter); } itemCard += AddFilteredPrime(list, PI, filter); itemCard += AddFilteredPrime(list, Comment, filter); card |= itemCard; break; case XmlTypeCode.Attribute: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Namespace: case XmlTypeCode.Text: card |= XmlQueryCardinality.Zero; break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); break; } } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } /// /// For the type of node sequence calculate type of ancestor filtered with a type (filter) /// /// source type /// type filter ///type of the ancestor node sequence public XmlQueryType AncestorsOf(XmlQueryType source, XmlQueryType filter) { Debug.Assert(filter.IsNode && filter.Count == 1 && filter.IsSingleton); Listlist = new List (); XmlQueryCardinality card = XmlQueryCardinality.None; foreach (XmlQueryType sourceItem in source) { switch (sourceItem.TypeCode) { case XmlTypeCode.Node: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Comment: case XmlTypeCode.Text: case XmlTypeCode.Element: case XmlTypeCode.Namespace: case XmlTypeCode.Attribute: if (schemaSet == null) { card |= (AddFilteredPrime(list, UntypedDocument, filter) * XmlQueryCardinality.ZeroOrOne) + (AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore); } else { card |= (AddFilteredPrime(list, Document, filter) * XmlQueryCardinality.ZeroOrOne) + (AddFilteredPrime(list, Element, filter) * XmlQueryCardinality.ZeroOrMore); } break; case XmlTypeCode.Document: card |= XmlQueryCardinality.Zero; break; default: Debug.Assert(sourceItem.IsAtomicValue, "missed case for a node"); break; } } // Make sure that cardinality is at least Zero return PrimeProduct(ChoiceType.Create(list), source.Cardinality * card); } private XmlQueryCardinality AddAttributes(List list, XmlSchemaObjectTable attributeUses, XmlSchemaAnyAttribute attributeWildcard, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.Zero; if (attributeWildcard != null) { XmlSchemaType attributeSchemaType = attributeWildcard.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? DatatypeImplementation.UntypedAtomicType : DatatypeImplementation.AnySimpleType; // wildcard will match more then one attribute switch (attributeWildcard.NamespaceList.Type) { case NamespaceList.ListType.Set: foreach (string ns in attributeWildcard.NamespaceList.Enumerate) { card += AddFilteredPrime(list, CreateAttributeType(ns, false, attributeSchemaType), filter); } break; case NamespaceList.ListType.Other: card += AddFilteredPrime(list, CreateAttributeType(attributeWildcard.NamespaceList.Excluded, true, attributeSchemaType), filter); break; case NamespaceList.ListType.Any: default: card += AddFilteredPrime(list, attributeWildcard.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedAttribute : Attribute, filter); break; } // Always optional card *= XmlQueryCardinality.ZeroOrOne; } foreach (XmlSchemaAttribute attribute in attributeUses.Values) { XmlQueryCardinality cardAttr = AddFilteredPrime(list, CreateAttributeType(attribute), filter); if (cardAttr != XmlQueryCardinality.Zero) { Debug.Assert(cardAttr == XmlQueryCardinality.ZeroOrOne || cardAttr == XmlQueryCardinality.One); card += (attribute.Use == XmlSchemaUse.Optional ? XmlQueryCardinality.ZeroOrOne : cardAttr); } } return card; } private XmlQueryType CreateAttributeType(XmlSchemaAttribute attribute) { return ItemType.Create(XmlTypeCode.Attribute, XmlQualifiedNameTest.New(attribute.QualifiedName), attribute.AttributeSchemaType, false); } private XmlQueryType CreateAttributeType(string ns, bool exclude, XmlSchemaType schemaType) { return ItemType.Create(XmlTypeCode.Attribute, XmlQualifiedNameTest.New(ns, exclude), schemaType, false); } private XmlQueryCardinality AddDescendantParticle(List list, Dictionary allTypes, XmlSchemaParticle particle, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.None; XmlSchemaElement element = particle as XmlSchemaElement; if (element != null) { // Single element XmlQueryType elementType = CreateElementType(element); // Add it card = AddFilteredPrime(list, elementType, filter); // Descend card += AddElementOrTextDescendants(list, allTypes, elementType.SchemaType, filter); } else { XmlSchemaAny any = particle as XmlSchemaAny; if (any != null) { // Descendants of any card = AddFilteredPrime(list, Element, filter); } else { XmlSchemaGroupBase group = particle as XmlSchemaGroupBase; if (group.Items.Count != 0) { if (particle is XmlSchemaChoice) { foreach (XmlSchemaParticle p in group.Items) { card |= AddDescendantParticle(list, allTypes, p, filter); } } else { // Sequence and All foreach (XmlSchemaParticle p in group.Items) { card += AddDescendantParticle(list, allTypes, p, filter); } } } } } return card * CardinalityOfParticle(particle); } private XmlQueryCardinality AddElementOrTextDescendants(List list, Dictionary allTypes, XmlSchemaType sourceSchemaType, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.None; if (sourceSchemaType == XmlSchemaComplexType.UntypedAnyType) { card = AddFilteredPrime(list, UntypedElement, filter) * XmlQueryCardinality.ZeroOrMore; card += AddFilteredPrime(list, Text, filter); } else if (sourceSchemaType.Datatype != null) { // Text is the only child node simple content of complext type card = AddFilteredPrime(list, Text, filter, true) * XmlQueryCardinality.ZeroOrOne; } else { // Complex content XmlSchemaComplexType complexType = (XmlSchemaComplexType)sourceSchemaType; if (complexType.QualifiedName.IsEmpty || !allTypes.TryGetValue(complexType.QualifiedName, out card)) { allTypes[complexType.QualifiedName] = XmlQueryCardinality.ZeroOrMore; // take care of left recursion card = AddDescendantParticle(list, allTypes, complexType.ContentTypeParticle, filter); allTypes[complexType.QualifiedName] = card; //set correct card if (complexType.ContentType == XmlSchemaContentType.Mixed) { card += AddFilteredPrime(list, Text, filter); } } } return card; } /// /// Create type based on an XmlSchemaElement /// private XmlQueryType CreateElementType(XmlSchemaElement element) { return ItemType.Create(XmlTypeCode.Element, XmlQualifiedNameTest.New(element.QualifiedName), element.ElementSchemaType, element.IsNillable); } ////// Create type based on a wildcard /// private XmlQueryType CreateElementType(string ns, bool exclude, XmlSchemaType schemaType) { return ItemType.Create(XmlTypeCode.Element, XmlQualifiedNameTest.New(ns, exclude), schemaType, false); } ////// Descend though the content model /// private XmlQueryCardinality AddChildParticle(Listlist, XmlSchemaParticle particle, XmlQueryType filter) { XmlQueryCardinality card = XmlQueryCardinality.None; XmlSchemaElement element = particle as XmlSchemaElement; if (element != null) { // Single element card = AddFilteredPrime(list, CreateElementType(element), filter); } else { // XmlSchemaAny matches more then one element XmlSchemaAny any = particle as XmlSchemaAny; if (any != null) { XmlSchemaType elementSchemaType = any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? XmlSchemaComplexType.UntypedAnyType : XmlSchemaComplexType.AnyType; switch (any.NamespaceList.Type) { case NamespaceList.ListType.Set: // Add a separate type for each namespace in the list foreach (string ns in any.NamespaceList.Enumerate) { card |= AddFilteredPrime(list, CreateElementType(ns, false, elementSchemaType), filter); } break; case NamespaceList.ListType.Other: // Add ##other card = AddFilteredPrime(list, CreateElementType(any.NamespaceList.Excluded, true, elementSchemaType), filter); break; case NamespaceList.ListType.Any: default: // Add ##any card = AddFilteredPrime(list, any.ProcessContentsCorrect == XmlSchemaContentProcessing.Skip ? UntypedElement : Element, filter); break; } } else { // recurse into particle group XmlSchemaGroupBase group = particle as XmlSchemaGroupBase; if (group.Items.Count != 0) { if (particle is XmlSchemaChoice) { foreach (XmlSchemaParticle p in group.Items) { card |= AddChildParticle(list, p, filter); } } else { // Sequence and All foreach (XmlSchemaParticle p in group.Items) { card += AddChildParticle(list, p, filter); } } } } } return card * CardinalityOfParticle(particle); } /// /// Apply filter an item type, add the result to a list, return cardinality /// private XmlQueryCardinality AddFilteredPrime(Listlist, XmlQueryType source, XmlQueryType filter) { return AddFilteredPrime(list, source, filter, false); } private XmlQueryCardinality AddFilteredPrime(List list, XmlQueryType source, XmlQueryType filter, bool forseSingle) { Debug.Assert(source.IsNode && source.IsSingleton); Debug.Assert(filter.IsNode && filter.IsSingleton); // Intersect types XmlQueryType intersection = IntersectItemTypes(source, filter); if ((object)intersection == (object)None) { return XmlQueryCardinality.Zero; } AddItemToChoice(list, intersection); // In the case of forseSingle - filtering all nodes behave as singletones XmlTypeCode typeCode = (forseSingle ? XmlTypeCode.Node : intersection.TypeCode); switch (typeCode) { case XmlTypeCode.Node: case XmlTypeCode.Document: case XmlTypeCode.Element: // Filter can result in empty sequence if filter is not wider then source if (intersection == source) return XmlQueryCardinality.One; else return XmlQueryCardinality.ZeroOrOne; case XmlTypeCode.Attribute: // wildcard attribute matches more then one node if (!intersection.NameTest.IsSingleName) return XmlQueryCardinality.ZeroOrMore; else if (intersection == source) return XmlQueryCardinality.One; else return XmlQueryCardinality.ZeroOrOne; case XmlTypeCode.Comment: case XmlTypeCode.Text: case XmlTypeCode.ProcessingInstruction: case XmlTypeCode.Namespace: return XmlQueryCardinality.ZeroOrMore; default: Debug.Assert(false); return XmlQueryCardinality.None; } } /// /// Construct the intersection of two lists of prime XmlQueryTypes. /// private XmlQueryType IntersectItemTypes(XmlQueryType left, XmlQueryType right) { Debug.Assert(left.Count == 1 && left.IsSingleton, "left should be an item"); Debug.Assert(right.Count == 1 && right.IsSingleton, "right should be an item"); if (left.TypeCode == right.TypeCode && (left.NodeKinds & (XmlNodeKindFlags.Document | XmlNodeKindFlags.Element | XmlNodeKindFlags.Attribute)) != 0) { if (left.TypeCode == XmlTypeCode.Node) { return left; } // Intersect name tests XmlQualifiedNameTest nameTest = left.NameTest.Intersect(right.NameTest); // Intersect types XmlSchemaType type = XmlSchemaType.IsDerivedFrom(left.SchemaType, right.SchemaType, /* exept:*/XmlSchemaDerivationMethod.Empty) ? left.SchemaType : XmlSchemaType.IsDerivedFrom(right.SchemaType, left.SchemaType, /* exept:*/XmlSchemaDerivationMethod.Empty) ? right.SchemaType : null; bool isNillable = left.IsNillable && right.IsNillable; if ((object)nameTest == (object)left.NameTest && type == left.SchemaType && isNillable == left.IsNillable) { // left is a subtype of right return left return left; } else if ((object)nameTest == (object)right.NameTest && type == right.SchemaType && isNillable == right.IsNillable) { // right is a subtype of left return right return right; } else if (nameTest != null && type != null) { // create a new type return ItemType.Create(left.TypeCode, nameTest, type, isNillable); } } else if (left.IsSubtypeOf(right)) { // left is a subset of right, so left is in the intersection return left; } else if (right.IsSubtypeOf(left)) { // right is a subset of left, so right is in the intersection return right; } return None; } ////// Convert particle occurrance range into cardinality /// private XmlQueryCardinality CardinalityOfParticle(XmlSchemaParticle particle) { if (particle.MinOccurs == decimal.Zero) { if (particle.MaxOccurs == decimal.Zero) { return XmlQueryCardinality.Zero; } else if (particle.MaxOccurs == decimal.One) { return XmlQueryCardinality.ZeroOrOne; } else { return XmlQueryCardinality.ZeroOrMore; } } else { if (particle.MaxOccurs == decimal.One) { return XmlQueryCardinality.One; } else { return XmlQueryCardinality.OneOrMore; } } } #endif } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SqlTriggerContext.cs
- IndexedGlyphRun.cs
- ListViewGroupItemCollection.cs
- PriorityQueue.cs
- ClientTarget.cs
- RootBuilder.cs
- TraceContextEventArgs.cs
- TextFormatterContext.cs
- UserControl.cs
- Condition.cs
- RoleManagerSection.cs
- ActivityValidationServices.cs
- ToolStripDesignerAvailabilityAttribute.cs
- AppDomainFactory.cs
- ToolstripProfessionalRenderer.cs
- ConfigurationManagerHelperFactory.cs
- PageRequestManager.cs
- ToolStripItem.cs
- ParameterEditorUserControl.cs
- IisTraceListener.cs
- FilteredAttributeCollection.cs
- ConfigurationManagerHelper.cs
- SiteMapDataSourceView.cs
- MouseOverProperty.cs
- ImageConverter.cs
- TriggerBase.cs
- ProcessProtocolHandler.cs
- PtsHelper.cs
- VarRefManager.cs
- SelectiveScrollingGrid.cs
- DataColumn.cs
- ExtendedPropertyCollection.cs
- Matrix3D.cs
- Automation.cs
- XmlHelper.cs
- AspCompat.cs
- DesignerAdapterUtil.cs
- PhonemeConverter.cs
- KeyedQueue.cs
- OperatorExpressions.cs
- GeometryModel3D.cs
- Stackframe.cs
- SessionStateSection.cs
- SR.cs
- SQLMoneyStorage.cs
- TypeUtil.cs
- SqlDataSource.cs
- PageThemeParser.cs
- XmlUtil.cs
- DbModificationClause.cs
- ResumeStoryboard.cs
- ImageListImage.cs
- TempFiles.cs
- Pen.cs
- Normalization.cs
- DefaultTextStore.cs
- XmlAttribute.cs
- BitConverter.cs
- XamlParser.cs
- XsdValidatingReader.cs
- StagingAreaInputItem.cs
- PictureBox.cs
- InternalControlCollection.cs
- ListItem.cs
- DesignerAutoFormat.cs
- RevocationPoint.cs
- SliderAutomationPeer.cs
- DocComment.cs
- DirtyTextRange.cs
- ChangeInterceptorAttribute.cs
- MailDefinitionBodyFileNameEditor.cs
- Logging.cs
- NotifyIcon.cs
- FileNameEditor.cs
- NullableFloatSumAggregationOperator.cs
- StringSource.cs
- Window.cs
- safex509handles.cs
- BooleanStorage.cs
- XmlSerializerSection.cs
- BitArray.cs
- XmlSchemaSimpleType.cs
- XmlSchemaObjectCollection.cs
- HandleRef.cs
- Documentation.cs
- Int32CollectionValueSerializer.cs
- ProxyWebPartManager.cs
- RegexTree.cs
- AttributeQuery.cs
- StylusDevice.cs
- DataBindingExpressionBuilder.cs
- DropShadowBitmapEffect.cs
- UserPreferenceChangedEventArgs.cs
- CodeNamespaceImportCollection.cs
- WebPartConnectionsCloseVerb.cs
- WasEndpointConfigContainer.cs
- PrePrepareMethodAttribute.cs
- ContainerParagraph.cs
- EntityContainerEntitySet.cs
- FrameworkName.cs