We need you! We're working hard on the next version of Developer Fusion - Let us know what you think we should be up to!

The Labs \ Source Viewer \ SSCLI \ System.Xml.Serialization \ AccessorMapping

  1. //------------------------------------------------------------------------------
  2. // <copyright file="Mappings.cs" company="Microsoft">
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. // </copyright>
  14. // <owner current="true" primary="true">ElenaK</owner>
  15. //------------------------------------------------------------------------------
  16. namespace System.Xml.Serialization
  17. {
  18.    
  19.     using System.Reflection;
  20.     using System.Collections;
  21.     using System.Xml.Schema;
  22.     using System;
  23.     using System.Text;
  24.     using System.ComponentModel;
  25.     using System.Xml;
  26.     using System.CodeDom.Compiler;
  27.    
  28.     // These classes represent a mapping between classes and a particular XML format.
  29.     // There are two class of mapping information: accessors (such as elements and
  30.     // attributes), and mappings (which specify the type of an accessor).
  31.    
  32.     internal abstract class Accessor
  33.     {
  34.         string name;
  35.         object defaultValue = null;
  36.         string ns;
  37.         TypeMapping mapping;
  38.         bool any;
  39.         string anyNs;
  40.         bool topLevelInSchema;
  41.         bool isFixed;
  42.         bool isOptional;
  43.         XmlSchemaForm form = XmlSchemaForm.None;
  44.        
  45.         internal Accessor()
  46.         {
  47.         }
  48.        
  49.         internal TypeMapping Mapping {
  50.             get { return mapping; }
  51.             set { mapping = value; }
  52.         }
  53.        
  54.         internal object Default {
  55.             get { return defaultValue; }
  56.             set { defaultValue = value; }
  57.         }
  58.        
  59.         internal bool HasDefault {
  60.             get { return defaultValue != null && defaultValue != DBNull.Value; }
  61.         }
  62.        
  63.         internal virtual string Name {
  64.             get { return name == null ? string.Empty : name; }
  65.             set { name = value; }
  66.         }
  67.        
  68.         internal bool Any {
  69.             get { return any; }
  70.             set { any = value; }
  71.         }
  72.        
  73.         internal string AnyNamespaces {
  74.             get { return anyNs; }
  75.             set { anyNs = value; }
  76.         }
  77.        
  78.         internal string Namespace {
  79.             get { return ns; }
  80.             set { ns = value; }
  81.         }
  82.        
  83.         internal XmlSchemaForm Form {
  84.             get { return form; }
  85.             set { form = value; }
  86.         }
  87.        
  88.         internal bool IsFixed {
  89.             get { return isFixed; }
  90.             set { isFixed = value; }
  91.         }
  92.        
  93.         internal bool IsOptional {
  94.             get { return isOptional; }
  95.             set { isOptional = value; }
  96.         }
  97.        
  98.         internal bool IsTopLevelInSchema {
  99.             get { return topLevelInSchema; }
  100.             set { topLevelInSchema = value; }
  101.         }
  102.        
  103.         static internal string EscapeName(string name)
  104.         {
  105.             if (name == null || name.Length == 0)
  106.                 return name;
  107.             return XmlConvert.EncodeLocalName(name);
  108.         }
  109.        
  110.         static internal string EscapeQName(string name)
  111.         {
  112.             if (name == null || name.Length == 0)
  113.                 return name;
  114.             int colon = name.LastIndexOf(':');
  115.             if (colon < 0)
  116.                 return XmlConvert.EncodeLocalName(name);
  117.             else {
  118.                 if (colon == 0 || colon == name.Length - 1)
  119.                     throw new ArgumentException(Res.GetString(Res.Xml_InvalidNameChars, name), "name");
  120.                 return new XmlQualifiedName(XmlConvert.EncodeLocalName(name.Substring(colon + 1)), XmlConvert.EncodeLocalName(name.Substring(0, colon))).ToString();
  121.             }
  122.         }
  123.        
  124.         static internal string UnescapeName(string name)
  125.         {
  126.             return XmlConvert.DecodeName(name);
  127.         }
  128.        
  129.         internal string ToString(string defaultNs)
  130.         {
  131.             if (Any) {
  132.                 return (Namespace == null ? "##any" : Namespace) + ":" + Name;
  133.             }
  134.             else {
  135.                 return Namespace == defaultNs ? Name : Namespace + ":" + Name;
  136.             }
  137.         }
  138.     }
  139.    
  140.     internal class ElementAccessor : Accessor
  141.     {
  142.         bool nullable;
  143.         bool isSoap;
  144.         bool unbounded = false;
  145.        
  146.         internal bool IsSoap {
  147.             get { return isSoap; }
  148.             set { isSoap = value; }
  149.         }
  150.        
  151.         internal bool IsNullable {
  152.             get { return nullable; }
  153.             set { nullable = value; }
  154.         }
  155.        
  156.         internal bool IsUnbounded {
  157.             get { return unbounded; }
  158.             set { unbounded = value; }
  159.         }
  160.        
  161.         internal ElementAccessor Clone()
  162.         {
  163.             ElementAccessor newAccessor = new ElementAccessor();
  164.             newAccessor.nullable = this.nullable;
  165.             newAccessor.IsTopLevelInSchema = this.IsTopLevelInSchema;
  166.             newAccessor.Form = this.Form;
  167.             newAccessor.isSoap = this.isSoap;
  168.             newAccessor.Name = this.Name;
  169.             newAccessor.Default = this.Default;
  170.             newAccessor.Namespace = this.Namespace;
  171.             newAccessor.Mapping = this.Mapping;
  172.             newAccessor.Any = this.Any;
  173.            
  174.             return newAccessor;
  175.         }
  176.     }
  177.    
  178.     internal class ChoiceIdentifierAccessor : Accessor
  179.     {
  180.         string memberName;
  181.         string[] memberIds;
  182.        
  183.         internal string MemberName {
  184.             get { return memberName; }
  185.             set { memberName = value; }
  186.         }
  187.        
  188.         internal string[] MemberIds {
  189.             get { return memberIds; }
  190.             set { memberIds = value; }
  191.         }
  192.        
  193.     }
  194.    
  195.     internal class TextAccessor : Accessor
  196.     {
  197.     }
  198.    
  199.     internal class XmlnsAccessor : Accessor
  200.     {
  201.     }
  202.    
  203.     internal class AttributeAccessor : Accessor
  204.     {
  205.         bool isSpecial;
  206.         bool isList;
  207.        
  208.         internal bool IsSpecialXmlNamespace {
  209.             get { return isSpecial; }
  210.         }
  211.        
  212.         internal bool IsList {
  213.             get { return isList; }
  214.             set { isList = value; }
  215.         }
  216.        
  217.         internal void CheckSpecial()
  218.         {
  219.             int colon = Name.LastIndexOf(':');
  220.            
  221.             if (colon >= 0) {
  222.                 if (!Name.StartsWith("xml:", StringComparison.Ordinal)) {
  223.                     throw new InvalidOperationException(Res.GetString(Res.Xml_InvalidNameChars, Name));
  224.                 }
  225.                 Name = Name.Substring("xml:".Length);
  226.                 Namespace = XmlReservedNs.NsXml;
  227.                 isSpecial = true;
  228.             }
  229.             else {
  230.                 if (Namespace == XmlReservedNs.NsXml) {
  231.                     isSpecial = true;
  232.                 }
  233.                 else {
  234.                     isSpecial = false;
  235.                 }
  236.             }
  237.             if (isSpecial) {
  238.                 Form = XmlSchemaForm.Qualified;
  239.             }
  240.         }
  241.     }
  242.    
  243.     internal abstract class Mapping
  244.     {
  245.         bool isSoap;
  246.        
  247.         internal Mapping()
  248.         {
  249.         }
  250.        
  251.         internal bool IsSoap {
  252.             get { return isSoap; }
  253.             set { isSoap = value; }
  254.         }
  255.     }
  256.    
  257.     internal abstract class TypeMapping : Mapping
  258.     {
  259.         TypeDesc typeDesc;
  260.         string typeNs;
  261.         string typeName;
  262.         bool referencedByElement;
  263.         bool referencedByTopLevelElement;
  264.         bool includeInSchema = true;
  265.         bool reference = false;
  266.        
  267.         internal bool ReferencedByTopLevelElement {
  268.             get { return referencedByTopLevelElement; }
  269.             set { referencedByTopLevelElement = value; }
  270.         }
  271.        
  272.         internal bool ReferencedByElement {
  273.             get { return referencedByElement || referencedByTopLevelElement; }
  274.             set { referencedByElement = value; }
  275.         }
  276.         internal string Namespace {
  277.             get { return typeNs; }
  278.             set { typeNs = value; }
  279.         }
  280.        
  281.         internal string TypeName {
  282.             get { return typeName; }
  283.             set { typeName = value; }
  284.         }
  285.        
  286.         internal TypeDesc TypeDesc {
  287.             get { return typeDesc; }
  288.             set { typeDesc = value; }
  289.         }
  290.        
  291.         internal bool IncludeInSchema {
  292.             get { return includeInSchema; }
  293.             set { includeInSchema = value; }
  294.         }
  295.        
  296.         internal virtual bool IsList {
  297.             get { return false; }
  298.             set { }
  299.         }
  300.        
  301.         internal bool IsReference {
  302.             get { return reference; }
  303.             set { reference = value; }
  304.         }
  305.        
  306.         internal bool IsAnonymousType {
  307.             get { return typeName == null || typeName.Length == 0; }
  308.         }
  309.        
  310.         internal virtual string DefaultElementName {
  311.             get { return IsAnonymousType ? XmlConvert.EncodeLocalName(typeDesc.Name) : typeName; }
  312.         }
  313.     }
  314.    
  315.     internal class PrimitiveMapping : TypeMapping
  316.     {
  317.         bool isList;
  318.        
  319.         internal override bool IsList {
  320.             get { return isList; }
  321.             set { isList = value; }
  322.         }
  323.     }
  324.    
  325.     internal class NullableMapping : TypeMapping
  326.     {
  327.         TypeMapping baseMapping;
  328.        
  329.         internal TypeMapping BaseMapping {
  330.             get { return baseMapping; }
  331.             set { baseMapping = value; }
  332.         }
  333.        
  334.         internal override string DefaultElementName {
  335.             get { return BaseMapping.DefaultElementName; }
  336.         }
  337.     }
  338.    
  339.     internal class ArrayMapping : TypeMapping
  340.     {
  341.         ElementAccessor[] elements;
  342.         ElementAccessor[] sortedElements;
  343.         ArrayMapping next;
  344.         StructMapping topLevelMapping;
  345.        
  346.         internal ElementAccessor[] Elements {
  347.             get { return elements; }
  348.             set {
  349.                 elements = value;
  350.                 sortedElements = null;
  351.             }
  352.         }
  353.        
  354.         internal ElementAccessor[] ElementsSortedByDerivation {
  355.             get {
  356.                 if (sortedElements != null)
  357.                     return sortedElements;
  358.                 if (elements == null)
  359.                     return null;
  360.                 sortedElements = new ElementAccessor[elements.Length];
  361.                 Array.Copy(elements, 0, sortedElements, 0, elements.Length);
  362.                 AccessorMapping.SortMostToLeastDerived(sortedElements);
  363.                 return sortedElements;
  364.             }
  365.         }
  366.        
  367.        
  368.         internal ArrayMapping Next {
  369.             get { return next; }
  370.             set { next = value; }
  371.         }
  372.        
  373.         internal StructMapping TopLevelMapping {
  374.             get { return topLevelMapping; }
  375.             set { topLevelMapping = value; }
  376.         }
  377.     }
  378.    
  379.     internal class EnumMapping : PrimitiveMapping
  380.     {
  381.         ConstantMapping[] constants;
  382.         bool isFlags;
  383.        
  384.         internal bool IsFlags {
  385.             get { return isFlags; }
  386.             set { isFlags = value; }
  387.         }
  388.        
  389.         internal ConstantMapping[] Constants {
  390.             get { return constants; }
  391.             set { constants = value; }
  392.         }
  393.     }
  394.    
  395.     internal class ConstantMapping : Mapping
  396.     {
  397.         string xmlName;
  398.         string name;
  399.         long value;
  400.        
  401.         internal string XmlName {
  402.             get { return xmlName == null ? string.Empty : xmlName; }
  403.             set { xmlName = value; }
  404.         }
  405.        
  406.         internal string Name {
  407.             get { return name == null ? string.Empty : name; }
  408.             set { this.name = value; }
  409.         }
  410.        
  411.         internal long Value {
  412.             get { return value; }
  413.             set { this.value = value; }
  414.         }
  415.     }
  416.    
  417.     internal class StructMapping : TypeMapping, INameScope
  418.     {
  419.         MemberMapping[] members;
  420.         StructMapping baseMapping;
  421.         StructMapping derivedMappings;
  422.         StructMapping nextDerivedMapping;
  423.         MemberMapping xmlnsMember = null;
  424.         bool hasSimpleContent;
  425.         bool openModel;
  426.         NameTable elements;
  427.         NameTable attributes;
  428.         CodeIdentifiers scope;
  429.        
  430.         internal StructMapping BaseMapping {
  431.             get { return baseMapping; }
  432.             set {
  433.                 baseMapping = value;
  434.                 if (!IsAnonymousType && baseMapping != null) {
  435.                     nextDerivedMapping = baseMapping.derivedMappings;
  436.                     baseMapping.derivedMappings = this;
  437.                 }
  438.             }
  439.         }
  440.        
  441.         internal StructMapping DerivedMappings {
  442.             get { return derivedMappings; }
  443.         }
  444.        
  445.         internal NameTable LocalElements {
  446.             get {
  447.                 if (elements == null)
  448.                     elements = new NameTable();
  449.                 return elements;
  450.             }
  451.         }
  452.         internal NameTable LocalAttributes {
  453.             get {
  454.                 if (attributes == null)
  455.                     attributes = new NameTable();
  456.                 return attributes;
  457.             }
  458.         }
  459.         object INameScope.this[string name, string ns]
  460.         {
  461.             get {
  462.                 object named = LocalElements[name, ns];
  463.                 if (named != null)
  464.                     return named;
  465.                 if (baseMapping != null)
  466.                     return ((INameScope)baseMapping)[name, ns];
  467.                 return null;
  468.             }
  469.             set { LocalElements[name, ns] = value; }
  470.         }
  471.         internal StructMapping NextDerivedMapping {
  472.             get { return nextDerivedMapping; }
  473.         }
  474.        
  475.         internal bool HasSimpleContent {
  476.             get { return hasSimpleContent; }
  477.         }
  478.        
  479.         internal bool HasXmlnsMember {
  480.             get {
  481.                 StructMapping mapping = this;
  482.                 while (mapping != null) {
  483.                     if (mapping.XmlnsMember != null)
  484.                         return true;
  485.                     mapping = mapping.BaseMapping;
  486.                 }
  487.                 return false;
  488.             }
  489.         }
  490.        
  491.         internal MemberMapping[] Members {
  492.             get { return members; }
  493.             set { members = value; }
  494.         }
  495.        
  496.         internal MemberMapping XmlnsMember {
  497.             get { return xmlnsMember; }
  498.             set { xmlnsMember = value; }
  499.         }
  500.        
  501.         internal bool IsOpenModel {
  502.             get { return openModel; }
  503.             set { openModel = value; }
  504.         }
  505.        
  506.         internal CodeIdentifiers Scope {
  507.             get {
  508.                 if (scope == null)
  509.                     scope = new CodeIdentifiers();
  510.                 return scope;
  511.             }
  512.             set { scope = value; }
  513.         }
  514.        
  515.         internal MemberMapping FindDeclaringMapping(MemberMapping member, out StructMapping declaringMapping, string parent)
  516.         {
  517.             declaringMapping = null;
  518.             if (BaseMapping != null) {
  519.                 MemberMapping baseMember = BaseMapping.FindDeclaringMapping(member, out declaringMapping, parent);
  520.                 if (baseMember != null)
  521.                     return baseMember;
  522.             }
  523.             if (members == null)
  524.                 return null;
  525.            
  526.             for (int i = 0; i < members.Length; i++) {
  527.                 if (members[i].Name == member.Name) {
  528.                     if (members[i].TypeDesc != member.TypeDesc)
  529.                         throw new InvalidOperationException(Res.GetString(Res.XmlHiddenMember, parent, member.Name, member.TypeDesc.FullName, this.TypeName, members[i].Name, members[i].TypeDesc.FullName));
  530.                     else if (!members[i].Match(member)) {
  531.                         throw new InvalidOperationException(Res.GetString(Res.XmlInvalidXmlOverride, parent, member.Name, this.TypeName, members[i].Name));
  532.                     }
  533.                     declaringMapping = this;
  534.                     return members[i];
  535.                 }
  536.             }
  537.             return null;
  538.         }
  539.         internal bool Declares(MemberMapping member, string parent)
  540.         {
  541.             StructMapping m;
  542.             return (FindDeclaringMapping(member, out m, parent) != null);
  543.         }
  544.        
  545.         internal void SetContentModel(TextAccessor text, bool hasElements)
  546.         {
  547.             if (BaseMapping == null || BaseMapping.TypeDesc.IsRoot) {
  548.                 hasSimpleContent = !hasElements && text != null && !text.Mapping.IsList;
  549.             }
  550.             else if (BaseMapping.HasSimpleContent) {
  551.                 if (text != null || hasElements) {
  552.                     // we can only extent a simleContent type with attributes
  553.                     throw new InvalidOperationException(Res.GetString(Res.XmlIllegalSimpleContentExtension, TypeDesc.FullName, BaseMapping.TypeDesc.FullName));
  554.                 }
  555.                 else {
  556.                     hasSimpleContent = true;
  557.                 }
  558.             }
  559.             else {
  560.                 hasSimpleContent = false;
  561.             }
  562.             if (!hasSimpleContent && text != null && !text.Mapping.TypeDesc.CanBeTextValue) {
  563.                 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalTypedTextAttribute, TypeDesc.FullName, text.Name, text.Mapping.TypeDesc.FullName));
  564.             }
  565.         }
  566.        
  567.         internal bool HasElements {
  568.             get { return elements != null && elements.Values.Count > 0; }
  569.         }
  570.        
  571.         internal bool HasExplicitSequence()
  572.         {
  573.             if (members != null) {
  574.                 for (int i = 0; i < members.Length; i++) {
  575.                     if (members[i].IsParticle && members[i].IsSequence) {
  576.                         return true;
  577.                     }
  578.                 }
  579.             }
  580.             return (baseMapping != null && baseMapping.HasExplicitSequence());
  581.         }
  582.        
  583.         internal void SetSequence()
  584.         {
  585.             for (int i = 0; i < members.Length; i++) {
  586.                 if (members[i].IsParticle) {
  587.                     members[i].SequenceId = i;
  588.                 }
  589.             }
  590.             if (baseMapping != null) {
  591.                 baseMapping.SetSequence();
  592.             }
  593.         }
  594.     }
  595.    
  596.     internal abstract class AccessorMapping : Mapping
  597.     {
  598.         TypeDesc typeDesc;
  599.         AttributeAccessor attribute;
  600.         ElementAccessor[] elements;
  601.         ElementAccessor[] sortedElements;
  602.         TextAccessor text;
  603.         ChoiceIdentifierAccessor choiceIdentifier;
  604.         XmlnsAccessor xmlns;
  605.         bool ignore;
  606.        
  607.         internal bool IsAttribute {
  608.             get { return attribute != null; }
  609.         }
  610.        
  611.         internal bool IsText {
  612.             get { return text != null && (elements == null || elements.Length == 0); }
  613.         }
  614.        
  615.         internal bool IsParticle {
  616.             get { return (elements != null && elements.Length > 0); }
  617.         }
  618.        
  619.         internal TypeDesc TypeDesc {
  620.             get { return typeDesc; }
  621.             set { typeDesc = value; }
  622.         }
  623.        
  624.         internal AttributeAccessor Attribute {
  625.             get { return attribute; }
  626.             set { attribute = value; }
  627.         }
  628.        
  629.         internal ElementAccessor[] Elements {
  630.             get { return elements; }
  631.             set {
  632.                 elements = value;
  633.                 sortedElements = null;
  634.             }
  635.         }
  636.        
  637.         static internal void SortMostToLeastDerived(ElementAccessor[] elements)
  638.         {
  639.             Array.Sort(elements, new AccessorComparer());
  640.         }
  641.        
  642.         internal class AccessorComparer : IComparer
  643.         {
  644.             public int Compare(object o1, object o2)
  645.             {
  646.                 if (o1 == o2)
  647.                     return 0;
  648.                 Accessor a1 = (Accessor)o1;
  649.                 Accessor a2 = (Accessor)o2;
  650.                 int w1 = a1.Mapping.TypeDesc.Weight;
  651.                 int w2 = a2.Mapping.TypeDesc.Weight;
  652.                 if (w1 == w2)
  653.                     return 0;
  654.                 if (w1 < w2)
  655.                     return 1;
  656.                 return -1;
  657.             }
  658.         }
  659.        
  660.         internal ElementAccessor[] ElementsSortedByDerivation {
  661.             get {
  662.                 if (sortedElements != null)
  663.                     return sortedElements;
  664.                 if (elements == null)
  665.                     return null;
  666.                 sortedElements = new ElementAccessor[elements.Length];
  667.                 Array.Copy(elements, 0, sortedElements, 0, elements.Length);
  668.                 SortMostToLeastDerived(sortedElements);
  669.                 return sortedElements;
  670.             }
  671.         }
  672.        
  673.         internal TextAccessor Text {
  674.             get { return text; }
  675.             set { text = value; }
  676.         }
  677.        
  678.         internal ChoiceIdentifierAccessor ChoiceIdentifier {
  679.             get { return choiceIdentifier; }
  680.             set { choiceIdentifier = value; }
  681.         }
  682.        
  683.         internal XmlnsAccessor Xmlns {
  684.             get { return xmlns; }
  685.             set { xmlns = value; }
  686.         }
  687.        
  688.         internal bool Ignore {
  689.             get { return ignore; }
  690.             set { ignore = value; }
  691.         }
  692.        
  693.         internal Accessor Accessor {
  694.             get {
  695.                 if (xmlns != null)
  696.                     return xmlns;
  697.                 if (attribute != null)
  698.                     return attribute;
  699.                 if (elements != null && elements.Length > 0)
  700.                     return elements[0];
  701.                 return text;
  702.             }
  703.         }
  704.        
  705.         static bool IsNeedNullableMember(ElementAccessor element)
  706.         {
  707.             if (element.Mapping is ArrayMapping) {
  708.                 ArrayMapping arrayMapping = (ArrayMapping)element.Mapping;
  709.                 if (arrayMapping.Elements != null && arrayMapping.Elements.Length == 1) {
  710.                     return IsNeedNullableMember(arrayMapping.Elements[0]);
  711.                 }
  712.                 return false;
  713.             }
  714.             else {
  715.                 return element.IsNullable && element.Mapping.TypeDesc.IsValueType;
  716.             }
  717.         }
  718.        
  719.         internal bool IsNeedNullable {
  720.             get {
  721.                 if (xmlns != null)
  722.                     return false;
  723.                 if (attribute != null)
  724.                     return false;
  725.                 if (elements != null && elements.Length == 1) {
  726.                     return IsNeedNullableMember(elements[0]);
  727.                 }
  728.                 return false;
  729.             }
  730.         }
  731.        
  732.         static internal bool ElementsMatch(ElementAccessor[] a, ElementAccessor[] b)
  733.         {
  734.             if (a == null) {
  735.                 if (b == null)
  736.                     return true;
  737.                 return false;
  738.             }
  739.             if (b == null)
  740.                 return false;
  741.             if (a.Length != b.Length)
  742.                 return false;
  743.             for (int i = 0; i < a.Length; i++) {
  744.                 if (a[i].Name != b[i].Name || a[i].Namespace != b[i].Namespace || a[i].Form != b[i].Form || a[i].IsNullable != b[i].IsNullable)
  745.                     return false;
  746.             }
  747.             return true;
  748.         }
  749.        
  750.         internal bool Match(AccessorMapping mapping)
  751.         {
  752.             if (Elements != null && Elements.Length > 0) {
  753.                 if (!ElementsMatch(Elements, mapping.Elements)) {
  754.                     return false;
  755.                 }
  756.                 if (Text == null) {
  757.                     return (mapping.Text == null);
  758.                 }
  759.             }
  760.     &