[bcl] Updates referencesource to 4.7.1
[mono-project.git] / mcs / class / referencesource / System.Xml / System / Xml / Serialization / SoapSchemaExporter.cs
blobaaf94a6442a424fcf5e3b53100cad4ec702bcc62
1 //------------------------------------------------------------------------------
2 // <copyright file="SoapSchemaExporter.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
4 // </copyright>
5 // <owner current="true" primary="true">Microsoft</owner>
6 //------------------------------------------------------------------------------
8 namespace System.Xml.Serialization {
10 using System;
11 using System.Collections;
12 using System.Xml.Schema;
13 using System.Xml;
14 using System.ComponentModel;
15 using System.Diagnostics;
17 /// <include file='doc\SoapSchemaExporter.uex' path='docs/doc[@for="SoapSchemaExporter"]/*' />
18 /// <internalonly/>
19 public class SoapSchemaExporter {
20 internal const XmlSchemaForm elementFormDefault = XmlSchemaForm.Qualified;
21 XmlSchemas schemas;
22 Hashtable types = new Hashtable(); // StructMapping/EnumMapping -> XmlSchemaComplexType/XmlSchemaSimpleType
23 bool exportedRoot;
24 TypeScope scope;
25 XmlDocument document;
27 static XmlQualifiedName ArrayQName = new XmlQualifiedName(Soap.Array, Soap.Encoding);
28 static XmlQualifiedName ArrayTypeQName = new XmlQualifiedName(Soap.ArrayType, Soap.Encoding);
30 /// <include file='doc\SoapSchemaExporter.uex' path='docs/doc[@for="SoapSchemaExporter.SoapSchemaExporter"]/*' />
31 /// <devdoc>
32 /// <para>[To be supplied.]</para>
33 /// </devdoc>
34 public SoapSchemaExporter(XmlSchemas schemas) {
35 this.schemas = schemas;
38 /// <include file='doc\SoapSchemaExporter.uex' path='docs/doc[@for="SoapSchemaExporter.ExportTypeMapping"]/*' />
39 /// <devdoc>
40 /// <para>[To be supplied.]</para>
41 /// </devdoc>
42 public void ExportTypeMapping(XmlTypeMapping xmlTypeMapping) {
43 CheckScope(xmlTypeMapping.Scope);
44 ExportTypeMapping(xmlTypeMapping.Mapping, null);
47 /// <include file='doc\SoapSchemaExporter.uex' path='docs/doc[@for="SoapSchemaExporter.ExportMembersMapping"]/*' />
48 /// <devdoc>
49 /// <para>[To be supplied.]</para>
50 /// </devdoc>
51 public void ExportMembersMapping(XmlMembersMapping xmlMembersMapping) {
52 ExportMembersMapping(xmlMembersMapping, false);
55 /// <include file='doc\SoapSchemaExporter.uex' path='docs/doc[@for="SoapSchemaExporter.ExportMembersMapping1"]/*' />
56 /// <devdoc>
57 /// <para>[To be supplied.]</para>
58 /// </devdoc>
59 public void ExportMembersMapping(XmlMembersMapping xmlMembersMapping, bool exportEnclosingType) {
60 CheckScope(xmlMembersMapping.Scope);
61 MembersMapping membersMapping = (MembersMapping)xmlMembersMapping.Accessor.Mapping;
62 if (exportEnclosingType) {
63 ExportTypeMapping(membersMapping, null);
65 else {
66 foreach (MemberMapping memberMapping in membersMapping.Members) {
67 if (memberMapping.Elements.Length > 0)
68 ExportTypeMapping(memberMapping.Elements[0].Mapping, null);
73 void CheckScope(TypeScope scope) {
74 if (this.scope == null) {
75 this.scope = scope;
77 else if (this.scope != scope) {
78 throw new InvalidOperationException(Res.GetString(Res.XmlMappingsScopeMismatch));
82 internal XmlDocument Document {
83 get {
84 if (document == null) document = new XmlDocument();
85 return document;
89 void CheckForDuplicateType(string newTypeName, string newNamespace){
90 XmlSchema schema = schemas[newNamespace];
91 if (schema != null){
92 foreach (XmlSchemaObject o in schema.Items) {
93 XmlSchemaType type = o as XmlSchemaType;
94 if ( type != null && type.Name == newTypeName)
95 throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateTypeName, newTypeName, newNamespace));
101 void AddSchemaItem(XmlSchemaObject item, string ns, string referencingNs) {
102 if (!SchemaContainsItem(item, ns)) {
103 XmlSchema schema = schemas[ns];
104 if (schema == null) {
105 schema = new XmlSchema();
106 schema.TargetNamespace = ns == null || ns.Length == 0 ? null : ns;
108 #pragma warning disable 429 // unreachable code detected: elementFormDefault is const so it will never be Unqualified
109 schema.ElementFormDefault = elementFormDefault == XmlSchemaForm.Unqualified ? XmlSchemaForm.None : elementFormDefault;
110 #pragma warning restore 429
111 schemas.Add(schema);
113 schema.Items.Add(item);
115 if (referencingNs != null)
116 AddSchemaImport(ns, referencingNs);
119 void AddSchemaImport(string ns, string referencingNs) {
120 if (referencingNs == null || ns == null) return;
121 if (ns == referencingNs) return;
122 XmlSchema schema = schemas[referencingNs];
123 if (schema == null) throw new InvalidOperationException(Res.GetString(Res.XmlMissingSchema, referencingNs));
124 if (ns != null && ns.Length > 0 && FindImport(schema, ns) == null) {
125 XmlSchemaImport import = new XmlSchemaImport();
126 import.Namespace = ns;
127 schema.Includes.Add(import);
131 bool SchemaContainsItem(XmlSchemaObject item, string ns) {
132 XmlSchema schema = schemas[ns];
133 if (schema != null) {
134 return schema.Items.Contains(item);
136 return false;
139 XmlSchemaImport FindImport(XmlSchema schema, string ns) {
140 foreach (object item in schema.Includes) {
141 if (item is XmlSchemaImport) {
142 XmlSchemaImport import = (XmlSchemaImport)item;
143 if (import.Namespace == ns) {
144 return import;
148 return null;
151 XmlQualifiedName ExportTypeMapping(TypeMapping mapping, string ns) {
152 if (mapping is ArrayMapping)
153 return ExportArrayMapping((ArrayMapping)mapping, ns);
154 else if (mapping is EnumMapping)
155 return ExportEnumMapping((EnumMapping)mapping, ns);
156 else if (mapping is PrimitiveMapping) {
157 PrimitiveMapping pm = (PrimitiveMapping)mapping;
158 if (pm.TypeDesc.IsXsdType) {
159 return ExportPrimitiveMapping(pm);
161 else {
162 return ExportNonXsdPrimitiveMapping(pm, ns);
165 else if (mapping is StructMapping)
166 return ExportStructMapping((StructMapping)mapping, ns);
167 else if (mapping is NullableMapping)
168 return ExportTypeMapping(((NullableMapping)mapping).BaseMapping, ns);
169 else if (mapping is MembersMapping)
170 return ExportMembersMapping((MembersMapping)mapping, ns);
171 else
172 throw new ArgumentException(Res.GetString(Res.XmlInternalError), "mapping");
175 XmlQualifiedName ExportNonXsdPrimitiveMapping(PrimitiveMapping mapping, string ns) {
176 XmlSchemaType type = mapping.TypeDesc.DataType;
177 if (!SchemaContainsItem(type, UrtTypes.Namespace)) {
178 AddSchemaItem(type, UrtTypes.Namespace, ns);
180 else {
181 AddSchemaImport(UrtTypes.Namespace, ns);
183 return new XmlQualifiedName(mapping.TypeDesc.DataType.Name, UrtTypes.Namespace);
186 XmlQualifiedName ExportPrimitiveMapping(PrimitiveMapping mapping) {
187 return new XmlQualifiedName(mapping.TypeDesc.DataType.Name, XmlSchema.Namespace);
190 XmlQualifiedName ExportArrayMapping(ArrayMapping mapping, string ns) {
191 // for the Rpc ArrayMapping different mappings could have the same schema type
192 // we link all mappings corresponding to the same type together
193 // loop through all mapping that will map to the same complexType, and export only one,
194 // the obvious choice is the last one.
195 while (mapping.Next != null) {
196 mapping = mapping.Next;
199 XmlSchemaComplexType type = (XmlSchemaComplexType)types[mapping];
200 if (type == null) {
201 CheckForDuplicateType(mapping.TypeName, mapping.Namespace);
202 type = new XmlSchemaComplexType();
203 type.Name = mapping.TypeName;
204 types.Add(mapping, type);
206 // we need to add the type first, to make sure that the schema get created
207 AddSchemaItem(type, mapping.Namespace, ns);
208 AddSchemaImport(Soap.Encoding, mapping.Namespace);
209 AddSchemaImport(Wsdl.Namespace, mapping.Namespace);
211 XmlSchemaComplexContentRestriction restriction = new XmlSchemaComplexContentRestriction();
212 XmlQualifiedName qname = ExportTypeMapping(mapping.Elements[0].Mapping, mapping.Namespace);
214 if (qname.IsEmpty) {
215 // this is a root mapping
216 qname = new XmlQualifiedName(Soap.UrType, XmlSchema.Namespace);
218 //<attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:float[]"/>
219 XmlSchemaAttribute attr = new XmlSchemaAttribute();
220 attr.RefName = ArrayTypeQName;
221 XmlAttribute attribute = new XmlAttribute("wsdl", Wsdl.ArrayType, Wsdl.Namespace, Document);
222 attribute.Value = qname.Namespace + ":" + qname.Name + "[]";
224 attr.UnhandledAttributes = new XmlAttribute[] {attribute};
225 restriction.Attributes.Add(attr);
226 restriction.BaseTypeName = ArrayQName;
227 XmlSchemaComplexContent model = new XmlSchemaComplexContent();
228 model.Content = restriction;
229 type.ContentModel = model;
230 if (qname.Namespace != XmlSchema.Namespace)
231 AddSchemaImport(qname.Namespace, mapping.Namespace);
233 else {
234 AddSchemaImport(mapping.Namespace, ns);
236 return new XmlQualifiedName(mapping.TypeName, mapping.Namespace);
239 void ExportElementAccessors(XmlSchemaGroupBase group, ElementAccessor[] accessors, bool repeats, bool valueTypeOptional, string ns) {
240 if (accessors.Length == 0) return;
241 if (accessors.Length == 1) {
242 ExportElementAccessor(group, accessors[0], repeats, valueTypeOptional, ns);
244 else {
245 XmlSchemaChoice choice = new XmlSchemaChoice();
246 choice.MaxOccurs = repeats ? decimal.MaxValue : 1;
247 choice.MinOccurs = repeats ? 0 : 1;
248 for (int i = 0; i < accessors.Length; i++)
249 ExportElementAccessor(choice, accessors[i], false, valueTypeOptional, ns);
251 if (choice.Items.Count > 0) group.Items.Add(choice);
256 void ExportElementAccessor(XmlSchemaGroupBase group, ElementAccessor accessor, bool repeats, bool valueTypeOptional, string ns) {
257 XmlSchemaElement element = new XmlSchemaElement();
258 element.MinOccurs = repeats || valueTypeOptional ? 0 : 1;
259 element.MaxOccurs = repeats ? decimal.MaxValue : 1;
260 element.Name = accessor.Name;
261 element.IsNillable = accessor.IsNullable || accessor.Mapping is NullableMapping;
262 element.Form = XmlSchemaForm.Unqualified;
263 element.SchemaTypeName = ExportTypeMapping(accessor.Mapping, accessor.Namespace);
265 group.Items.Add(element);
268 XmlQualifiedName ExportRootMapping(StructMapping mapping) {
269 if (!exportedRoot) {
270 exportedRoot = true;
271 ExportDerivedMappings(mapping);
273 return new XmlQualifiedName(Soap.UrType, XmlSchema.Namespace);
276 XmlQualifiedName ExportStructMapping(StructMapping mapping, string ns) {
277 if (mapping.TypeDesc.IsRoot) return ExportRootMapping(mapping);
278 XmlSchemaComplexType type = (XmlSchemaComplexType)types[mapping];
279 if (type == null) {
280 if (!mapping.IncludeInSchema) throw new InvalidOperationException(Res.GetString(Res.XmlSoapCannotIncludeInSchema, mapping.TypeDesc.Name));
281 CheckForDuplicateType(mapping.TypeName, mapping.Namespace);
282 type = new XmlSchemaComplexType();
283 type.Name = mapping.TypeName;
284 types.Add(mapping, type);
285 AddSchemaItem(type, mapping.Namespace, ns);
286 type.IsAbstract = mapping.TypeDesc.IsAbstract;
288 if (mapping.BaseMapping != null && mapping.BaseMapping.IncludeInSchema) {
289 XmlSchemaComplexContentExtension extension = new XmlSchemaComplexContentExtension();
290 extension.BaseTypeName = ExportStructMapping(mapping.BaseMapping, mapping.Namespace);
291 XmlSchemaComplexContent model = new XmlSchemaComplexContent();
292 model.Content = extension;
293 type.ContentModel = model;
295 ExportTypeMembers(type, mapping.Members, mapping.Namespace);
296 ExportDerivedMappings(mapping);
298 else {
299 AddSchemaImport(mapping.Namespace, ns);
301 return new XmlQualifiedName(type.Name, mapping.Namespace);
304 XmlQualifiedName ExportMembersMapping(MembersMapping mapping, string ns) {
305 XmlSchemaComplexType type = (XmlSchemaComplexType)types[mapping];
306 if(type == null) {
307 CheckForDuplicateType(mapping.TypeName, mapping.Namespace);
308 type = new XmlSchemaComplexType();
309 type.Name = mapping.TypeName;
310 types.Add(mapping, type);
311 AddSchemaItem(type, mapping.Namespace, ns);
312 ExportTypeMembers(type, mapping.Members, mapping.Namespace);
314 else {
315 AddSchemaImport(mapping.Namespace, ns);
317 return new XmlQualifiedName(type.Name, mapping.Namespace);
320 void ExportTypeMembers(XmlSchemaComplexType type, MemberMapping[] members, string ns) {
321 XmlSchemaGroupBase seq = new XmlSchemaSequence();
322 for (int i = 0; i < members.Length; i++) {
323 MemberMapping member = members[i];
324 if (member.Elements.Length > 0) {
325 bool valueTypeOptional = member.CheckSpecified != SpecifiedAccessor.None || member.CheckShouldPersist || !member.TypeDesc.IsValueType;
326 ExportElementAccessors(seq, member.Elements, false, valueTypeOptional, ns);
329 if (seq.Items.Count > 0) {
330 if (type.ContentModel != null) {
331 if (type.ContentModel.Content is XmlSchemaComplexContentExtension)
332 ((XmlSchemaComplexContentExtension)type.ContentModel.Content).Particle = seq;
333 else if (type.ContentModel.Content is XmlSchemaComplexContentRestriction)
334 ((XmlSchemaComplexContentRestriction)type.ContentModel.Content).Particle = seq;
335 else
336 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidContent, type.ContentModel.Content.GetType().Name));
338 else {
339 type.Particle = seq;
344 void ExportDerivedMappings(StructMapping mapping) {
345 for (StructMapping derived = mapping.DerivedMappings; derived != null; derived = derived.NextDerivedMapping) {
346 if (derived.IncludeInSchema) ExportStructMapping(derived, mapping.TypeDesc.IsRoot ? null : mapping.Namespace);
350 XmlQualifiedName ExportEnumMapping(EnumMapping mapping, string ns) {
351 XmlSchemaSimpleType dataType = (XmlSchemaSimpleType)types[mapping];
352 if (dataType == null) {
353 CheckForDuplicateType(mapping.TypeName, mapping.Namespace);
354 dataType = new XmlSchemaSimpleType();
355 dataType.Name = mapping.TypeName;
356 types.Add(mapping, dataType);
357 AddSchemaItem(dataType, mapping.Namespace, ns);
359 XmlSchemaSimpleTypeRestriction restriction = new XmlSchemaSimpleTypeRestriction();
360 restriction.BaseTypeName = new XmlQualifiedName("string", XmlSchema.Namespace);
362 for (int i = 0; i < mapping.Constants.Length; i++) {
363 ConstantMapping constant = mapping.Constants[i];
364 XmlSchemaEnumerationFacet enumeration = new XmlSchemaEnumerationFacet();
365 enumeration.Value = constant.XmlName;
366 restriction.Facets.Add(enumeration);
368 if (!mapping.IsFlags) {
369 dataType.Content = restriction;
371 else {
372 XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList();
373 XmlSchemaSimpleType enumType = new XmlSchemaSimpleType();
374 enumType.Content = restriction;
375 list.ItemType = enumType;
376 dataType.Content = list;
379 else {
380 AddSchemaImport(mapping.Namespace, ns);
382 return new XmlQualifiedName(mapping.TypeName, mapping.Namespace);