Updates referencesource to .NET 4.7
[mono-project.git] / mcs / class / referencesource / System.Xml / System / Xml / Serialization / XmlSchemaImporter.cs
blob1f7aa1d1a103bfec063ea5227cb03fbb6ef5003e
1 //------------------------------------------------------------------------------
2 // <copyright file="XmlSchemaImporter.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.Xml.Schema;
12 using System.Collections;
13 using System.Collections.Generic;
14 using System.ComponentModel;
15 using System.Reflection;
16 using System.Xml.Serialization.Configuration;
17 using System.CodeDom;
18 using System.CodeDom.Compiler;
19 using System.Collections.Specialized;
20 using System.Globalization;
21 using System.Security.Permissions;
22 using System.Xml.Serialization.Advanced;
24 #if DEBUG
25 using System.Diagnostics;
26 #endif
28 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter"]/*' />
29 ///<internalonly/>
30 /// <devdoc>
31 /// <para>[To be supplied.]</para>
32 /// </devdoc>
33 public class XmlSchemaImporter : SchemaImporter {
35 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.XmlSchemaImporter"]/*' />
36 /// <devdoc>
37 /// <para>[To be supplied.]</para>
38 /// </devdoc>
39 public XmlSchemaImporter(XmlSchemas schemas) : base(schemas, CodeGenerationOptions.GenerateProperties, null, new ImportContext()) {}
41 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.XmlSchemaImporter1"]/*' />
42 /// <devdoc>
43 /// <para>[To be supplied.]</para>
44 /// </devdoc>
45 public XmlSchemaImporter(XmlSchemas schemas, CodeIdentifiers typeIdentifiers) : base(schemas, CodeGenerationOptions.GenerateProperties, null, new ImportContext(typeIdentifiers, false)) {}
47 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.XmlSchemaImporter2"]/*' />
48 /// <devdoc>
49 /// <para>[To be supplied.]</para>
50 /// </devdoc>
51 public XmlSchemaImporter(XmlSchemas schemas, CodeIdentifiers typeIdentifiers, CodeGenerationOptions options) : base(schemas, options, null, new ImportContext(typeIdentifiers, false)) {}
53 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.XmlSchemaImporter3"]/*' />
54 /// <devdoc>
55 /// <para>[To be supplied.]</para>
56 /// </devdoc>
57 public XmlSchemaImporter(XmlSchemas schemas, CodeGenerationOptions options, ImportContext context) : base(schemas, options, null, context){}
59 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.XmlSchemaImporter4"]/*' />
60 /// <devdoc>
61 /// <para>[To be supplied.]</para>
62 /// </devdoc>
63 public XmlSchemaImporter(XmlSchemas schemas, CodeGenerationOptions options, CodeDomProvider codeProvider, ImportContext context) : base(schemas, options, codeProvider, context){
66 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportDerivedTypeMapping"]/*' />
67 /// <devdoc>
68 /// <para>[To be supplied.]</para>
69 /// </devdoc>
70 public XmlTypeMapping ImportDerivedTypeMapping(XmlQualifiedName name, Type baseType) {
71 return ImportDerivedTypeMapping(name, baseType, false);
74 internal bool GenerateOrder {
75 get { return (Options & CodeGenerationOptions.GenerateOrder) != 0; }
78 internal TypeMapping GetDefaultMapping(TypeFlags flags) {
79 PrimitiveMapping mapping = new PrimitiveMapping();
80 mapping.TypeDesc = Scope.GetTypeDesc("string", XmlSchema.Namespace, flags);
81 mapping.TypeName = mapping.TypeDesc.DataType.Name;
82 mapping.Namespace = XmlSchema.Namespace;
83 return mapping;
86 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportDerivedTypeMapping1"]/*' />
87 /// <devdoc>
88 /// <para>[To be supplied.]</para>
89 /// </devdoc>
90 public XmlTypeMapping ImportDerivedTypeMapping(XmlQualifiedName name, Type baseType, bool baseTypeCanBeIndirect) {
91 ElementAccessor element = ImportElement(name, typeof(TypeMapping), baseType);
93 if (element.Mapping is StructMapping) {
94 MakeDerived((StructMapping)element.Mapping, baseType, baseTypeCanBeIndirect);
96 else if (baseType != null) {
97 if (element.Mapping is ArrayMapping) {
98 // in the case of the ArrayMapping we can use the top-level StructMapping, because it does not have base base type
99 element.Mapping = ((ArrayMapping)element.Mapping).TopLevelMapping;
100 MakeDerived((StructMapping)element.Mapping, baseType, baseTypeCanBeIndirect);
102 else {
103 // Element '{0}' from namespace '{1}' is not a complex type and cannot be used as a {2}.
104 throw new InvalidOperationException(Res.GetString(Res.XmlBadBaseElement, name.Name, name.Namespace, baseType.FullName));
107 return new XmlTypeMapping(Scope, element);
110 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportSchemaType"]/*' />
111 /// <devdoc>
112 /// <para>[To be supplied.]</para>
113 /// </devdoc>
114 public XmlTypeMapping ImportSchemaType(XmlQualifiedName typeName) {
115 return ImportSchemaType(typeName, null, false);
119 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportSchemaType1"]/*' />
120 /// <devdoc>
121 /// <para>[To be supplied.]</para>
122 /// </devdoc>
123 public XmlTypeMapping ImportSchemaType(XmlQualifiedName typeName, Type baseType) {
124 return ImportSchemaType(typeName, baseType, false);
127 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportSchemaType2"]/*' />
128 /// <devdoc>
129 /// <para>[To be supplied.]</para>
130 /// </devdoc>
131 public XmlTypeMapping ImportSchemaType(XmlQualifiedName typeName, Type baseType, bool baseTypeCanBeIndirect) {
132 TypeMapping typeMapping = ImportType(typeName, typeof(TypeMapping), baseType, TypeFlags.CanBeElementValue, true);
133 typeMapping.ReferencedByElement = false;
135 ElementAccessor accessor = new ElementAccessor();
136 accessor.IsTopLevelInSchema = true; // false
137 accessor.Name = typeName.Name;
138 accessor.Namespace = typeName.Namespace;
139 accessor.Mapping = typeMapping;
141 if (typeMapping is SpecialMapping && ((SpecialMapping)typeMapping).NamedAny)
142 accessor.Any = true;
143 accessor.IsNullable = typeMapping.TypeDesc.IsNullable;
144 accessor.Form = XmlSchemaForm.Qualified;
146 if (accessor.Mapping is StructMapping) {
147 MakeDerived((StructMapping)accessor.Mapping, baseType, baseTypeCanBeIndirect);
149 else if (baseType != null) {
150 if (accessor.Mapping is ArrayMapping) {
151 // in the case of the ArrayMapping we can use the top-level StructMapping, because it does not have base base type
152 accessor.Mapping = ((ArrayMapping)accessor.Mapping).TopLevelMapping;
153 MakeDerived((StructMapping)accessor.Mapping, baseType, baseTypeCanBeIndirect);
155 else {
156 // Type '{0}' from namespace '{1}' is not a complex type and cannot be used as a {2}.
157 throw new InvalidOperationException(Res.GetString(Res.XmlBadBaseType, typeName.Name, typeName.Namespace, baseType.FullName));
160 return new XmlTypeMapping(Scope, accessor);
163 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportTypeMapping"]/*' />
164 /// <devdoc>
165 /// <para>[To be supplied.]</para>
166 /// </devdoc>
167 public XmlTypeMapping ImportTypeMapping(XmlQualifiedName name) {
168 return ImportDerivedTypeMapping(name, null);
171 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportMembersMapping"]/*' />
172 /// <devdoc>
173 /// <para>[To be supplied.]</para>
174 /// </devdoc>
175 public XmlMembersMapping ImportMembersMapping(XmlQualifiedName name) {
176 return new XmlMembersMapping(Scope, ImportElement(name, typeof(MembersMapping), null), XmlMappingAccess.Read | XmlMappingAccess.Write);
179 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportAnyType"]/*' />
180 public XmlMembersMapping ImportAnyType(XmlQualifiedName typeName, string elementName) {
181 TypeMapping typeMapping = ImportType(typeName, typeof(MembersMapping), null, TypeFlags.CanBeElementValue, true);
182 MembersMapping mapping = typeMapping as MembersMapping;
184 if (mapping == null) {
185 XmlSchemaComplexType type = new XmlSchemaComplexType();
186 XmlSchemaSequence seq = new XmlSchemaSequence();
187 type.Particle = seq;
188 XmlSchemaElement element = new XmlSchemaElement();
189 element.Name = elementName;
190 element.SchemaTypeName = typeName;
191 seq.Items.Add(element);
192 mapping = ImportMembersType(type, typeName.Namespace, elementName);
195 if (mapping.Members.Length != 1 || !mapping.Members[0].Accessor.Any)
196 return null;
197 mapping.Members[0].Name = elementName;
198 ElementAccessor accessor = new ElementAccessor();
199 accessor.Name = elementName;
200 accessor.Namespace = typeName.Namespace;
201 accessor.Mapping = mapping;
202 accessor.Any = true;
204 XmlSchemaObject xso = Schemas.SchemaSet.GlobalTypes[typeName];
205 if (xso != null) {
206 XmlSchema schema = xso.Parent as XmlSchema;
207 if (schema != null) {
208 accessor.Form = schema.ElementFormDefault == XmlSchemaForm.None ? XmlSchemaForm.Unqualified : schema.ElementFormDefault;
211 XmlMembersMapping members = new XmlMembersMapping(Scope, accessor, XmlMappingAccess.Read | XmlMappingAccess.Write);
212 return members;
215 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportMembersMapping1"]/*' />
216 /// <devdoc>
217 /// <para>[To be supplied.]</para>
218 /// </devdoc>
219 public XmlMembersMapping ImportMembersMapping(XmlQualifiedName[] names) {
220 return ImportMembersMapping(names, null, false);
223 /// <include file='doc\XmlSchemaImporter.uex' path='docs/doc[@for="XmlSchemaImporter.ImportMembersMapping2"]/*' />
224 /// <devdoc>
225 /// <para>[To be supplied.]</para>
226 /// </devdoc>
227 public XmlMembersMapping ImportMembersMapping(XmlQualifiedName[] names, Type baseType, bool baseTypeCanBeIndirect) {
228 CodeIdentifiers memberScope = new CodeIdentifiers();
229 memberScope.UseCamelCasing = true;
230 MemberMapping[] members = new MemberMapping[names.Length];
231 for (int i = 0; i < names.Length; i++) {
232 XmlQualifiedName name = names[i];
233 ElementAccessor accessor = ImportElement(name, typeof(TypeMapping), baseType);
234 if (baseType != null && accessor.Mapping is StructMapping)
235 MakeDerived((StructMapping)accessor.Mapping, baseType, baseTypeCanBeIndirect);
237 MemberMapping member = new MemberMapping();
238 member.Name = CodeIdentifier.MakeValid(Accessor.UnescapeName(accessor.Name));
239 member.Name = memberScope.AddUnique(member.Name, member);
240 member.TypeDesc = accessor.Mapping.TypeDesc;
241 member.Elements = new ElementAccessor[] { accessor };
242 members[i] = member;
244 MembersMapping mapping = new MembersMapping();
245 mapping.HasWrapperElement = false;
246 mapping.TypeDesc = Scope.GetTypeDesc(typeof(object[]));
247 mapping.Members = members;
248 ElementAccessor element = new ElementAccessor();
249 element.Mapping = mapping;
250 return new XmlMembersMapping(Scope, element, XmlMappingAccess.Read | XmlMappingAccess.Write);
253 public XmlMembersMapping ImportMembersMapping(string name, string ns, SoapSchemaMember[] members) {
254 XmlSchemaComplexType type = new XmlSchemaComplexType();
255 XmlSchemaSequence seq = new XmlSchemaSequence();
256 type.Particle = seq;
257 foreach (SoapSchemaMember member in members) {
258 XmlSchemaElement element = new XmlSchemaElement();
259 element.Name = member.MemberName;
260 element.SchemaTypeName = member.MemberType;
261 seq.Items.Add(element);
263 MembersMapping mapping = ImportMembersType(type, null, name);
265 ElementAccessor accessor = new ElementAccessor();
266 accessor.Name = Accessor.EscapeName(name);
267 accessor.Namespace = ns;
268 accessor.Mapping = mapping;
269 accessor.IsNullable = false;
270 accessor.Form = XmlSchemaForm.Qualified;
271 return new XmlMembersMapping(Scope, accessor, XmlMappingAccess.Read | XmlMappingAccess.Write);
274 ElementAccessor ImportElement(XmlQualifiedName name, Type desiredMappingType, Type baseType) {
275 XmlSchemaElement element = FindElement(name);
276 ElementAccessor accessor = (ElementAccessor)ImportedElements[element];
277 if (accessor != null) return accessor;
278 accessor = ImportElement(element, string.Empty, desiredMappingType, baseType, name.Namespace, true);
279 ElementAccessor existing = (ElementAccessor)ImportedElements[element];
280 if (existing != null) {
281 return existing;
283 ImportedElements.Add(element, accessor);
284 return accessor;
287 ElementAccessor ImportElement(XmlSchemaElement element, string identifier, Type desiredMappingType, Type baseType, string ns, bool topLevelElement) {
288 if (!element.RefName.IsEmpty) {
289 // we cannot re-use the accessor for the element refs
290 ElementAccessor topAccessor = ImportElement(element.RefName, desiredMappingType, baseType);
291 if (element.IsMultipleOccurrence && topAccessor.Mapping is ArrayMapping) {
292 ElementAccessor refAccessor = topAccessor.Clone();
293 refAccessor.IsTopLevelInSchema = false;
294 refAccessor.Mapping.ReferencedByElement = true;
295 return refAccessor;
297 return topAccessor;
300 if (element.Name.Length == 0) {
301 XmlQualifiedName parentType = XmlSchemas.GetParentName(element);
302 throw new InvalidOperationException(Res.GetString(Res.XmlElementHasNoName, parentType.Name, parentType.Namespace));
304 string unescapedName = Accessor.UnescapeName(element.Name);
305 if (identifier.Length == 0)
306 identifier = CodeIdentifier.MakeValid(unescapedName);
307 else
308 identifier += CodeIdentifier.MakePascal(unescapedName);
309 TypeMapping mapping = ImportElementType(element, identifier, desiredMappingType, baseType, ns);
310 ElementAccessor accessor = new ElementAccessor();
311 accessor.IsTopLevelInSchema = element.Parent is XmlSchema;
312 accessor.Name = element.Name;
313 accessor.Namespace = ns;
314 accessor.Mapping = mapping;
315 accessor.IsOptional = element.MinOccurs == 0m;
317 if (element.DefaultValue != null) {
318 accessor.Default = element.DefaultValue;
320 else if (element.FixedValue != null) {
321 accessor.Default = element.FixedValue;
322 accessor.IsFixed = true;
325 if (mapping is SpecialMapping && ((SpecialMapping)mapping).NamedAny)
326 accessor.Any = true;
327 accessor.IsNullable = element.IsNillable;
328 if (topLevelElement) {
329 accessor.Form = XmlSchemaForm.Qualified;
331 else {
332 accessor.Form = ElementForm(ns, element);
334 return accessor;
337 TypeMapping ImportElementType(XmlSchemaElement element, string identifier, Type desiredMappingType, Type baseType, string ns) {
338 TypeMapping mapping;
339 if (!element.SchemaTypeName.IsEmpty) {
340 mapping = ImportType(element.SchemaTypeName, desiredMappingType, baseType, TypeFlags.CanBeElementValue, false);
341 if (!mapping.ReferencedByElement) {
342 object type = FindType(element.SchemaTypeName, TypeFlags.CanBeElementValue);
343 XmlSchemaObject parent = element;
344 while (parent.Parent != null && type != parent) {
345 parent = parent.Parent;
347 mapping.ReferencedByElement = (type != parent);
350 else if (element.SchemaType != null) {
351 if (element.SchemaType is XmlSchemaComplexType)
352 mapping = ImportType((XmlSchemaComplexType)element.SchemaType, ns, identifier, desiredMappingType, baseType, TypeFlags.CanBeElementValue);
353 else
354 mapping = ImportDataType((XmlSchemaSimpleType)element.SchemaType, ns, identifier, baseType, TypeFlags.CanBeElementValue | TypeFlags.CanBeAttributeValue | TypeFlags.CanBeTextValue, false);
355 mapping.ReferencedByElement = true;
357 else if (!element.SubstitutionGroup.IsEmpty)
358 mapping = ImportElementType(FindElement(element.SubstitutionGroup), identifier, desiredMappingType, baseType, ns);
359 else {
360 if (desiredMappingType == typeof(MembersMapping)) {
361 mapping = ImportMembersType(new XmlSchemaType(), ns, identifier);
363 else {
364 mapping = ImportRootMapping();
367 if (!(desiredMappingType.IsAssignableFrom(mapping.GetType())))
368 throw new InvalidOperationException(Res.GetString(Res.XmlElementImportedTwice, element.Name, ns, mapping.GetType().Name, desiredMappingType.Name));
370 // let the extensions to run
371 if (!mapping.TypeDesc.IsMappedType) {
372 RunSchemaExtensions(mapping, element.SchemaTypeName, element.SchemaType, element, TypeFlags.CanBeElementValue);
374 return mapping;
377 void RunSchemaExtensions(TypeMapping mapping, XmlQualifiedName qname, XmlSchemaType type, XmlSchemaObject context, TypeFlags flags) {
378 string typeName = null;
379 SchemaImporterExtension typeOwner = null;
380 CodeCompileUnit compileUnit = new CodeCompileUnit();
381 CodeNamespace mainNamespace = new CodeNamespace();
382 compileUnit.Namespaces.Add(mainNamespace);
384 if (!qname.IsEmpty) {
385 typeName = FindExtendedType(qname.Name, qname.Namespace, context, compileUnit, mainNamespace, out typeOwner);
387 else if (type != null) {
388 typeName = FindExtendedType(type, context, compileUnit, mainNamespace, out typeOwner);
390 else if (context is XmlSchemaAny) {
391 typeName = FindExtendedAnyElement((XmlSchemaAny)context, ((flags & TypeFlags.CanBeTextValue) != 0), compileUnit, mainNamespace, out typeOwner);
394 if (typeName != null && typeName.Length > 0) {
395 // check if the type name is valid
396 typeName = typeName.Replace('+', '.');
397 try {
398 CodeGenerator.ValidateIdentifiers(new CodeTypeReference(typeName));
400 catch (ArgumentException) {
401 if (qname.IsEmpty) {
402 throw new InvalidOperationException(Res.GetString(Res.XmlImporterExtensionBadLocalTypeName, typeOwner.GetType().FullName, typeName));
404 else {
405 throw new InvalidOperationException(Res.GetString(Res.XmlImporterExtensionBadTypeName, typeOwner.GetType().FullName, qname.Name, qname.Namespace, typeName));
411 foreach (CodeNamespace ns in compileUnit.Namespaces) {
412 CodeGenerator.ValidateIdentifiers(ns);
416 mapping.TypeDesc = mapping.TypeDesc.CreateMappedTypeDesc(new MappedTypeDesc(typeName, qname.Name, qname.Namespace, type, context, typeOwner, mainNamespace, compileUnit.ReferencedAssemblies));
418 if (mapping is ArrayMapping) {
419 TypeMapping top = ((ArrayMapping)mapping).TopLevelMapping;
420 top.TypeName = mapping.TypeName;
421 top.TypeDesc = mapping.TypeDesc;
423 else {
424 mapping.TypeName = qname.IsEmpty ? null : typeName;
428 string GenerateUniqueTypeName(string desiredName, string ns) {
429 int i = 1;
431 string typeName = desiredName;
432 while (true) {
433 XmlQualifiedName qname = new XmlQualifiedName(typeName, ns);
435 object type = Schemas.Find(qname, typeof(XmlSchemaType));
436 if (type == null) {
437 break;
439 typeName = desiredName + i.ToString(CultureInfo.InvariantCulture);
440 i++;
442 typeName = CodeIdentifier.MakeValid(typeName);
443 return TypeIdentifiers.AddUnique(typeName, typeName);
446 [PermissionSet(SecurityAction.InheritanceDemand, Name="FullTrust")]
447 internal override void ImportDerivedTypes(XmlQualifiedName baseName) {
448 foreach (XmlSchema schema in Schemas) {
449 if (Schemas.IsReference(schema)) continue;
450 if (XmlSchemas.IsDataSet(schema)) continue;
451 XmlSchemas.Preprocess(schema);
452 foreach (object item in schema.SchemaTypes.Values) {
453 if (item is XmlSchemaType) {
454 XmlSchemaType type = (XmlSchemaType)item;
455 if (type.DerivedFrom == baseName && TypesInUse[type.Name, schema.TargetNamespace] == null) {
456 ImportType(type.QualifiedName, typeof(TypeMapping), null, TypeFlags.CanBeElementValue, false);
463 TypeMapping ImportType(XmlQualifiedName name, Type desiredMappingType, Type baseType, TypeFlags flags, bool addref) {
464 if (name.Name == Soap.UrType && name.Namespace == XmlSchema.Namespace)
465 return ImportRootMapping();
466 object type = FindType(name, flags);
468 TypeMapping mapping = (TypeMapping)ImportedMappings[type];
469 if (mapping != null && desiredMappingType.IsAssignableFrom(mapping.GetType()))
470 return mapping;
472 if (addref)
473 AddReference(name, TypesInUse, Res.XmlCircularTypeReference);
474 if (type is XmlSchemaComplexType) {
475 mapping = ImportType((XmlSchemaComplexType)type, name.Namespace, name.Name, desiredMappingType, baseType, flags);
477 else if (type is XmlSchemaSimpleType)
478 mapping = ImportDataType((XmlSchemaSimpleType)type, name.Namespace, name.Name, baseType, flags, false);
479 else
480 throw new InvalidOperationException(Res.GetString(Res.XmlInternalError));
482 if (addref && name.Namespace != XmlSchema.Namespace)
483 RemoveReference(name, TypesInUse);
485 return mapping;
488 TypeMapping ImportType(XmlSchemaComplexType type, string typeNs, string identifier, Type desiredMappingType, Type baseType, TypeFlags flags) {
489 if (type.Redefined != null) {
490 // we do not support redefine in the current version
491 throw new NotSupportedException(Res.GetString(Res.XmlUnsupportedRedefine, type.Name, typeNs));
493 if (desiredMappingType == typeof(TypeMapping)) {
494 TypeMapping mapping = null;
496 if (baseType == null) {
497 if ((mapping = ImportArrayMapping(type, identifier, typeNs, false)) == null) {
498 mapping = ImportAnyMapping(type, identifier, typeNs, false);
501 if (mapping == null) {
502 mapping = ImportStructType(type, typeNs, identifier, baseType, false);
504 if (mapping != null && type.Name != null && type.Name.Length != 0)
505 ImportDerivedTypes(new XmlQualifiedName(identifier, typeNs));
507 return mapping;
509 else if (desiredMappingType == typeof(MembersMapping))
510 return ImportMembersType(type, typeNs, identifier);
511 else
512 throw new ArgumentException(Res.GetString(Res.XmlInternalError), "desiredMappingType");
515 MembersMapping ImportMembersType(XmlSchemaType type, string typeNs, string identifier) {
516 if (!type.DerivedFrom.IsEmpty) throw new InvalidOperationException(Res.GetString(Res.XmlMembersDeriveError));
517 CodeIdentifiers memberScope = new CodeIdentifiers();
518 memberScope.UseCamelCasing = true;
519 bool needExplicitOrder = false;
520 MemberMapping[] members = ImportTypeMembers(type, typeNs, identifier, memberScope, new CodeIdentifiers(), new NameTable(), ref needExplicitOrder, false, false);
521 MembersMapping mappings = new MembersMapping();
522 mappings.HasWrapperElement = true;
523 mappings.TypeDesc = Scope.GetTypeDesc(typeof(object[]));
524 mappings.Members = members;
525 return mappings;
528 StructMapping ImportStructType(XmlSchemaType type, string typeNs, string identifier, Type baseType, bool arrayLike) {
529 TypeDesc baseTypeDesc = null;
530 TypeMapping baseMapping = null;
532 bool isRootType = false;
533 if (!type.DerivedFrom.IsEmpty) {
534 baseMapping = ImportType(type.DerivedFrom, typeof(TypeMapping), null, TypeFlags.CanBeElementValue | TypeFlags.CanBeTextValue, false);
536 if (baseMapping is StructMapping)
537 baseTypeDesc = ((StructMapping)baseMapping).TypeDesc;
538 else if (baseMapping is ArrayMapping) {
539 baseMapping = ((ArrayMapping)baseMapping).TopLevelMapping;
540 if (baseMapping != null) {
541 baseMapping.ReferencedByTopLevelElement = false;
542 baseMapping.ReferencedByElement = true;
543 baseTypeDesc = baseMapping.TypeDesc;
546 else
547 baseMapping = null;
549 if (baseTypeDesc == null && baseType != null)
550 baseTypeDesc = Scope.GetTypeDesc(baseType);
551 if (baseMapping == null)
553 baseMapping = GetRootMapping();
554 isRootType = true;
556 Mapping previousMapping = (Mapping)ImportedMappings[type];
557 if (previousMapping != null) {
558 if (previousMapping is StructMapping) {
559 return (StructMapping)previousMapping;
561 else if (arrayLike && previousMapping is ArrayMapping){
562 ArrayMapping arrayMapping = (ArrayMapping)previousMapping;
563 if (arrayMapping.TopLevelMapping != null) {
564 return arrayMapping.TopLevelMapping;
567 else {
568 throw new InvalidOperationException(Res.GetString(Res.XmlTypeUsedTwice, type.QualifiedName.Name, type.QualifiedName.Namespace));
571 StructMapping structMapping = new StructMapping();
572 structMapping.IsReference = Schemas.IsReference(type);
573 TypeFlags flags = TypeFlags.Reference;
574 if (type is XmlSchemaComplexType) {
575 if (((XmlSchemaComplexType)type).IsAbstract)
576 flags |= TypeFlags.Abstract;
579 identifier = Accessor.UnescapeName(identifier);
580 string typeName = type.Name == null || type.Name.Length == 0 ? GenerateUniqueTypeName(identifier, typeNs) : GenerateUniqueTypeName(identifier);
581 structMapping.TypeDesc = new TypeDesc(typeName, typeName, TypeKind.Struct, baseTypeDesc, flags);
582 structMapping.Namespace = typeNs;
583 structMapping.TypeName = type.Name == null || type.Name.Length == 0 ? null : identifier;
584 structMapping.BaseMapping = (StructMapping)baseMapping;
585 if (!arrayLike)
586 ImportedMappings.Add(type, structMapping);
587 CodeIdentifiers members = new CodeIdentifiers();
588 CodeIdentifiers membersScope = structMapping.BaseMapping.Scope.Clone();
589 members.AddReserved(typeName);
590 membersScope.AddReserved(typeName);
591 AddReservedIdentifiersForDataBinding(members);
592 if (isRootType)
593 AddReservedIdentifiersForDataBinding(membersScope);
594 bool needExplicitOrder = false;
595 structMapping.Members = ImportTypeMembers(type, typeNs, identifier, members, membersScope, structMapping, ref needExplicitOrder, true, true);
597 if (!IsAllGroup(type)) {
598 if (needExplicitOrder && !GenerateOrder) {
599 structMapping.SetSequence();
601 else if (GenerateOrder) {
602 structMapping.IsSequence = true;
606 for (int i = 0; i < structMapping.Members.Length; i++) {
607 StructMapping declaringMapping;
608 MemberMapping baseMember = ((StructMapping)baseMapping).FindDeclaringMapping(structMapping.Members[i], out declaringMapping, structMapping.TypeName);
609 if (baseMember != null && baseMember.TypeDesc != structMapping.Members[i].TypeDesc)
610 throw new InvalidOperationException(Res.GetString(Res.XmlIllegalOverride, type.Name, baseMember.Name, baseMember.TypeDesc.FullName, structMapping.Members[i].TypeDesc.FullName, declaringMapping.TypeDesc.FullName));
612 structMapping.Scope = membersScope;
613 Scope.AddTypeMapping(structMapping);
614 return structMapping;
617 bool IsAllGroup(XmlSchemaType type) {
618 TypeItems items = GetTypeItems(type);
619 return (items.Particle != null) && (items.Particle is XmlSchemaAll);
622 StructMapping ImportStructDataType(XmlSchemaSimpleType dataType, string typeNs, string identifier, Type baseType) {
623 identifier = Accessor.UnescapeName(identifier);
624 string typeName = GenerateUniqueTypeName(identifier);
625 StructMapping structMapping = new StructMapping();
626 structMapping.IsReference = Schemas.IsReference(dataType);
627 TypeFlags flags = TypeFlags.Reference;
628 TypeDesc baseTypeDesc = Scope.GetTypeDesc(baseType);
629 structMapping.TypeDesc = new TypeDesc(typeName, typeName, TypeKind.Struct, baseTypeDesc, flags);
630 structMapping.Namespace = typeNs;
631 structMapping.TypeName = identifier;
632 CodeIdentifiers members = new CodeIdentifiers();
633 members.AddReserved(typeName);
634 AddReservedIdentifiersForDataBinding(members);
635 ImportTextMember(members, new CodeIdentifiers(), null);
636 structMapping.Members = (MemberMapping[])members.ToArray(typeof(MemberMapping));
637 structMapping.Scope = members;
638 Scope.AddTypeMapping(structMapping);
639 return structMapping;
642 class TypeItems {
643 internal XmlSchemaObjectCollection Attributes = new XmlSchemaObjectCollection();
644 internal XmlSchemaAnyAttribute AnyAttribute;
645 internal XmlSchemaGroupBase Particle;
646 internal XmlQualifiedName baseSimpleType;
647 internal bool IsUnbounded;
650 MemberMapping[] ImportTypeMembers(XmlSchemaType type, string typeNs, string identifier, CodeIdentifiers members, CodeIdentifiers membersScope, INameScope elementsScope, ref bool needExplicitOrder, bool order, bool allowUnboundedElements) {
651 TypeItems items = GetTypeItems(type);
652 bool mixed = IsMixed(type);
654 if (mixed) {
655 // check if we can transfer the attribute to the base class
656 XmlSchemaType t = type;
657 while (!t.DerivedFrom.IsEmpty) {
658 t = FindType(t.DerivedFrom, TypeFlags.CanBeElementValue | TypeFlags.CanBeTextValue);
659 if (IsMixed(t)) {
660 // keep the mixed attribute on the base class
661 mixed = false;
662 break;
667 if (items.Particle != null) {
668 ImportGroup(items.Particle, identifier, members, membersScope, elementsScope, typeNs, mixed, ref needExplicitOrder, order, items.IsUnbounded, allowUnboundedElements);
670 for (int i = 0; i < items.Attributes.Count; i++) {
671 object item = items.Attributes[i];
672 if (item is XmlSchemaAttribute) {
673 ImportAttributeMember((XmlSchemaAttribute)item, identifier, members, membersScope, typeNs);
675 else if (item is XmlSchemaAttributeGroupRef) {
676 XmlQualifiedName groupName = ((XmlSchemaAttributeGroupRef)item).RefName;
677 ImportAttributeGroupMembers(FindAttributeGroup(groupName), identifier, members, membersScope, groupName.Namespace);
680 if (items.AnyAttribute != null) {
681 ImportAnyAttributeMember(items.AnyAttribute, members, membersScope);
684 if (items.baseSimpleType != null || (items.Particle == null && mixed)) {
685 ImportTextMember(members, membersScope, mixed ? null : items.baseSimpleType);
688 ImportXmlnsDeclarationsMember(type, members, membersScope);
689 MemberMapping[] typeMembers = (MemberMapping[])members.ToArray(typeof(MemberMapping));
690 return typeMembers;
693 internal static bool IsMixed(XmlSchemaType type) {
694 if (!(type is XmlSchemaComplexType))
695 return false;
697 XmlSchemaComplexType ct = (XmlSchemaComplexType)type;
698 bool mixed = ct.IsMixed;
700 // check the mixed attribute on the complexContent
701 if (!mixed) {
702 if (ct.ContentModel != null && ct.ContentModel is XmlSchemaComplexContent) {
703 mixed = ((XmlSchemaComplexContent)ct.ContentModel).IsMixed;
706 return mixed;
709 TypeItems GetTypeItems(XmlSchemaType type) {
710 TypeItems items = new TypeItems();
711 if (type is XmlSchemaComplexType) {
712 XmlSchemaParticle particle = null;
713 XmlSchemaComplexType ct = (XmlSchemaComplexType)type;
714 if (ct.ContentModel != null) {
715 XmlSchemaContent content = ct.ContentModel.Content;
716 if (content is XmlSchemaComplexContentExtension) {
717 XmlSchemaComplexContentExtension extension = (XmlSchemaComplexContentExtension)content;
718 items.Attributes = extension.Attributes;
719 items.AnyAttribute = extension.AnyAttribute;
720 particle = extension.Particle;
722 else if (content is XmlSchemaSimpleContentExtension) {
723 XmlSchemaSimpleContentExtension extension = (XmlSchemaSimpleContentExtension)content;
724 items.Attributes = extension.Attributes;
725 items.AnyAttribute = extension.AnyAttribute;
726 items.baseSimpleType = extension.BaseTypeName;
729 else {
730 items.Attributes = ct.Attributes;
731 items.AnyAttribute = ct.AnyAttribute;
732 particle = ct.Particle;
734 if (particle is XmlSchemaGroupRef) {
735 XmlSchemaGroupRef refGroup = (XmlSchemaGroupRef)particle;
736 items.Particle = FindGroup(refGroup.RefName).Particle;
737 items.IsUnbounded = particle.IsMultipleOccurrence;
739 else if (particle is XmlSchemaGroupBase) {
740 items.Particle = (XmlSchemaGroupBase)particle;
741 items.IsUnbounded = particle.IsMultipleOccurrence;
744 return items;
747 void ImportGroup(XmlSchemaGroupBase group, string identifier, CodeIdentifiers members, CodeIdentifiers membersScope, INameScope elementsScope, string ns, bool mixed, ref bool needExplicitOrder, bool allowDuplicates, bool groupRepeats, bool allowUnboundedElements) {
748 if (group is XmlSchemaChoice)
749 ImportChoiceGroup((XmlSchemaChoice)group, identifier, members, membersScope, elementsScope, ns, groupRepeats, ref needExplicitOrder, allowDuplicates);
750 else
751 ImportGroupMembers(group, identifier, members, membersScope, elementsScope, ns, groupRepeats, ref mixed, ref needExplicitOrder, allowDuplicates, allowUnboundedElements);
753 if (mixed) {
754 ImportTextMember(members, membersScope, null);
758 MemberMapping ImportChoiceGroup(XmlSchemaGroupBase group, string identifier, CodeIdentifiers members, CodeIdentifiers membersScope, INameScope elementsScope, string ns, bool groupRepeats, ref bool needExplicitOrder, bool allowDuplicates) {
759 NameTable choiceElements = new NameTable();
760 if (GatherGroupChoices(group, choiceElements, identifier, ns, ref needExplicitOrder, allowDuplicates))
761 groupRepeats = true;
762 MemberMapping member = new MemberMapping();
763 member.Elements = (ElementAccessor[])choiceElements.ToArray(typeof(ElementAccessor));
764 Array.Sort(member.Elements, new ElementComparer());
766 AddScopeElements(elementsScope, member.Elements, ref needExplicitOrder, allowDuplicates);
767 bool duplicateTypes = false;
768 bool nullableMismatch = false;
769 Hashtable uniqueTypeDescs = new Hashtable(member.Elements.Length);
771 for (int i = 0; i < member.Elements.Length; i++) {
772 ElementAccessor element = member.Elements[i];
773 string tdFullName = element.Mapping.TypeDesc.FullName;
774 object val = uniqueTypeDescs[tdFullName];
775 if (val != null) {
776 duplicateTypes = true;
777 ElementAccessor existingElement = (ElementAccessor)val;
778 if (!nullableMismatch && existingElement.IsNullable != element.IsNullable)
779 nullableMismatch = true;
781 else {
782 uniqueTypeDescs.Add(tdFullName, element);
785 ArrayMapping arrayMapping = element.Mapping as ArrayMapping;
786 if (arrayMapping != null) {
787 if (IsNeedXmlSerializationAttributes(arrayMapping)) {
788 // we cannot use ArrayMapping in choice if additional custom
789 // serialization attributes are needed to serialize it
790 element.Mapping = arrayMapping.TopLevelMapping;
791 element.Mapping.ReferencedByTopLevelElement = false;
792 element.Mapping.ReferencedByElement = true;
796 if (nullableMismatch)
797 member.TypeDesc = Scope.GetTypeDesc(typeof(object));
798 else
800 TypeDesc[] typeDescs = new TypeDesc[uniqueTypeDescs.Count];
801 IEnumerator enumerator = uniqueTypeDescs.Values.GetEnumerator();
802 for (int i = 0; i < typeDescs.Length; i++)
804 if (!enumerator.MoveNext())
805 break;
806 typeDescs[i] = ((ElementAccessor)enumerator.Current).Mapping.TypeDesc;
808 member.TypeDesc = TypeDesc.FindCommonBaseTypeDesc(typeDescs);
809 if (member.TypeDesc == null) member.TypeDesc = Scope.GetTypeDesc(typeof(object));
812 if (groupRepeats)
813 member.TypeDesc = member.TypeDesc.CreateArrayTypeDesc();
815 if (membersScope != null) {
816 member.Name = membersScope.AddUnique(groupRepeats ? "Items" : "Item", member);
817 if (members != null) {
818 members.Add(member.Name, member);
822 if (duplicateTypes) {
823 member.ChoiceIdentifier = new ChoiceIdentifierAccessor();
824 member.ChoiceIdentifier.MemberName = member.Name + "ElementName";
825 // we need to create the EnumMapping to store all of the element names
826 member.ChoiceIdentifier.Mapping = ImportEnumeratedChoice(member.Elements, ns, member.Name + "ChoiceType");
827 member.ChoiceIdentifier.MemberIds = new string[member.Elements.Length];
828 ConstantMapping[] constants = ((EnumMapping)member.ChoiceIdentifier.Mapping).Constants;
829 for (int i = 0; i < member.Elements.Length; i++) {
830 member.ChoiceIdentifier.MemberIds[i] = constants[i].Name;
832 MemberMapping choiceIdentifier = new MemberMapping();
833 choiceIdentifier.Ignore = true;
834 choiceIdentifier.Name = member.ChoiceIdentifier.MemberName;
835 if (groupRepeats) {
836 choiceIdentifier.TypeDesc = member.ChoiceIdentifier.Mapping.TypeDesc.CreateArrayTypeDesc();
838 else {
839 choiceIdentifier.TypeDesc = member.ChoiceIdentifier.Mapping.TypeDesc;
842 // create element accessor for the choiceIdentifier
844 ElementAccessor choiceAccessor = new ElementAccessor();
845 choiceAccessor.Name = choiceIdentifier.Name;
846 choiceAccessor.Namespace = ns;
847 choiceAccessor.Mapping = member.ChoiceIdentifier.Mapping;
848 choiceIdentifier.Elements = new ElementAccessor[] {choiceAccessor};
850 if (membersScope != null) {
851 choiceAccessor.Name = choiceIdentifier.Name = member.ChoiceIdentifier.MemberName = membersScope.AddUnique(member.ChoiceIdentifier.MemberName, choiceIdentifier);
852 if (members != null) {
853 members.Add(choiceAccessor.Name, choiceIdentifier);
857 return member;
860 bool IsNeedXmlSerializationAttributes(ArrayMapping arrayMapping) {
861 if (arrayMapping.Elements.Length != 1)
862 return true;
864 ElementAccessor item = arrayMapping.Elements[0];
865 TypeMapping itemMapping = item.Mapping;
867 if (item.Name != itemMapping.DefaultElementName)
868 return true;
870 if (item.Form != XmlSchemaForm.None && item.Form != XmlSchemaExporter.elementFormDefault)
871 return true;
873 if (item.Mapping.TypeDesc != null)
875 if (item.IsNullable != item.Mapping.TypeDesc.IsNullable)
876 return true;
878 if (item.Mapping.TypeDesc.IsAmbiguousDataType)
879 return true;
881 return false;
884 bool GatherGroupChoices(XmlSchemaGroup group, NameTable choiceElements, string identifier, string ns, ref bool needExplicitOrder, bool allowDuplicates) {
885 return GatherGroupChoices(group.Particle, choiceElements, identifier, ns, ref needExplicitOrder, allowDuplicates);
888 bool GatherGroupChoices(XmlSchemaParticle particle, NameTable choiceElements, string identifier, string ns, ref bool needExplicitOrder, bool allowDuplicates) {
889 if (particle is XmlSchemaGroupRef) {
890 XmlSchemaGroupRef refGroup = (XmlSchemaGroupRef)particle;
891 if (!refGroup.RefName.IsEmpty) {
892 AddReference(refGroup.RefName, GroupsInUse, Res.XmlCircularGroupReference);
893 if (GatherGroupChoices(FindGroup(refGroup.RefName), choiceElements, identifier, refGroup.RefName.Namespace, ref needExplicitOrder, allowDuplicates)) {
894 RemoveReference(refGroup.RefName, GroupsInUse);
895 return true;
897 RemoveReference(refGroup.RefName, GroupsInUse);
900 else if (particle is XmlSchemaGroupBase) {
901 XmlSchemaGroupBase group = (XmlSchemaGroupBase)particle;
902 bool groupRepeats = group.IsMultipleOccurrence;
903 XmlSchemaAny any = null;
904 bool duplicateElements = false;
905 for (int i = 0; i < group.Items.Count; i++) {
906 object item = group.Items[i];
907 if (item is XmlSchemaGroupBase || item is XmlSchemaGroupRef) {
908 if (GatherGroupChoices((XmlSchemaParticle)item, choiceElements, identifier, ns, ref needExplicitOrder, allowDuplicates))
909 groupRepeats = true;
911 else if (item is XmlSchemaAny) {
912 if (GenerateOrder) {
913 AddScopeElements(choiceElements, ImportAny((XmlSchemaAny)item, true, ns), ref duplicateElements, allowDuplicates);
915 else {
916 any = (XmlSchemaAny)item;
919 else if (item is XmlSchemaElement) {
920 XmlSchemaElement element = (XmlSchemaElement)item;
921 XmlSchemaElement headElement = GetTopLevelElement(element);
922 if (headElement != null) {
923 XmlSchemaElement[] elements = GetEquivalentElements(headElement);
924 for (int j = 0; j < elements.Length; j++) {
925 if (elements[j].IsMultipleOccurrence) groupRepeats = true;
926 AddScopeElement(choiceElements, ImportElement(elements[j], identifier, typeof(TypeMapping), null, elements[j].QualifiedName.Namespace, true), ref duplicateElements, allowDuplicates);
929 if (element.IsMultipleOccurrence) groupRepeats = true;
930 AddScopeElement(choiceElements, ImportElement(element, identifier, typeof(TypeMapping), null, element.QualifiedName.Namespace, false), ref duplicateElements, allowDuplicates);
933 if (any != null) {
934 AddScopeElements(choiceElements, ImportAny(any, true, ns), ref duplicateElements, allowDuplicates);
936 if (!groupRepeats && !(group is XmlSchemaChoice) && group.Items.Count > 1) {
937 groupRepeats = true;
939 return groupRepeats;
941 return false;
944 void AddScopeElement(INameScope scope, ElementAccessor element, ref bool duplicateElements, bool allowDuplicates) {
945 if (scope == null)
946 return;
948 ElementAccessor scopeElement = (ElementAccessor)scope[element.Name, element.Namespace];
949 if (scopeElement != null) {
950 if (!allowDuplicates) {
951 throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateElementInScope, element.Name, element.Namespace));
953 if (scopeElement.Mapping.TypeDesc != element.Mapping.TypeDesc) {
954 throw new InvalidOperationException(Res.GetString(Res.XmlDuplicateElementInScope1, element.Name, element.Namespace));
956 duplicateElements = true;
958 else {
959 scope[element.Name, element.Namespace] = element;
963 void AddScopeElements(INameScope scope, ElementAccessor[] elements, ref bool duplicateElements, bool allowDuplicates) {
964 for (int i = 0; i < elements.Length; i++) {
965 AddScopeElement(scope, elements[i], ref duplicateElements, allowDuplicates);
969 void ImportGroupMembers(XmlSchemaParticle particle, string identifier, CodeIdentifiers members, CodeIdentifiers membersScope, INameScope elementsScope, string ns, bool groupRepeats, ref bool mixed, ref bool needExplicitOrder, bool allowDuplicates, bool allowUnboundedElements) {
971 if (particle is XmlSchemaGroupRef) {
972 XmlSchemaGroupRef refGroup = (XmlSchemaGroupRef)particle;
973 if (!refGroup.RefName.IsEmpty) {
974 AddReference(refGroup.RefName, GroupsInUse, Res.XmlCircularGroupReference);
975 ImportGroupMembers(FindGroup(refGroup.RefName).Particle, identifier, members, membersScope, elementsScope, refGroup.RefName.Namespace, groupRepeats | refGroup.IsMultipleOccurrence, ref mixed, ref needExplicitOrder, allowDuplicates, allowUnboundedElements);
976 RemoveReference(refGroup.RefName, GroupsInUse);
979 else if (particle is XmlSchemaGroupBase) {
980 XmlSchemaGroupBase group = (XmlSchemaGroupBase)particle;
982 if (group.IsMultipleOccurrence)
983 groupRepeats = true;
985 if (GenerateOrder && groupRepeats && group.Items.Count > 1) {
986 ImportChoiceGroup(group, identifier, members, membersScope, elementsScope, ns, groupRepeats, ref needExplicitOrder, allowDuplicates);
988 else {
989 for (int i = 0; i < group.Items.Count; i++) {
990 object item = group.Items[i];
991 if (item is XmlSchemaChoice)
992 ImportChoiceGroup((XmlSchemaGroupBase)item, identifier, members, membersScope, elementsScope, ns, groupRepeats, ref needExplicitOrder, allowDuplicates);
993 else if (item is XmlSchemaElement)
994 ImportElementMember((XmlSchemaElement)item, identifier, members, membersScope, elementsScope, ns, groupRepeats, ref needExplicitOrder, allowDuplicates, allowUnboundedElements);
995 else if (item is XmlSchemaAny) {
996 ImportAnyMember((XmlSchemaAny)item, identifier, members, membersScope, elementsScope, ns, ref mixed, ref needExplicitOrder, allowDuplicates);
998 else if (item is XmlSchemaParticle) {
999 ImportGroupMembers((XmlSchemaParticle)item, identifier, members, membersScope, elementsScope, ns, groupRepeats, ref mixed, ref needExplicitOrder, allowDuplicates, true);
1006 XmlSchemaElement GetTopLevelElement(XmlSchemaElement element) {
1007 if (!element.RefName.IsEmpty)
1008 return FindElement(element.RefName);
1009 return null;
1012 XmlSchemaElement[] GetEquivalentElements(XmlSchemaElement element) {
1013 ArrayList equivalentElements = new ArrayList();
1015 foreach (XmlSchema schema in Schemas.SchemaSet.Schemas()) {
1016 for (int j = 0; j < schema.Items.Count; j++) {
1017 object item = schema.Items[j];
1018 if (item is XmlSchemaElement) {
1019 XmlSchemaElement equivalentElement = (XmlSchemaElement)item;
1020 if (!equivalentElement.IsAbstract &&
1021 equivalentElement.SubstitutionGroup.Namespace == schema.TargetNamespace &&
1022 equivalentElement.SubstitutionGroup.Name == element.Name) {
1023 equivalentElements.Add(equivalentElement);
1029 return (XmlSchemaElement[])equivalentElements.ToArray(typeof(XmlSchemaElement));
1032 bool ImportSubstitutionGroupMember(XmlSchemaElement element, string identifier, CodeIdentifiers members, CodeIdentifiers membersScope, string ns, bool repeats, ref bool needExplicitOrder, bool allowDuplicates) {
1033 XmlSchemaElement[] elements = GetEquivalentElements(element);
1034 if (elements.Length == 0)
1035 return false;
1036 XmlSchemaChoice choice = new XmlSchemaChoice();
1037 for (int i = 0; i < elements.Length; i++)
1038 choice.Items.Add(elements[i]);
1039 if (!element.IsAbstract)
1040 choice.Items.Add(element);
1041 if (identifier.Length == 0)
1042 identifier = CodeIdentifier.MakeValid(Accessor.UnescapeName(element.Name));
1043 else
1044 identifier += CodeIdentifier.MakePascal(Accessor.UnescapeName(element.Name));
1045 ImportChoiceGroup(choice, identifier, members, membersScope, null, ns, repeats, ref needExplicitOrder, allowDuplicates);
1047 return true;
1050 void ImportTextMember(CodeIdentifiers members, CodeIdentifiers membersScope, XmlQualifiedName simpleContentType) {
1051 TypeMapping mapping;
1052 bool isMixed = false;
1054 if (simpleContentType != null) {
1055 // allow to use all primitive types
1056 mapping = ImportType(simpleContentType, typeof(TypeMapping), null, TypeFlags.CanBeElementValue | TypeFlags.CanBeTextValue, false);
1057 if (!(mapping is PrimitiveMapping || mapping.TypeDesc.CanBeTextValue)) {
1058 return;
1061 else {
1062 // this is a case of the mixed content type, just generate string typeDesc
1063 isMixed = true;
1064 mapping = GetDefaultMapping(TypeFlags.CanBeElementValue | TypeFlags.CanBeTextValue);
1067 TextAccessor accessor = new TextAccessor();
1068 accessor.Mapping = mapping;
1070 MemberMapping member = new MemberMapping();
1071 member.Elements = new ElementAccessor[0];
1072 member.Text = accessor;
1073 if (isMixed) {
1074 // just generate code for the standard mixed case (string[] text)
1075 member.TypeDesc = accessor.Mapping.TypeDesc.CreateArrayTypeDesc();
1076 member.Name = members.MakeRightCase("Text");
1078 else {
1079 // import mapping for the simpleContent
1080 PrimitiveMapping pm = (PrimitiveMapping)accessor.Mapping;
1081 if (pm.IsList) {
1082 member.TypeDesc = accessor.Mapping.TypeDesc.CreateArrayTypeDesc();
1083 member.Name = members.MakeRightCase("Text");
1085 else {
1086 member.TypeDesc = accessor.Mapping.TypeDesc;
1087 member.Name = members.MakeRightCase("Value");
1090 member.Name = membersScope.AddUnique(member.Name, member);
1091 members.Add(member.Name, member);
1094 MemberMapping ImportAnyMember(XmlSchemaAny any, string identifier, CodeIdentifiers members, CodeIdentifiers membersScope, INameScope elementsScope, string ns, ref bool mixed, ref bool needExplicitOrder, bool allowDuplicates) {
1095 ElementAccessor[] accessors = ImportAny(any, !mixed, ns);
1096 AddScopeElements(elementsScope, accessors, ref needExplicitOrder, allowDuplicates);
1097 MemberMapping member = new MemberMapping();
1098 member.Elements = accessors;
1099 member.Name = membersScope.MakeRightCase("Any");
1100 member.Name = membersScope.AddUnique(member.Name, member);
1101 members.Add(member.Name, member);
1102 member.TypeDesc = ((TypeMapping)accessors[0].Mapping).TypeDesc;
1104 bool repeats = any.IsMultipleOccurrence;
1106 if (mixed) {
1107 SpecialMapping textMapping = new SpecialMapping();
1108 textMapping.TypeDesc = Scope.GetTypeDesc(typeof(XmlNode));
1109 textMapping.TypeName = textMapping.TypeDesc.Name;
1110 member.TypeDesc = textMapping.TypeDesc;
1111 TextAccessor text = new TextAccessor();
1112 text.Mapping = textMapping;
1113 member.Text = text;
1114 repeats = true;
1115 mixed = false;
1118 if (repeats) {
1119 member.TypeDesc = member.TypeDesc.CreateArrayTypeDesc();
1121 return member;
1123 ElementAccessor[] ImportAny(XmlSchemaAny any, bool makeElement, string targetNamespace) {
1124 SpecialMapping mapping = new SpecialMapping();
1126 mapping.TypeDesc = Scope.GetTypeDesc(makeElement ? typeof(XmlElement) : typeof(XmlNode));
1127 mapping.TypeName = mapping.TypeDesc.Name;
1130 TypeFlags flags = TypeFlags.CanBeElementValue;
1131 if (makeElement)
1132 flags |= TypeFlags.CanBeTextValue;
1134 // let the extensions to run
1135 RunSchemaExtensions(mapping, XmlQualifiedName.Empty, null, any, flags);
1137 if (GenerateOrder && any.Namespace != null) {
1138 NamespaceList list = new NamespaceList(any.Namespace, targetNamespace);
1140 if (list.Type == NamespaceList.ListType.Set) {
1141 ICollection namespaces = list.Enumerate;
1142 ElementAccessor[] accessors = new ElementAccessor[namespaces.Count == 0 ? 1 : namespaces.Count];
1143 int count = 0;
1144 foreach(string ns in list.Enumerate) {
1145 ElementAccessor accessor = new ElementAccessor();
1146 accessor.Mapping = mapping;
1147 accessor.Any = true;
1148 accessor.Namespace = ns;
1149 accessors[count++] = accessor;
1151 if (count > 0) {
1152 return accessors;
1157 ElementAccessor anyAccessor = new ElementAccessor();
1158 anyAccessor.Mapping = mapping;
1159 anyAccessor.Any = true;
1160 return new ElementAccessor[] {anyAccessor};
1163 ElementAccessor ImportArray(XmlSchemaElement element, string identifier, string ns, bool repeats) {
1164 if (repeats) return null;
1165 if (element.SchemaType == null) return null;
1166 if (element.IsMultipleOccurrence) return null;
1167 XmlSchemaType type = element.SchemaType;
1168 ArrayMapping arrayMapping = ImportArrayMapping(type, identifier, ns, repeats);
1169 if (arrayMapping == null) return null;
1170 ElementAccessor arrayAccessor = new ElementAccessor();
1171 arrayAccessor.Name = element.Name;
1172 arrayAccessor.Namespace = ns;
1173 arrayAccessor.Mapping = arrayMapping;
1174 if (arrayMapping.TypeDesc.IsNullable)
1175 arrayAccessor.IsNullable = element.IsNillable;
1176 arrayAccessor.Form = ElementForm(ns, element);
1177 return arrayAccessor;
1180 ArrayMapping ImportArrayMapping(XmlSchemaType type, string identifier, string ns, bool repeats) {
1181 if (!(type is XmlSchemaComplexType)) return null;
1182 if (!type.DerivedFrom.IsEmpty) return null;
1183 if (IsMixed(type)) return null;
1185 Mapping previousMapping = (Mapping)ImportedMappings[type];
1186 if (previousMapping != null) {
1187 if (previousMapping is ArrayMapping)
1188 return (ArrayMapping)previousMapping;
1189 else
1190 return null;
1193 TypeItems items = GetTypeItems(type);
1195 if (items.Attributes != null && items.Attributes.Count > 0) return null;
1196 if (items.AnyAttribute != null) return null;
1197 if (items.Particle == null) return null;
1199 XmlSchemaGroupBase item = items.Particle;
1200 ArrayMapping arrayMapping = new ArrayMapping();
1202 arrayMapping.TypeName = identifier;
1203 arrayMapping.Namespace = ns;
1205 if (item is XmlSchemaChoice) {
1206 XmlSchemaChoice choice = (XmlSchemaChoice)item;
1207 if (!choice.IsMultipleOccurrence)
1208 return null;
1209 bool needExplicitOrder = false;
1210 MemberMapping choiceMember = ImportChoiceGroup(choice, identifier, null, null, null, ns, true, ref needExplicitOrder, false);
1211 if (choiceMember.ChoiceIdentifier != null) return null;
1212 arrayMapping.TypeDesc = choiceMember.TypeDesc;
1213 arrayMapping.Elements = choiceMember.Elements;
1214 arrayMapping.TypeName = (type.Name == null || type.Name.Length == 0) ? "ArrayOf" + CodeIdentifier.MakePascal(arrayMapping.TypeDesc.Name) : type.Name;
1216 else if (item is XmlSchemaAll || item is XmlSchemaSequence) {
1217 if (item.Items.Count != 1 || !(item.Items[0] is XmlSchemaElement)) return null;
1218 XmlSchemaElement itemElement = (XmlSchemaElement)item.Items[0];
1219 if (!itemElement.IsMultipleOccurrence) return null;
1220 if (IsCyclicReferencedType(itemElement, new List<string>(1){identifier}))
1222 return null;
1225 ElementAccessor itemAccessor = ImportElement(itemElement, identifier, typeof(TypeMapping), null, ns, false);
1226 if (itemAccessor.Any)
1227 return null;
1228 arrayMapping.Elements = new ElementAccessor[] { itemAccessor };
1229 arrayMapping.TypeDesc = ((TypeMapping)itemAccessor.Mapping).TypeDesc.CreateArrayTypeDesc();
1230 arrayMapping.TypeName = (type.Name == null || type.Name.Length == 0) ? "ArrayOf" + CodeIdentifier.MakePascal(itemAccessor.Mapping.TypeDesc.Name) : type.Name;
1232 else {
1233 return null;
1236 ImportedMappings[type] = arrayMapping;
1237 Scope.AddTypeMapping(arrayMapping);
1238 // for the array-like mappings we need to create a struct mapping for the case when it referenced by the top-level element
1239 arrayMapping.TopLevelMapping = ImportStructType(type, ns, identifier, null, true);
1240 arrayMapping.TopLevelMapping.ReferencedByTopLevelElement = true;
1241 if (type.Name != null && type.Name.Length != 0)
1242 ImportDerivedTypes(new XmlQualifiedName(identifier, ns));
1244 return arrayMapping;
1247 bool IsCyclicReferencedType(XmlSchemaElement element, List<string> identifiers)
1249 if (!element.RefName.IsEmpty)
1251 XmlSchemaElement refElement = FindElement(element.RefName);
1252 string refElementIdentifier = CodeIdentifier.MakeValid(Accessor.UnescapeName(refElement.Name));
1253 foreach (string identifier in identifiers)
1255 if (refElementIdentifier == identifier)
1257 return true;
1260 identifiers.Add(refElementIdentifier);
1262 XmlSchemaType refType = refElement.SchemaType;
1263 if (refType is XmlSchemaComplexType)
1265 TypeItems items = GetTypeItems(refType);
1266 if ((items.Particle is XmlSchemaSequence || items.Particle is XmlSchemaAll) && items.Particle.Items.Count == 1 && items.Particle.Items[0] is XmlSchemaElement)
1268 XmlSchemaElement innerRefElement = (XmlSchemaElement)items.Particle.Items[0];
1269 if (innerRefElement.IsMultipleOccurrence)
1271 return IsCyclicReferencedType(innerRefElement, identifiers);
1276 return false;
1279 SpecialMapping ImportAnyMapping(XmlSchemaType type, string identifier, string ns, bool repeats) {
1280 if (type == null) return null;
1281 if (!type.DerivedFrom.IsEmpty) return null;
1283 bool mixed = IsMixed(type);
1284 TypeItems items = GetTypeItems(type);
1285 if (items.Particle == null) return null;
1286 if (!(items.Particle is XmlSchemaAll || items.Particle is XmlSchemaSequence)) return null;
1287 if (items.Attributes != null && items.Attributes.Count > 0) return null;
1288 XmlSchemaGroupBase group = (XmlSchemaGroupBase) items.Particle;
1290 if (group.Items.Count != 1 || !(group.Items[0] is XmlSchemaAny)) return null;
1291 XmlSchemaAny any = (XmlSchemaAny)group.Items[0];
1293 SpecialMapping mapping = new SpecialMapping();
1294 // check for special named any case
1295 if (items.AnyAttribute != null && any.IsMultipleOccurrence && mixed) {
1296 mapping.NamedAny = true;
1297 mapping.TypeDesc = Scope.GetTypeDesc(typeof(XmlElement));
1299 else if (items.AnyAttribute != null || any.IsMultipleOccurrence) {
1300 // these only work for named any case -- otherwise import as struct
1301 return null;
1303 else {
1304 mapping.TypeDesc = Scope.GetTypeDesc(mixed ? typeof(XmlNode) : typeof(XmlElement));
1307 TypeFlags flags = TypeFlags.CanBeElementValue;
1308 if (items.AnyAttribute != null || mixed)
1309 flags |= TypeFlags.CanBeTextValue;
1311 // let the extensions to run
1312 RunSchemaExtensions(mapping, XmlQualifiedName.Empty, null, any, flags);
1314 mapping.TypeName = mapping.TypeDesc.Name;
1315 if (repeats)
1316 mapping.TypeDesc = mapping.TypeDesc.CreateArrayTypeDesc();
1318 return mapping;
1321 void ImportElementMember(XmlSchemaElement element, string identifier, CodeIdentifiers members, CodeIdentifiers membersScope, INameScope elementsScope, string ns, bool repeats, ref bool needExplicitOrder, bool allowDuplicates, bool allowUnboundedElements) {
1322 repeats = repeats | element.IsMultipleOccurrence;
1323 XmlSchemaElement headElement = GetTopLevelElement(element);
1324 if (headElement != null && ImportSubstitutionGroupMember(headElement, identifier, members, membersScope, ns, repeats, ref needExplicitOrder, allowDuplicates)) {
1325 return;
1327 ElementAccessor accessor;
1328 if ((accessor = ImportArray(element, identifier, ns, repeats)) == null) {
1329 accessor = ImportElement(element, identifier, typeof(TypeMapping), null, ns, false);
1332 MemberMapping member = new MemberMapping();
1333 string name = CodeIdentifier.MakeValid(Accessor.UnescapeName(accessor.Name));
1334 member.Name = membersScope.AddUnique(name, member);
1336 if (member.Name.EndsWith("Specified", StringComparison.Ordinal)) {
1337 name = member.Name;
1338 member.Name = membersScope.AddUnique(member.Name, member);
1339 membersScope.Remove(name);
1341 members.Add(member.Name, member);
1342 // we do not support lists for elements
1343 if (accessor.Mapping.IsList) {
1344 accessor.Mapping = GetDefaultMapping(TypeFlags.CanBeElementValue | TypeFlags.CanBeTextValue);
1345 member.TypeDesc = accessor.Mapping.TypeDesc;
1347 else {
1348 member.TypeDesc = accessor.Mapping.TypeDesc;
1351 AddScopeElement(elementsScope, accessor, ref needExplicitOrder, allowDuplicates);
1352 member.Elements = new ElementAccessor[] { accessor };
1354 if (element.IsMultipleOccurrence || repeats) {
1355 if (!allowUnboundedElements && accessor.Mapping is ArrayMapping) {
1356 accessor.Mapping = ((ArrayMapping)accessor.Mapping).TopLevelMapping;
1357 accessor.Mapping.ReferencedByTopLevelElement = false;
1358 accessor.Mapping.ReferencedByElement = true;
1360 member.TypeDesc = accessor.Mapping.TypeDesc.CreateArrayTypeDesc();
1363 if (element.MinOccurs == 0 && member.TypeDesc.IsValueType && !element.HasDefault && !member.TypeDesc.HasIsEmpty) {
1364 member.CheckSpecified = SpecifiedAccessor.ReadWrite;
1368 void ImportAttributeMember(XmlSchemaAttribute attribute, string identifier, CodeIdentifiers members, CodeIdentifiers membersScope, string ns) {
1369 AttributeAccessor accessor = ImportAttribute(attribute, identifier, ns, attribute);
1370 if (accessor == null) return;
1371 MemberMapping member = new MemberMapping();
1372 member.Elements = new ElementAccessor[0];
1373 member.Attribute = accessor;
1374 member.Name = CodeIdentifier.MakeValid(Accessor.UnescapeName(accessor.Name));
1375 member.Name = membersScope.AddUnique(member.Name, member);
1376 if (member.Name.EndsWith("Specified", StringComparison.Ordinal)) {
1377 string name = member.Name;
1378 member.Name = membersScope.AddUnique(member.Name, member);
1379 membersScope.Remove(name);
1381 members.Add(member.Name, member);
1382 member.TypeDesc = accessor.IsList ? accessor.Mapping.TypeDesc.CreateArrayTypeDesc() : accessor.Mapping.TypeDesc;
1384 if ((attribute.Use == XmlSchemaUse.Optional || attribute.Use == XmlSchemaUse.None) && member.TypeDesc.IsValueType && !attribute.HasDefault && !member.TypeDesc.HasIsEmpty) {
1385 member.CheckSpecified = SpecifiedAccessor.ReadWrite;
1389 void ImportAnyAttributeMember(XmlSchemaAnyAttribute any, CodeIdentifiers members, CodeIdentifiers membersScope) {
1390 SpecialMapping mapping = new SpecialMapping();
1391 mapping.TypeDesc = Scope.GetTypeDesc(typeof(XmlAttribute));
1392 mapping.TypeName = mapping.TypeDesc.Name;
1394 AttributeAccessor accessor = new AttributeAccessor();
1395 accessor.Any = true;
1396 accessor.Mapping = mapping;
1398 MemberMapping member = new MemberMapping();
1399 member.Elements = new ElementAccessor[0];
1400 member.Attribute = accessor;
1401 member.Name = membersScope.MakeRightCase("AnyAttr");
1402 member.Name = membersScope.AddUnique(member.Name, member);
1403 members.Add(member.Name, member);
1404 member.TypeDesc = ((TypeMapping)accessor.Mapping).TypeDesc;
1405 member.TypeDesc = member.TypeDesc.CreateArrayTypeDesc();
1408 bool KeepXmlnsDeclarations(XmlSchemaType type, out string xmlnsMemberName) {
1409 xmlnsMemberName = null;
1410 if (type.Annotation == null)
1411 return false;
1412 if (type.Annotation.Items == null || type.Annotation.Items.Count == 0)
1413 return false;
1415 foreach(XmlSchemaObject o in type.Annotation.Items) {
1416 if (o is XmlSchemaAppInfo) {
1417 XmlNode[] nodes = ((XmlSchemaAppInfo)o).Markup;
1418 if (nodes != null && nodes.Length > 0) {
1419 foreach(XmlNode node in nodes) {
1420 if (node is XmlElement) {
1421 XmlElement e = (XmlElement)node;
1422 if (e.Name == "keepNamespaceDeclarations") {
1423 if (e.LastNode is XmlText) {
1424 xmlnsMemberName = (((XmlText)e.LastNode).Value).Trim(null);
1426 return true;
1433 return false;
1436 void ImportXmlnsDeclarationsMember(XmlSchemaType type, CodeIdentifiers members, CodeIdentifiers membersScope) {
1437 string xmlnsMemberName;
1438 if (!KeepXmlnsDeclarations(type, out xmlnsMemberName))
1439 return;
1440 TypeDesc xmlnsTypeDesc = Scope.GetTypeDesc(typeof(XmlSerializerNamespaces));
1441 StructMapping xmlnsMapping = new StructMapping();
1443 xmlnsMapping.TypeDesc = xmlnsTypeDesc;
1444 xmlnsMapping.TypeName = xmlnsMapping.TypeDesc.Name;
1445 xmlnsMapping.Members = new MemberMapping[0];
1446 xmlnsMapping.IncludeInSchema = false;
1447 xmlnsMapping.ReferencedByTopLevelElement = true;
1449 ElementAccessor xmlns = new ElementAccessor();
1450 xmlns.Mapping = xmlnsMapping;
1452 MemberMapping member = new MemberMapping();
1453 member.Elements = new ElementAccessor[] {xmlns};
1454 member.Name = CodeIdentifier.MakeValid(xmlnsMemberName == null ? "Namespaces" : xmlnsMemberName);
1455 member.Name = membersScope.AddUnique(member.Name, member);
1456 members.Add(member.Name, member);
1457 member.TypeDesc = xmlnsTypeDesc;
1458 member.Xmlns = new XmlnsAccessor();
1459 member.Ignore = true;
1462 void ImportAttributeGroupMembers(XmlSchemaAttributeGroup group, string identifier, CodeIdentifiers members, CodeIdentifiers membersScope, string ns) {
1463 for (int i = 0; i < group.Attributes.Count; i++) {
1464 object item = group.Attributes[i];
1465 if (item is XmlSchemaAttributeGroup)
1466 ImportAttributeGroupMembers((XmlSchemaAttributeGroup)item, identifier, members, membersScope, ns);
1467 else if (item is XmlSchemaAttribute)
1468 ImportAttributeMember((XmlSchemaAttribute)item, identifier, members, membersScope, ns);
1470 if (group.AnyAttribute != null)
1471 ImportAnyAttributeMember(group.AnyAttribute, members, membersScope);
1474 AttributeAccessor ImportSpecialAttribute(XmlQualifiedName name, string identifier) {
1475 PrimitiveMapping mapping = new PrimitiveMapping();
1476 mapping.TypeDesc = Scope.GetTypeDesc(typeof(string));
1477 mapping.TypeName = mapping.TypeDesc.DataType.Name;
1478 AttributeAccessor accessor = new AttributeAccessor();
1479 accessor.Name = name.Name;
1480 accessor.Namespace = XmlReservedNs.NsXml;
1481 accessor.CheckSpecial();
1482 accessor.Mapping = mapping;
1483 return accessor;
1486 AttributeAccessor ImportAttribute(XmlSchemaAttribute attribute, string identifier, string ns, XmlSchemaAttribute defaultValueProvider) {
1487 if (attribute.Use == XmlSchemaUse.Prohibited) return null;
1488 if (!attribute.RefName.IsEmpty) {
1489 if (attribute.RefName.Namespace == XmlReservedNs.NsXml)
1490 return ImportSpecialAttribute(attribute.RefName, identifier);
1491 else
1492 return ImportAttribute(FindAttribute(attribute.RefName), identifier, attribute.RefName.Namespace, defaultValueProvider);
1494 TypeMapping mapping;
1495 if (attribute.Name.Length == 0) throw new InvalidOperationException(Res.GetString(Res.XmlAttributeHasNoName));
1496 if (identifier.Length == 0)
1497 identifier = CodeIdentifier.MakeValid(attribute.Name);
1498 else
1499 identifier += CodeIdentifier.MakePascal(attribute.Name);
1500 if (!attribute.SchemaTypeName.IsEmpty)
1501 mapping = (TypeMapping)ImportType(attribute.SchemaTypeName, typeof(TypeMapping), null, TypeFlags.CanBeAttributeValue, false);
1502 else if (attribute.SchemaType != null)
1503 mapping = ImportDataType((XmlSchemaSimpleType)attribute.SchemaType, ns, identifier, null, TypeFlags.CanBeAttributeValue, false);
1504 else {
1505 mapping = GetDefaultMapping(TypeFlags.CanBeAttributeValue);
1508 // let the extensions to run
1509 if (mapping != null && !mapping.TypeDesc.IsMappedType) {
1510 RunSchemaExtensions(mapping, attribute.SchemaTypeName, attribute.SchemaType, attribute, TypeFlags.CanBeElementValue | TypeFlags.CanBeAttributeValue | TypeFlags.CanBeTextValue);
1512 AttributeAccessor accessor = new AttributeAccessor();
1513 accessor.Name = attribute.Name;
1514 accessor.Namespace = ns;
1515 accessor.Form = AttributeForm(ns, attribute);
1516 accessor.CheckSpecial();
1517 accessor.Mapping = mapping;
1518 accessor.IsList = mapping.IsList;
1519 accessor.IsOptional = attribute.Use != XmlSchemaUse.Required;
1521 if (defaultValueProvider.DefaultValue != null) {
1522 accessor.Default = defaultValueProvider.DefaultValue;
1524 else if (defaultValueProvider.FixedValue != null) {
1525 accessor.Default = defaultValueProvider.FixedValue;
1526 accessor.IsFixed = true;
1528 else if (attribute != defaultValueProvider) {
1529 if (attribute.DefaultValue != null) {
1530 accessor.Default = attribute.DefaultValue;
1532 else if (attribute.FixedValue != null) {
1533 accessor.Default = attribute.FixedValue;
1534 accessor.IsFixed = true;
1537 return accessor;
1540 TypeMapping ImportDataType(XmlSchemaSimpleType dataType, string typeNs, string identifier, Type baseType, TypeFlags flags, bool isList) {
1541 if (baseType != null)
1542 return ImportStructDataType(dataType, typeNs, identifier, baseType);
1544 TypeMapping mapping = ImportNonXsdPrimitiveDataType(dataType, typeNs, flags);
1545 if (mapping != null)
1546 return mapping;
1548 if (dataType.Content is XmlSchemaSimpleTypeRestriction) {
1549 XmlSchemaSimpleTypeRestriction restriction = (XmlSchemaSimpleTypeRestriction)dataType.Content;
1550 foreach (object o in restriction.Facets) {
1551 if (o is XmlSchemaEnumerationFacet) {
1552 return ImportEnumeratedDataType(dataType, typeNs, identifier, flags, isList);
1555 if (restriction.BaseType != null) {
1556 return ImportDataType(restriction.BaseType, typeNs, identifier, null, flags, false);
1558 else {
1559 AddReference(restriction.BaseTypeName, TypesInUse, Res.XmlCircularTypeReference);
1560 mapping = ImportDataType(FindDataType(restriction.BaseTypeName, flags), restriction.BaseTypeName.Namespace, identifier, null, flags, false);
1561 if (restriction.BaseTypeName.Namespace != XmlSchema.Namespace)
1562 RemoveReference(restriction.BaseTypeName, TypesInUse);
1563 return mapping;
1566 else if (dataType.Content is XmlSchemaSimpleTypeList || dataType.Content is XmlSchemaSimpleTypeUnion) {
1567 if (dataType.Content is XmlSchemaSimpleTypeList) {
1568 // check if we have enumeration list
1569 XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList)dataType.Content;
1570 if (list.ItemType != null) {
1571 mapping = ImportDataType(list.ItemType, typeNs, identifier, null, flags, true);
1572 if (mapping != null) {
1573 mapping.TypeName = dataType.Name;
1574 return mapping;
1577 else if (list.ItemTypeName != null && !list.ItemTypeName.IsEmpty) {
1578 mapping = ImportType(list.ItemTypeName, typeof(TypeMapping), null, TypeFlags.CanBeAttributeValue, true);
1579 if (mapping != null && mapping is PrimitiveMapping) {
1580 ((PrimitiveMapping)mapping).IsList = true;
1581 return mapping;
1585 return GetDefaultMapping(flags);
1587 return ImportPrimitiveDataType(dataType, flags);
1590 TypeMapping ImportEnumeratedDataType(XmlSchemaSimpleType dataType, string typeNs, string identifier, TypeFlags flags, bool isList) {
1591 TypeMapping mapping = (TypeMapping)ImportedMappings[dataType];
1592 if (mapping != null)
1593 return mapping;
1595 XmlSchemaType sourceType = dataType;
1596 while (!sourceType.DerivedFrom.IsEmpty) {
1597 sourceType = FindType(sourceType.DerivedFrom, TypeFlags.CanBeElementValue | TypeFlags.CanBeAttributeValue);
1599 if (sourceType is XmlSchemaComplexType) return null;
1600 TypeDesc sourceTypeDesc = Scope.GetTypeDesc((XmlSchemaSimpleType)sourceType);
1601 if (sourceTypeDesc != null && sourceTypeDesc.FullName != typeof(string).FullName)
1602 return ImportPrimitiveDataType(dataType, flags);
1603 identifier = Accessor.UnescapeName(identifier);
1604 string typeName = GenerateUniqueTypeName(identifier);
1605 EnumMapping enumMapping = new EnumMapping();
1606 enumMapping.IsReference = Schemas.IsReference(dataType);
1607 enumMapping.TypeDesc = new TypeDesc(typeName, typeName, TypeKind.Enum, null, 0);
1608 if (dataType.Name != null && dataType.Name.Length > 0)
1609 enumMapping.TypeName = identifier;
1610 enumMapping.Namespace = typeNs;
1611 enumMapping.IsFlags = isList;
1613 CodeIdentifiers constants = new CodeIdentifiers();
1614 XmlSchemaSimpleTypeContent content = dataType.Content;
1616 if (content is XmlSchemaSimpleTypeRestriction) {
1617 XmlSchemaSimpleTypeRestriction restriction = (XmlSchemaSimpleTypeRestriction)content;
1618 for (int i = 0; i < restriction.Facets.Count; i++) {
1619 object facet = restriction.Facets[i];
1620 if (!(facet is XmlSchemaEnumerationFacet)) continue;
1621 XmlSchemaEnumerationFacet enumeration = (XmlSchemaEnumerationFacet)facet;
1622 // validate the enumeration value
1623 if (sourceTypeDesc != null && sourceTypeDesc.HasCustomFormatter) {
1624 XmlCustomFormatter.ToDefaultValue(enumeration.Value, sourceTypeDesc.FormatterName);
1626 ConstantMapping constant = new ConstantMapping();
1627 string constantName = CodeIdentifier.MakeValid(enumeration.Value);
1628 constant.Name = constants.AddUnique(constantName, constant);
1629 constant.XmlName = enumeration.Value;
1630 constant.Value = i;
1633 enumMapping.Constants = (ConstantMapping[])constants.ToArray(typeof(ConstantMapping));
1634 if (isList && enumMapping.Constants.Length > 63) {
1635 // if we have 64+ flag constants we cannot map the type to long enum, we will use string mapping instead.
1636 mapping = GetDefaultMapping(TypeFlags.CanBeElementValue | TypeFlags.CanBeTextValue | TypeFlags.CanBeAttributeValue);
1637 ImportedMappings.Add(dataType, mapping);
1638 return mapping;
1640 ImportedMappings.Add(dataType, enumMapping);
1641 Scope.AddTypeMapping(enumMapping);
1642 return enumMapping;
1645 internal class ElementComparer : IComparer {
1646 public int Compare(object o1, object o2) {
1647 ElementAccessor e1 = (ElementAccessor)o1;
1648 ElementAccessor e2 = (ElementAccessor)o2;
1649 return String.Compare(e1.ToString(string.Empty), e2.ToString(string.Empty), StringComparison.Ordinal);
1653 EnumMapping ImportEnumeratedChoice(ElementAccessor[] choice, string typeNs, string typeName) {
1654 typeName = GenerateUniqueTypeName(Accessor.UnescapeName(typeName), typeNs);
1655 EnumMapping enumMapping = new EnumMapping();
1656 enumMapping.TypeDesc = new TypeDesc(typeName, typeName, TypeKind.Enum, null, 0);
1657 enumMapping.TypeName = typeName;
1658 enumMapping.Namespace = typeNs;
1659 enumMapping.IsFlags = false;
1660 enumMapping.IncludeInSchema = false;
1662 if (GenerateOrder) {
1663 Array.Sort(choice, new ElementComparer());
1665 CodeIdentifiers constants = new CodeIdentifiers();
1666 for (int i = 0; i < choice.Length; i++) {
1667 ElementAccessor element = choice[i];
1668 ConstantMapping constant = new ConstantMapping();
1669 string constantName = CodeIdentifier.MakeValid(element.Name);
1670 constant.Name = constants.AddUnique(constantName, constant);
1671 constant.XmlName = element.ToString(typeNs);
1672 constant.Value = i;
1674 enumMapping.Constants = (ConstantMapping[])constants.ToArray(typeof(ConstantMapping));
1675 Scope.AddTypeMapping(enumMapping);
1676 return enumMapping;
1679 PrimitiveMapping ImportPrimitiveDataType(XmlSchemaSimpleType dataType, TypeFlags flags) {
1680 TypeDesc sourceTypeDesc = GetDataTypeSource(dataType, flags);
1681 PrimitiveMapping mapping = new PrimitiveMapping();
1682 mapping.TypeDesc = sourceTypeDesc;
1683 mapping.TypeName = sourceTypeDesc.DataType.Name;
1684 mapping.Namespace = mapping.TypeDesc.IsXsdType ? XmlSchema.Namespace : UrtTypes.Namespace;
1685 return mapping;
1688 PrimitiveMapping ImportNonXsdPrimitiveDataType(XmlSchemaSimpleType dataType, string ns, TypeFlags flags) {
1689 PrimitiveMapping mapping = null;
1690 TypeDesc typeDesc = null;
1691 if (dataType.Name != null && dataType.Name.Length != 0) {
1692 typeDesc = Scope.GetTypeDesc(dataType.Name, ns, flags);
1693 if (typeDesc != null) {
1694 mapping = new PrimitiveMapping();
1695 mapping.TypeDesc = typeDesc;
1696 mapping.TypeName = typeDesc.DataType.Name;
1697 mapping.Namespace = mapping.TypeDesc.IsXsdType ? XmlSchema.Namespace : ns;
1700 return mapping;
1703 XmlSchemaGroup FindGroup(XmlQualifiedName name) {
1704 XmlSchemaGroup group = (XmlSchemaGroup)Schemas.Find(name, typeof(XmlSchemaGroup));
1705 if (group == null)
1706 throw new InvalidOperationException(Res.GetString(Res.XmlMissingGroup, name.Name));
1708 return group;
1711 XmlSchemaAttributeGroup FindAttributeGroup(XmlQualifiedName name) {
1712 XmlSchemaAttributeGroup group = (XmlSchemaAttributeGroup)Schemas.Find(name, typeof(XmlSchemaAttributeGroup));
1713 if (group == null)
1714 throw new InvalidOperationException(Res.GetString(Res.XmlMissingAttributeGroup, name.Name));
1716 return group;
1719 internal static XmlQualifiedName BaseTypeName(XmlSchemaSimpleType dataType) {
1720 XmlSchemaSimpleTypeContent content = dataType.Content;
1721 if (content is XmlSchemaSimpleTypeRestriction) {
1722 return ((XmlSchemaSimpleTypeRestriction)content).BaseTypeName;
1724 else if (content is XmlSchemaSimpleTypeList) {
1725 XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList)content;
1726 if (list.ItemTypeName != null && !list.ItemTypeName.IsEmpty)
1727 return list.ItemTypeName;
1728 if (list.ItemType != null) {
1729 return BaseTypeName(list.ItemType);
1732 return new XmlQualifiedName("string", XmlSchema.Namespace);
1735 TypeDesc GetDataTypeSource(XmlSchemaSimpleType dataType, TypeFlags flags) {
1736 TypeDesc typeDesc = null;
1737 if (dataType.Name != null && dataType.Name.Length != 0) {
1738 typeDesc = Scope.GetTypeDesc(dataType);
1739 if (typeDesc != null) return typeDesc;
1741 XmlQualifiedName qname = BaseTypeName(dataType);
1742 AddReference(qname, TypesInUse, Res.XmlCircularTypeReference);
1743 typeDesc = GetDataTypeSource(FindDataType(qname, flags), flags);
1744 if (qname.Namespace != XmlSchema.Namespace)
1745 RemoveReference(qname, TypesInUse);
1747 return typeDesc;
1750 XmlSchemaSimpleType FindDataType(XmlQualifiedName name, TypeFlags flags) {
1751 if (name == null || name.IsEmpty) {
1752 return (XmlSchemaSimpleType)Scope.GetTypeDesc(typeof(string)).DataType;
1754 TypeDesc typeDesc = Scope.GetTypeDesc(name.Name, name.Namespace, flags);
1755 if (typeDesc != null && typeDesc.DataType is XmlSchemaSimpleType)
1756 return (XmlSchemaSimpleType)typeDesc.DataType;
1757 XmlSchemaSimpleType dataType = (XmlSchemaSimpleType)Schemas.Find(name, typeof(XmlSchemaSimpleType));
1758 if (dataType != null) {
1759 return dataType;
1761 if (name.Namespace == XmlSchema.Namespace)
1762 return (XmlSchemaSimpleType)Scope.GetTypeDesc("string", XmlSchema.Namespace, flags).DataType;
1763 else {
1764 if (name.Name == Soap.Array && name.Namespace == Soap.Encoding) {
1765 throw new InvalidOperationException(Res.GetString(Res.XmlInvalidEncoding, name.ToString()));
1767 else {
1768 throw new InvalidOperationException(Res.GetString(Res.XmlMissingDataType, name.ToString()));
1773 XmlSchemaType FindType(XmlQualifiedName name, TypeFlags flags) {
1774 if (name == null || name.IsEmpty) {
1775 return Scope.GetTypeDesc(typeof(string)).DataType;
1777 object type = Schemas.Find(name, typeof(XmlSchemaComplexType));
1778 if (type != null) {
1779 return (XmlSchemaComplexType)type;
1781 return FindDataType(name, flags);
1784 XmlSchemaElement FindElement(XmlQualifiedName name) {
1785 XmlSchemaElement element = (XmlSchemaElement)Schemas.Find(name, typeof(XmlSchemaElement));
1786 if (element == null)
1787 throw new InvalidOperationException(Res.GetString(Res.XmlMissingElement, name.ToString()));
1788 return element;
1791 XmlSchemaAttribute FindAttribute(XmlQualifiedName name) {
1792 XmlSchemaAttribute attribute = (XmlSchemaAttribute)Schemas.Find(name, typeof(XmlSchemaAttribute));
1793 if (attribute == null)
1794 throw new InvalidOperationException(Res.GetString(Res.XmlMissingAttribute, name.Name));
1796 return attribute;
1799 XmlSchemaForm ElementForm(string ns, XmlSchemaElement element) {
1800 if (element.Form == XmlSchemaForm.None) {
1801 XmlSchemaObject parent = element;
1802 while (parent.Parent != null) {
1803 parent = parent.Parent;
1805 XmlSchema schema = parent as XmlSchema;
1807 if (schema != null) {
1808 if (ns == null || ns.Length == 0) {
1809 return schema.ElementFormDefault == XmlSchemaForm.None ? XmlSchemaForm.Unqualified : schema.ElementFormDefault;
1811 else {
1812 XmlSchemas.Preprocess(schema);
1813 return element.QualifiedName.Namespace == null || element.QualifiedName.Namespace.Length == 0 ? XmlSchemaForm.Unqualified : XmlSchemaForm.Qualified;
1816 return XmlSchemaForm.Qualified;
1818 return element.Form;
1821 internal string FindExtendedAnyElement(XmlSchemaAny any, bool mixed, CodeCompileUnit compileUnit, CodeNamespace mainNamespace, out SchemaImporterExtension extension) {
1822 extension = null;
1823 foreach (SchemaImporterExtension ex in Extensions) {
1824 string typeName = ex.ImportAnyElement(any, mixed, Schemas, this, compileUnit, mainNamespace, Options, CodeProvider);
1825 if (typeName != null && typeName.Length > 0) {
1826 extension = ex;
1827 return typeName;
1830 return null;
1833 internal string FindExtendedType(string name, string ns, XmlSchemaObject context, CodeCompileUnit compileUnit, CodeNamespace mainNamespace, out SchemaImporterExtension extension ) {
1834 extension = null;
1835 foreach (SchemaImporterExtension ex in Extensions) {
1836 string typeName = ex.ImportSchemaType(name, ns, context, Schemas, this, compileUnit, mainNamespace, Options, CodeProvider);
1837 if (typeName != null && typeName.Length > 0) {
1838 extension = ex;
1839 return typeName;
1842 return null;
1845 internal string FindExtendedType(XmlSchemaType type, XmlSchemaObject context, CodeCompileUnit compileUnit, CodeNamespace mainNamespace, out SchemaImporterExtension extension) {
1846 extension = null;
1847 foreach (SchemaImporterExtension ex in Extensions) {
1848 string typeName = ex.ImportSchemaType(type, context, Schemas, this, compileUnit, mainNamespace, Options, CodeProvider);
1849 if (typeName != null && typeName.Length > 0) {
1850 extension = ex;
1851 return typeName;
1854 return null;
1857 XmlSchemaForm AttributeForm(string ns, XmlSchemaAttribute attribute) {
1858 if (attribute.Form == XmlSchemaForm.None) {
1859 XmlSchemaObject parent = attribute;
1860 while (parent.Parent != null) {
1861 parent = parent.Parent;
1863 XmlSchema schema = parent as XmlSchema;
1864 if (schema != null) {
1865 if (ns == null || ns.Length == 0) {
1866 return schema.AttributeFormDefault == XmlSchemaForm.None ? XmlSchemaForm.Unqualified : schema.AttributeFormDefault;
1868 else {
1869 XmlSchemas.Preprocess(schema);
1870 return attribute.QualifiedName.Namespace == null || attribute.QualifiedName.Namespace.Length == 0 ? XmlSchemaForm.Unqualified : XmlSchemaForm.Qualified;
1873 return XmlSchemaForm.Unqualified;
1875 return attribute.Form;