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

  1. //------------------------------------------------------------------------------
  2. // <copyright file="SoapSchemaExporter.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;
  20.     using System.Collections;
  21.     using System.Xml.Schema;
  22.     using System.Xml;
  23.     using System.ComponentModel;
  24.     using System.Diagnostics;
  25.    
  26.     /// <include file='doc\SoapSchemaExporter.uex' path='docs/doc[@for="SoapSchemaExporter"]/*' />
  27.     /// <internalonly/>
  28.     public class SoapSchemaExporter
  29.     {
  30.         internal const XmlSchemaForm elementFormDefault = XmlSchemaForm.Qualified;
  31.         XmlSchemas schemas;
  32.         Hashtable types = new Hashtable();
  33.         // StructMapping/EnumMapping -> XmlSchemaComplexType/XmlSchemaSimpleType
  34.         bool exportedRoot;
  35.         TypeScope scope;
  36.         XmlDocument document;
  37.        
  38.         static XmlQualifiedName ArrayQName = new XmlQualifiedName(Soap.Array, Soap.Encoding);
  39.         static XmlQualifiedName ArrayTypeQName = new XmlQualifiedName(Soap.ArrayType, Soap.Encoding);
  40.        
  41.         /// <include file='doc\SoapSchemaExporter.uex' path='docs/doc[@for="SoapSchemaExporter.SoapSchemaExporter"]/*' />
  42.         /// <devdoc>
  43.         /// <para>[To be supplied.]</para>
  44.         /// </devdoc>
  45.         public SoapSchemaExporter(XmlSchemas schemas)
  46.         {
  47.             this.schemas = schemas;
  48.         }
  49.        
  50.         /// <include file='doc\SoapSchemaExporter.uex' path='docs/doc[@for="SoapSchemaExporter.ExportTypeMapping"]/*' />
  51.         /// <devdoc>
  52.         /// <para>[To be supplied.]</para>
  53.         /// </devdoc>
  54.         public void ExportTypeMapping(XmlTypeMapping xmlTypeMapping)
  55.         {
  56.             CheckScope(xmlTypeMapping.Scope);
  57.             ExportTypeMapping(xmlTypeMapping.Mapping, null);
  58.         }
  59.        
  60.         /// <include file='doc\SoapSchemaExporter.uex' path='docs/doc[@for="SoapSchemaExporter.ExportMembersMapping"]/*' />
  61.         /// <devdoc>
  62.         /// <para>[To be supplied.]</para>
  63.         /// </devdoc>
  64.         public void ExportMembersMapping(XmlMembersMapping xmlMembersMapping)
  65.         {
  66.             ExportMembersMapping(xmlMembersMapping, false);
  67.         }
  68.        
  69.         /// <include file='doc\SoapSchemaExporter.uex' path='docs/doc[@for="SoapSchemaExporter.ExportMembersMapping1"]/*' />
  70.         /// <devdoc>
  71.         /// <para>[To be supplied.]</para>
  72.         /// </devdoc>
  73.         public void ExportMembersMapping(XmlMembersMapping xmlMembersMapping, bool exportEnclosingType)
  74.         {
  75.             CheckScope(xmlMembersMapping.Scope);
  76.             MembersMapping membersMapping = (MembersMapping)xmlMembersMapping.Accessor.Mapping;
  77.             if (exportEnclosingType) {
  78.                 ExportTypeMapping(membersMapping, null);
  79.             }
  80.             else {
  81.                 foreach (MemberMapping memberMapping in membersMapping.Members) {
  82.                     if (memberMapping.Elements.Length > 0)
  83.                         ExportTypeMapping(memberMapping.Elements[0].Mapping, null);
  84.                 }
  85.             }
  86.         }
  87.        
  88.         void CheckScope(TypeScope scope)
  89.         {
  90.             if (this.scope == null) {
  91.                 this.scope = scope;
  92.             }
  93.             else if (this.scope != scope) {
  94.                 throw new InvalidOperationException(Res.GetString(Res.XmlMappingsScopeMismatch));
  95.             }
  96.         }
  97.        
  98.         internal XmlDocument Document {
  99.             get {
  100.                 if (document == null)
  101.                     document = new XmlDocument();
  102.                 return document;
  103.             }
  104.         }
  105.        
  106.         void CheckForDuplicateType(string newTypeName, string newNamespace)
  107.         {
  108.             XmlSchema schema = schemas[newNamespace];
  109.             if (schema != null) {
  110.                 foreach (XmlSchemaObject o in schema.Items) {
  111.                     XmlSchemaType type = o as XmlSchemaType;
  112.                     if (type != null && type.Name == newTypeName)
  113.                         throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateTypeName, newTypeName, newNamespace));
  114.                    
  115.                 }
  116.             }
  117.         }
  118.        
  119.         void AddSchemaItem(XmlSchemaObject item, string ns, string referencingNs)
  120.         {
  121.             if (!SchemaContainsItem(item, ns)) {
  122.                 XmlSchema schema = schemas[ns];
  123.                 if (schema == null) {
  124.                     schema = new XmlSchema();
  125.                     schema.TargetNamespace = ns == null || ns.Length == 0 ? null : ns;
  126.                    
  127.                     #pragma warning disable 429 // unreachable code detected: elementFormDefault is const so it will never be Unqualified
  128.                     schema.ElementFormDefault = elementFormDefault == XmlSchemaForm.Unqualified ? XmlSchemaForm.None : elementFormDefault;
  129.                     #pragma warning restore 429
  130.                     schemas.Add(schema);
  131.                 }
  132.                 schema.Items.Add(item);
  133.             }
  134.             if (referencingNs != null)
  135.                 AddSchemaImport(ns, referencingNs);
  136.         }
  137.        
  138.         void AddSchemaImport(string ns, string referencingNs)
  139.         {
  140.             if (referencingNs == null || ns == null)
  141.                 return;
  142.             if (ns == referencingNs)
  143.                 return;
  144.             XmlSchema schema = schemas[referencingNs];
  145.             if (schema == null)
  146.                 throw new InvalidOperationException(Res.GetString(Res.XmlMissingSchema, referencingNs));
  147.             if (ns != null && ns.Length > 0 && FindImport(schema, ns) == null) {
  148.                 XmlSchemaImport import = new XmlSchemaImport();
  149.                 import.Namespace = ns;
  150.                 schema.Includes.Add(import);
  151.             }
  152.         }
  153.        
  154.         bool SchemaContainsItem(XmlSchemaObject item, string ns)
  155.         {
  156.             XmlSchema schema = schemas[ns];
  157.             if (schema != null) {
  158.                 return schema.Items.Contains(item);
  159.             }
  160.             return false;
  161.         }
  162.        
  163.         XmlSchemaImport FindImport(XmlSchema schema, string ns)
  164.         {
  165.             foreach (object item in schema.Includes) {
  166.                 if (item is XmlSchemaImport) {
  167.                     XmlSchemaImport import = (XmlSchemaImport)item;
  168.                     if (import.Namespace == ns) {
  169.                         return import;
  170.                     }
  171.                 }
  172.             }
  173.             return null;
  174.         }
  175.        
  176.         XmlQualifiedName ExportTypeMapping(TypeMapping mapping, string ns)
  177.         {
  178.             if (mapping is ArrayMapping)
  179.                 return ExportArrayMapping((ArrayMapping)mapping, ns);
  180.             else if (mapping is EnumMapping)
  181.                 return ExportEnumMapping((EnumMapping)mapping, ns);
  182.             else if (mapping is PrimitiveMapping) {
  183.                 PrimitiveMapping pm = (PrimitiveMapping)mapping;
  184.                 if (pm.TypeDesc.IsXsdType) {
  185.                     return ExportPrimitiveMapping(pm);
  186.                 }
  187.                 else {
  188.                     return ExportNonXsdPrimitiveMapping(pm, ns);
  189.                 }
  190.             }
  191.             else if (mapping is StructMapping)
  192.                 return ExportStructMapping((StructMapping)mapping, ns);
  193.             else if (mapping is NullableMapping)
  194.                 return ExportTypeMapping(((NullableMapping)mapping).BaseMapping, ns);
  195.             else if (mapping is MembersMapping)
  196.                 return ExportMembersMapping((MembersMapping)mapping, ns);
  197.             else
  198.                 throw new ArgumentException(Res.GetString(Res.XmlInternalError), "mapping");
  199.         }
  200.        
  201.         XmlQualifiedName ExportNonXsdPrimitiveMapping(PrimitiveMapping mapping, string ns)
  202.         {
  203.             XmlSchemaType type = mapping.TypeDesc.DataType;
  204.             if (!SchemaContainsItem(type, UrtTypes.Namespace)) {
  205.                 AddSchemaItem(type, UrtTypes.Namespace, ns);
  206.             }
  207.             else {
  208.                 AddSchemaImport(UrtTypes.Namespace, ns);
  209.             }
  210.             return new XmlQualifiedName(mapping.TypeDesc.DataType.Name, UrtTypes.Namespace);
  211.         }
  212.        
  213.         XmlQualifiedName ExportPrimitiveMapping(PrimitiveMapping mapping)
  214.         {
  215.             return new XmlQualifiedName(mapping.TypeDesc.DataType.Name, XmlSchema.Namespace);
  216.         }
  217.        
  218.         XmlQualifiedName ExportArrayMapping(ArrayMapping mapping, string ns)
  219.         {
  220.             // for the Rpc ArrayMapping different mappings could have the same schema type
  221.             // we link all mappings corresponding to the same type together
  222.             // loop through all mapping that will map to the same complexType, and export only one,
  223.             // the obvious choice is the last one.
  224.             while (mapping.Next != null) {
  225.                 mapping = mapping.Next;
  226.             }
  227.            
  228.             XmlSchemaComplexType type = (XmlSchemaComplexType)types[mapping];
  229.             if (type == null) {
  230.                 CheckForDuplicateType(mapping.TypeName, mapping.Namespace);
  231.                 type = new XmlSchemaComplexType();
  232.                 type.Name = mapping.TypeName;
  233.                 types.Add(mapping, type);
  234.                
  235.                 // we need to add the type first, to make sure that the schema get created
  236.                 AddSchemaItem(type, mapping.Namespace, ns);
  237.                 AddSchemaImport(Soap.Encoding, mapping.Namespace);
  238.                 AddSchemaImport(Wsdl.Namespace, mapping.Namespace);
  239.                
  240.                 XmlSchemaComplexContentRestriction restriction = new XmlSchemaComplexContentRestriction();
  241.                 XmlQualifiedName qname = ExportTypeMapping(mapping.Elements[0].Mapping, mapping.Namespace);
  242.                
  243.                 if (qname.IsEmpty) {
  244.                     // this is a root mapping
  245.                     qname = new XmlQualifiedName(Soap.UrType, XmlSchema.Namespace);
  246.                 }
  247.                 //<attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:float[]"/>
  248.                 XmlSchemaAttribute attr = new XmlSchemaAttribute();
  249.                 attr.RefName = ArrayTypeQName;
  250.                 XmlAttribute attribute = new XmlAttribute("wsdl", Wsdl.ArrayType, Wsdl.Namespace, Document);
  251.                 attribute.Value = qname.Namespace + ":" + qname.Name + "[]";
  252.                
  253.                 attr.UnhandledAttributes = new XmlAttribute[] {attribute};
  254.                 restriction.Attributes.Add(attr);
  255.                 restriction.BaseTypeName = ArrayQName;
  256.                 XmlSchemaComplexContent model = new XmlSchemaComplexContent();
  257.                 model.Content = restriction;
  258.                 type.ContentModel = model;
  259.                 if (qname.Namespace != XmlSchema.Namespace)
  260.                     AddSchemaImport(qname.Namespace, mapping.Namespace);
  261.             }
  262.             else {
  263.                 AddSchemaImport(mapping.Namespace, ns);
  264.             }
  265.             return new XmlQualifiedName(mapping.TypeName, mapping.Namespace);
  266.         }
  267.        
  268.         void ExportElementAccessors(XmlSchemaGroupBase group, ElementAccessor[] accessors, bool repeats, bool valueTypeOptional, string ns)
  269.         {
  270.             if (accessors.Length == 0)
  271.                 return;
  272.             if (accessors.Length == 1) {
  273.                 ExportElementAccessor(group, accessors[0], repeats, valueTypeOptional, ns);
  274.             }
  275.             else {
  276.                 XmlSchemaChoice choice = new XmlSchemaChoice();
  277.                 choice.MaxOccurs = repeats ? decimal.MaxValue : 1;
  278.                 choice.MinOccurs = repeats ? 0 : 1;
  279.                 for (int i = 0; i < accessors.Length; i++)
  280.                     ExportElementAccessor(choice, accessors[i], false, valueTypeOptional, ns);
  281.                
  282.                 if (choice.Items.Count > 0)
  283.                     group.Items.Add(choice);
  284.             }
  285.         }
  286.        
  287.        
  288.         void ExportElementAccessor(XmlSchemaGroupBase group, ElementAccessor accessor, bool repeats, bool valueTypeOptional, string ns)
  289.         {
  290.             XmlSchemaElement element = new XmlSchemaElement();
  291.             element.MinOccurs = repeats || valueTypeOptional ? 0 : 1;
  292.             element.MaxOccurs = repeats ? decimal.MaxValue : 1;
  293.             element.Name = accessor.Name;
  294.             element.IsNillable = accessor.IsNullable || accessor.Mapping is NullableMapping;
  295.             element.Form = XmlSchemaForm.Unqualified;
  296.             element.SchemaTypeName = ExportTypeMapping(accessor.Mapping, accessor.Namespace);
  297.            
  298.             group.Items.Add(element);
  299.         }
  300.        
  301.         XmlQualifiedName ExportRootMapping(StructMapping mapping)
  302.         {
  303.             if (!exportedRoot) {
  304.                 exportedRoot = true;
  305.                 ExportDerivedMappings(mapping);
  306.             }
  307.             return new XmlQualifiedName(Soap.UrType, XmlSchema.Namespace);
  308.         }
  309.        
  310.         XmlQualifiedName ExportStructMapping(StructMapping mapping, string ns)
  311.         {
  312.             if (mapping.TypeDesc.IsRoot)
  313.                 return ExportRootMapping(mapping);
  314.             XmlSchemaComplexType type = (XmlSchemaComplexType)types[mapping];
  315.             if (type == null) {
  316.                 if (!mapping.IncludeInSchema)
  317.                     throw new InvalidOperationException(Res.GetString(Res.XmlSoapCannotIncludeInSchema, mapping.TypeDesc.Name));
  318.                 CheckForDuplicateType(mapping.TypeName, mapping.Namespace);
  319.                 type = new XmlSchemaComplexType();
  320.                 type.Name = mapping.TypeName;
  321.                 types.Add(mapping, type);
  322.                 AddSchemaItem(type, mapping.Namespace, ns);
  323.                 type.IsAbstract = mapping.TypeDesc.IsAbstract;
  324.                
  325.                 if (mapping.BaseMapping != null && mapping.BaseMapping.IncludeInSchema) {
  326.                     XmlSchemaComplexContentExtension extension = new XmlSchemaComplexContentExtension();
  327.                     extension.BaseTypeName = ExportStructMapping(mapping.BaseMapping, mapping.Namespace);
  328.                     XmlSchemaComplexContent model = new XmlSchemaComplexContent();
  329.                     model.Content = extension;
  330.                     type.ContentModel = model;
  331.                 }
  332.                 ExportTypeMembers(type, mapping.Members, mapping.Namespace);
  333.                 ExportDerivedMappings(mapping);
  334.             }
  335.             else {
  336.                 AddSchemaImport(mapping.Namespace, ns);
  337.             }
  338.             return new XmlQualifiedName(type.Name, mapping.Namespace);
  339.         }
  340.        
  341.         XmlQualifiedName ExportMembersMapping(MembersMapping mapping, string ns)
  342.         {
  343.             XmlSchemaComplexType type = (XmlSchemaComplexType)types[mapping];
  344.             if (type == null) {
  345.                 CheckForDuplicateType(mapping.TypeName, mapping.Namespace);
  346.                 type = new XmlSchemaComplexType();
  347.                 type.Name = mapping.TypeName;
  348.                 types.Add(mapping, type);
  349.                 AddSchemaItem(type, mapping.Namespace, ns);
  350.                 ExportTypeMembers(type, mapping.Members, mapping.Namespace);
  351.             }
  352.             else {
  353.                 AddSchemaImport(mapping.Namespace, ns);
  354.             }
  355.             return new XmlQualifiedName(type.Name, mapping.Namespace);
  356.         }
  357.        
  358.         void ExportTypeMembers(XmlSchemaComplexType type, MemberMapping[] members, string ns)
  359.         {
  360.             XmlSchemaGroupBase seq = new XmlSchemaSequence();
  361.             for (int i = 0; i < members.Length; i++) {
  362.                 MemberMapping member = members[i];
  363.                 if (member.Elements.Length > 0) {
  364.                     bool valueTypeOptional = member.CheckSpecified || member.CheckShouldPersist || !member.TypeDesc.IsValueType;
  365.                     ExportElementAccessors(seq, member.Elements, false, valueTypeOptional, ns);
  366.                 }
  367.             }
  368.             if (seq.Items.Count > 0) {
  369.                 if (type.ContentModel != null) {
  370.                     if (type.ContentModel.Content is XmlSchemaComplexContentExtension)
  371.                         ((XmlSchemaComplexContentExtension)type.ContentModel.Content).Particle = seq;
  372.                     else if (type.ContentModel.Content is XmlSchemaComplexContentRestriction)
  373.                         ((XmlSchemaComplexContentRestriction)type.ContentModel.Content).Particle = seq;
  374.                     else
  375.                         throw new InvalidOperationException(Res.GetString(Res.XmlInvalidContent, type.ContentModel.Content.GetType().Name));
  376.                 }
  377.                 else {
  378.                     type.Particle = seq;
  379.                 }
  380.             }
  381.         }
  382.        
  383.         void ExportDerivedMappings(StructMapping mapping)
  384.         {
  385.             for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) {
  386.                 if (derived.IncludeInSchema)
  387.                     ExportStructMapping(derived, mapping.TypeDesc.IsRoot ? null : mapping.Namespace);
  388.             }
  389.         }
  390.        
  391.         XmlQualifiedName ExportEnumMapping(EnumMapping mapping, string ns)
  392.         {
  393.             XmlSchemaSimpleType dataType = (XmlSchemaSimpleType)types[mapping];
  394.             if (dataType == null) {
  395.                 CheckForDuplicateType(mapping.TypeName, mapping.Namespace);
  396.                 dataType = new XmlSchemaSimpleType();
  397.                 dataType.Name = mapping.TypeName;
  398.                 types.Add(mapping, dataType);
  399.                 AddSchemaItem(dataType, mapping.Namespace, ns);
  400.                
  401.                 XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction();
  402.                 restriction.BaseTypeName = new XmlQualifiedName("string", XmlSchema.Namespace);
  403.                
  404.                 for (int i = 0; i < mapping.Constants.Length; i++) {
  405.                     ConstantMapping constant = mapping.Constants[i];
  406.                     XmlSchemaEnumerationFacet enumeration = new XmlSchemaEnumerationFacet();
  407.                     enumeration.Value = constant.XmlName;
  408.                     restriction.Facets.Add(enumeration);
  409.                 }
  410.                 if (!mapping.IsFlags) {
  411.                     dataType.Content = restriction;
  412.                 }
  413.                 else {
  414.                     XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList();
  415.                     XmlSchemaSimpleType enumType = new XmlSchemaSimpleType();
  416.                     enumType.Content = restriction;
  417.                     list.ItemType = enumType;
  418.                     dataType.Content = list;
  419.                 }
  420.             }
  421.             else {
  422.                 AddSchemaImport(mapping.Namespace, ns);
  423.             }
  424.             return new XmlQualifiedName(mapping.TypeName, mapping.Namespace);
  425.         }
  426.     }
  427. }

Developer Fusion