2 // System.Xml.Serialization.XmlSchemaImporter
5 // Tim Coleman (tim@timcoleman.com)
6 // Lluis Sanchez Gual (lluis@ximian.com)
8 // Copyright (C) Tim Coleman, 2002
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System
.Xml
.Schema
;
34 using System
.Collections
;
36 namespace System
.Xml
.Serialization
38 public class XmlSchemaImporter
46 CodeIdentifiers typeIdentifiers
;
47 CodeIdentifiers elemIdentifiers
= new CodeIdentifiers ();
48 Hashtable mappedTypes
= new Hashtable ();
49 Hashtable dataMappedTypes
= new Hashtable ();
50 Queue pendingMaps
= new Queue ();
51 Hashtable sharedAnonymousTypes
= new Hashtable ();
52 bool encodedFormat
= false;
53 XmlReflectionImporter auxXmlRefImporter
;
54 SoapReflectionImporter auxSoapRefImporter
;
55 CodeGenerationOptions options
;
58 static readonly XmlQualifiedName anyType
= new XmlQualifiedName ("anyType",XmlSchema
.Namespace
);
59 static readonly XmlQualifiedName arrayType
= new XmlQualifiedName ("Array",XmlSerializer
.EncodingNamespace
);
60 static readonly XmlQualifiedName arrayTypeRefName
= new XmlQualifiedName ("arrayType",XmlSerializer
.EncodingNamespace
);
62 const string XmlNamespace
= "http://www.w3.org/XML/1998/namespace";
64 XmlSchemaElement anyElement
= null;
68 public XmlTypeMapping Map
;
69 public XmlSchemaComplexType SchemaType
;
70 public XmlQualifiedName TypeName
;
77 public XmlSchemaImporter (XmlSchemas schemas
)
79 this.schemas
= schemas
;
80 typeIdentifiers
= new CodeIdentifiers ();
83 public XmlSchemaImporter (XmlSchemas schemas
, CodeIdentifiers typeIdentifiers
)
86 this.typeIdentifiers
= typeIdentifiers
;
91 public XmlSchemaImporter (XmlSchemas schemas
, CodeGenerationOptions options
, System
.CodeDom
.Compiler
.ICodeGenerator codeGenerator
, ImportContext context
)
93 this.schemas
= schemas
;
94 this.options
= options
;
95 if (context
!= null) {
96 typeIdentifiers
= context
.TypeIdentifiers
;
97 InitSharedData (context
);
100 typeIdentifiers
= new CodeIdentifiers ();
103 public XmlSchemaImporter (XmlSchemas schemas
, CodeGenerationOptions options
, ImportContext context
)
105 this.schemas
= schemas
;
106 this.options
= options
;
107 if (context
!= null) {
108 typeIdentifiers
= context
.TypeIdentifiers
;
109 InitSharedData (context
);
112 typeIdentifiers
= new CodeIdentifiers ();
116 public XmlSchemaImporter (XmlSchemas schemas
, CodeIdentifiers typeIdentifiers
, CodeGenerationOptions options
)
118 this.typeIdentifiers
= typeIdentifiers
;
119 this.schemas
= schemas
;
120 this.options
= options
;
123 void InitSharedData (ImportContext context
)
125 if (context
.ShareTypes
) {
126 mappedTypes
= context
.MappedTypes
;
127 dataMappedTypes
= context
.DataMappedTypes
;
128 sharedAnonymousTypes
= context
.SharedAnonymousTypes
;
133 internal bool UseEncodedFormat
135 get { return encodedFormat; }
136 set { encodedFormat = value; }
139 #endregion // Constructors
143 public XmlMembersMapping
ImportAnyType (XmlQualifiedName typeName
, string elementName
)
145 if (typeName
== XmlQualifiedName
.Empty
)
147 XmlTypeMapMemberAnyElement mapMem
= new XmlTypeMapMemberAnyElement ();
148 mapMem
.Name
= typeName
.Name
;
149 mapMem
.TypeData
= TypeTranslator
.GetTypeData(typeof(XmlNode
));
150 mapMem
.ElementInfo
.Add (CreateElementInfo (typeName
.Namespace
, mapMem
, typeName
.Name
, mapMem
.TypeData
, true, XmlSchemaForm
.None
));
152 XmlMemberMapping
[] mm
= new XmlMemberMapping
[1];
153 mm
[0] = new XmlMemberMapping (typeName
.Name
, typeName
.Namespace
, mapMem
, encodedFormat
);
154 return new XmlMembersMapping (mm
);
158 XmlSchemaComplexType stype
= (XmlSchemaComplexType
) schemas
.Find (typeName
, typeof (XmlSchemaComplexType
));
160 throw new InvalidOperationException ("Referenced type '" + typeName
+ "' not found");
162 if (!CanBeAnyElement (stype
))
163 throw new InvalidOperationException ("The type '" + typeName
+ "' is not valid for a collection of any elements");
165 ClassMap cmap
= new ClassMap ();
166 CodeIdentifiers classIds
= new CodeIdentifiers ();
167 bool isMixed
= stype
.IsMixed
;
168 ImportSequenceContent (typeName
, cmap
, ((XmlSchemaSequence
) stype
.Particle
).Items
, classIds
, false, ref isMixed
);
169 XmlTypeMapMemberAnyElement mapMem
= (XmlTypeMapMemberAnyElement
) cmap
.AllMembers
[0];
170 mapMem
.Name
= typeName
.Name
;
172 XmlMemberMapping
[] mm
= new XmlMemberMapping
[1];
173 mm
[0] = new XmlMemberMapping (typeName
.Name
, typeName
.Namespace
, mapMem
, encodedFormat
);
174 return new XmlMembersMapping (mm
);
178 public XmlTypeMapping
ImportDerivedTypeMapping (XmlQualifiedName name
, Type baseType
)
180 return ImportDerivedTypeMapping (name
, baseType
, true);
183 public XmlTypeMapping
ImportDerivedTypeMapping (XmlQualifiedName name
, Type baseType
, bool baseTypeCanBeIndirect
)
185 XmlQualifiedName qname
;
191 stype
= schemas
.Find (name
, typeof (XmlSchemaComplexType
)) as XmlSchemaComplexType
;
192 if (stype
== null) throw new InvalidOperationException ("Schema type '" + name
+ "' not found or not valid");
196 if (!LocateElement (name
, out qname
, out stype
) || stype
== null)
200 XmlTypeMapping map
= GetRegisteredTypeMapping (qname
);
203 // If the type has already been imported, make sure that the map
204 // has the requested base type
206 SetMapBaseType (map
, baseType
);
207 map
.UpdateRoot (name
);
211 map
= CreateTypeMapping (qname
, SchemaTypes
.Class
, name
);
212 map
.Documentation
= GetDocumentation (stype
);
213 RegisterMapFixup (map
, qname
, (XmlSchemaComplexType
)stype
);
216 SetMapBaseType (map
, baseType
);
221 void SetMapBaseType (XmlTypeMapping map
, Type baseType
)
223 // This method sets the base type for a given map.
224 // If the map already inherits from this type, it does nothing.
226 // Fiirst of all, check if the map already inherits from baseType
228 XmlTypeMapping topMap
= null;
231 if (map
.TypeData
.Type
== baseType
)
237 // Does not have the requested base type.
238 // Then, get/create a map for that base type.
240 XmlTypeMapping baseMap
= ReflectType (baseType
, null);
242 // Add this map as a derived map of the base map
244 topMap
.BaseMap
= baseMap
;
245 baseMap
.DerivedTypes
.Add (topMap
);
246 baseMap
.DerivedTypes
.AddRange (topMap
.DerivedTypes
);
248 // Now add the base type fields to all derived maps
250 ClassMap baseClassMap
= (ClassMap
)baseMap
.ObjectMap
;
252 ClassMap cmap
= (ClassMap
)topMap
.ObjectMap
;
253 foreach (XmlTypeMapMember member
in baseClassMap
.AllMembers
)
254 cmap
.AddMember (member
);
256 foreach (XmlTypeMapping derivedMap
in topMap
.DerivedTypes
)
258 cmap
= (ClassMap
)derivedMap
.ObjectMap
;
259 foreach (XmlTypeMapMember member
in baseClassMap
.AllMembers
)
260 cmap
.AddMember (member
);
264 public XmlMembersMapping
ImportMembersMapping (XmlQualifiedName name
)
266 XmlSchemaElement elem
= (XmlSchemaElement
) schemas
.Find (name
, typeof (XmlSchemaElement
));
267 if (elem
== null) throw new InvalidOperationException ("Schema element '" + name
+ "' not found or not valid");
269 XmlSchemaComplexType stype
;
270 if (elem
.SchemaType
!= null)
272 stype
= elem
.SchemaType
as XmlSchemaComplexType
;
276 if (elem
.SchemaTypeName
.IsEmpty
) return null;
277 if (elem
.SchemaTypeName
.Namespace
== XmlSchema
.Namespace
) return null;
278 object type
= schemas
.Find (elem
.SchemaTypeName
, typeof (XmlSchemaComplexType
));
279 if (type
== null) throw new InvalidOperationException ("Schema type '" + elem
.SchemaTypeName
+ "' not found");
280 stype
= type
as XmlSchemaComplexType
;
284 throw new InvalidOperationException ("Schema element '" + name
+ "' not found or not valid");
286 XmlMemberMapping
[] mapping
= ImportMembersMappingComposite (stype
, name
);
287 return new XmlMembersMapping (name
.Name
, name
.Namespace
, mapping
);
290 public XmlMembersMapping
ImportMembersMapping (XmlQualifiedName
[] names
)
292 XmlMemberMapping
[] mapping
= new XmlMemberMapping
[names
.Length
];
293 for (int n
=0; n
<names
.Length
; n
++)
295 XmlSchemaElement elem
= (XmlSchemaElement
) schemas
.Find (names
[n
], typeof (XmlSchemaElement
));
296 if (elem
== null) throw new InvalidOperationException ("Schema element '" + names
[n
] + "' not found");
298 XmlQualifiedName typeQName
= new XmlQualifiedName ("Message", names
[n
].Namespace
);
300 TypeData td
= GetElementTypeData (typeQName
, elem
, names
[n
], out tmap
);
302 mapping
[n
] = ImportMemberMapping (elem
.Name
, typeQName
.Namespace
, elem
.IsNillable
, td
, tmap
);
305 return new XmlMembersMapping (mapping
);
310 public XmlMembersMapping
ImportMembersMapping (string name
, string ns
, SoapSchemaMember
[] members
)
312 throw new NotImplementedException ();
316 public XmlTypeMapping
ImportSchemaType (XmlQualifiedName typeName
)
318 throw new NotImplementedException ();
322 public XmlTypeMapping
ImportSchemaType (XmlQualifiedName typeName
, Type baseType
)
324 throw new NotImplementedException ();
328 public XmlTypeMapping
ImportSchemaType (XmlQualifiedName typeName
, Type baseType
, bool baseTypeCanBeIndirect
)
330 throw new NotImplementedException ();
334 internal XmlMembersMapping
ImportEncodedMembersMapping (string name
, string ns
, SoapSchemaMember
[] members
, bool hasWrapperElement
)
336 XmlMemberMapping
[] mapping
= new XmlMemberMapping
[members
.Length
];
337 for (int n
=0; n
<members
.Length
; n
++)
339 TypeData td
= GetTypeData (members
[n
].MemberType
, null);
340 XmlTypeMapping tmap
= GetTypeMapping (td
);
341 mapping
[n
] = ImportMemberMapping (members
[n
].MemberName
, members
[n
].MemberType
.Namespace
, true, td
, tmap
);
344 return new XmlMembersMapping (name
, ns
, hasWrapperElement
, false, mapping
);
347 internal XmlMembersMapping
ImportEncodedMembersMapping (string name
, string ns
, SoapSchemaMember member
)
349 XmlSchemaComplexType stype
= schemas
.Find (member
.MemberType
, typeof (XmlSchemaComplexType
)) as XmlSchemaComplexType
;
350 if (stype
== null) throw new InvalidOperationException ("Schema type '" + member
.MemberType
+ "' not found or not valid");
352 XmlMemberMapping
[] mapping
= ImportMembersMappingComposite (stype
, member
.MemberType
);
353 return new XmlMembersMapping (name
, ns
, mapping
);
356 XmlMemberMapping
[] ImportMembersMappingComposite (XmlSchemaComplexType stype
, XmlQualifiedName refer
)
358 if (stype
.Particle
== null)
359 return new XmlMemberMapping
[0];
361 ClassMap cmap
= new ClassMap ();
363 XmlSchemaSequence seq
= stype
.Particle
as XmlSchemaSequence
;
364 if (seq
== null) throw new InvalidOperationException ("Schema element '" + refer
+ "' cannot be imported as XmlMembersMapping");
366 CodeIdentifiers classIds
= new CodeIdentifiers ();
367 ImportParticleComplexContent (refer
, cmap
, seq
, classIds
, false);
368 ImportAttributes (refer
, cmap
, stype
.Attributes
, stype
.AnyAttribute
, classIds
);
373 XmlMemberMapping
[] mapping
= new XmlMemberMapping
[cmap
.AllMembers
.Count
];
374 foreach (XmlTypeMapMember mapMem
in cmap
.AllMembers
)
375 mapping
[n
++] = new XmlMemberMapping (mapMem
.Name
, refer
.Namespace
, mapMem
, encodedFormat
);
380 XmlMemberMapping
ImportMemberMapping (string name
, string ns
, bool isNullable
, TypeData type
, XmlTypeMapping emap
)
382 XmlTypeMapMemberElement mapMem
;
385 mapMem
= new XmlTypeMapMemberList ();
387 mapMem
= new XmlTypeMapMemberElement ();
390 mapMem
.TypeData
= type
;
391 mapMem
.ElementInfo
.Add (CreateElementInfo (ns
, mapMem
, name
, type
, isNullable
, XmlSchemaForm
.None
, emap
));
392 return new XmlMemberMapping (name
, ns
, mapMem
, encodedFormat
);
396 public XmlMembersMapping
ImportMembersMapping (XmlQualifiedName
[] names
, Type baseType
, bool baseTypeCanBeIndirect
)
398 throw new NotImplementedException ();
401 public XmlTypeMapping
ImportTypeMapping (XmlQualifiedName name
)
403 XmlQualifiedName qname
;
405 if (!LocateElement (name
, out qname
, out stype
)) return null;
408 // Importing a primitive type
409 TypeData td
= TypeTranslator
.GetPrimitiveTypeData (qname
.Name
);
410 return ReflectType (td
.Type
, name
.Namespace
);
413 XmlTypeMapping map
= GetRegisteredTypeMapping (qname
);
414 if (map
!= null) return map
;
416 map
= CreateTypeMapping (qname
, SchemaTypes
.Class
, name
);
417 map
.Documentation
= GetDocumentation (stype
);
418 RegisterMapFixup (map
, qname
, (XmlSchemaComplexType
)stype
);
424 bool LocateElement (XmlQualifiedName name
, out XmlQualifiedName qname
, out XmlSchemaType stype
)
429 XmlSchemaElement elem
= (XmlSchemaElement
) schemas
.Find (name
, typeof (XmlSchemaElement
));
430 if (elem
== null) return false;
432 // The root element must be an element with complex type
434 if (elem
.SchemaType
!= null)
436 stype
= elem
.SchemaType
;
441 if (elem
.SchemaTypeName
.IsEmpty
) return false;
443 if (elem
.SchemaTypeName
.Namespace
== XmlSchema
.Namespace
) {
444 qname
= elem
.SchemaTypeName
;
448 object type
= schemas
.Find (elem
.SchemaTypeName
, typeof (XmlSchemaComplexType
));
449 if (type
== null) type
= schemas
.Find (elem
.SchemaTypeName
, typeof (XmlSchemaSimpleType
));
450 if (type
== null) throw new InvalidOperationException ("Schema type '" + elem
.SchemaTypeName
+ "' not found");
451 stype
= (XmlSchemaType
) type
;
452 qname
= stype
.QualifiedName
;
454 XmlSchemaType btype
= stype
.BaseSchemaType
as XmlSchemaType
;
455 if (btype
!= null && btype
.QualifiedName
== elem
.SchemaTypeName
)
456 throw new InvalidOperationException ("Cannot import schema for type '" + elem
.SchemaTypeName
.Name
+ "' from namespace '" + elem
.SchemaTypeName
.Namespace
+ "'. Redefine not supported");
459 if (stype
is XmlSchemaSimpleType
) return false;
463 XmlTypeMapping
ImportType (XmlQualifiedName name
, XmlQualifiedName root
)
465 XmlTypeMapping map
= GetRegisteredTypeMapping (name
);
467 map
.UpdateRoot (root
);
471 XmlSchemaType type
= (XmlSchemaType
) schemas
.Find (name
, typeof (XmlSchemaComplexType
));
472 if (type
== null) type
= (XmlSchemaType
) schemas
.Find (name
, typeof (XmlSchemaSimpleType
));
476 if (name
.Namespace
== XmlSerializer
.EncodingNamespace
)
477 throw new InvalidOperationException ("Referenced type '" + name
+ "' valid only for encoded SOAP");
479 throw new InvalidOperationException ("Referenced type '" + name
+ "' not found");
482 return ImportType (name
, type
, root
);
485 XmlTypeMapping
ImportType (XmlQualifiedName name
, XmlSchemaType stype
, XmlQualifiedName root
)
487 XmlTypeMapping map
= GetRegisteredTypeMapping (name
);
489 XmlSchemaComplexType ct
= stype
as XmlSchemaComplexType
;
490 if (map
.TypeData
.SchemaType
!= SchemaTypes
.Class
|| ct
== null || !CanBeArray (name
, ct
)) {
491 map
.UpdateRoot (root
);
495 // The map was initially imported as a class, but it turns out that it is an
496 // array. It has to be imported now as array.
499 if (stype
is XmlSchemaComplexType
)
500 return ImportClassComplexType (name
, (XmlSchemaComplexType
) stype
, root
);
501 else if (stype
is XmlSchemaSimpleType
)
502 return ImportClassSimpleType (name
, (XmlSchemaSimpleType
) stype
, root
);
504 throw new NotSupportedException ("Schema type not supported: " + stype
.GetType ());
507 XmlTypeMapping
ImportClassComplexType (XmlQualifiedName typeQName
, XmlSchemaComplexType stype
, XmlQualifiedName root
)
511 // The need for fixups: If the complex type is an array, then to get the type of the
512 // array we need first to get the type of the items of the array.
513 // But if one of the item types or its children has a referece to this type array,
514 // then we enter in an infinite loop. This does not happen with class types because
515 // the class map is registered before parsing the children. We can't do the same
516 // with the array type because to register the array map we need the type of the array.
518 Type anyType
= GetAnyElementType (stype
);
520 return GetTypeMapping (TypeTranslator
.GetTypeData(anyType
));
522 if (CanBeArray (typeQName
, stype
))
525 ListMap listMap
= BuildArrayMap (typeQName
, stype
, out typeData
);
528 map
= CreateArrayTypeMapping (typeQName
, typeData
);
529 map
.ObjectMap
= listMap
;
533 // After all, it is not an array. Create a class map then.
535 else if (CanBeIXmlSerializable (stype
))
537 return ImportXmlSerializableMapping (typeQName
.Namespace
);
540 // Register the map right now but do not build it,
541 // This will avoid loops.
543 map
= CreateTypeMapping (typeQName
, SchemaTypes
.Class
, root
);
544 map
.Documentation
= GetDocumentation (stype
);
545 RegisterMapFixup (map
, typeQName
, stype
);
549 void RegisterMapFixup (XmlTypeMapping map
, XmlQualifiedName typeQName
, XmlSchemaComplexType stype
)
551 MapFixup fixup
= new MapFixup ();
553 fixup
.SchemaType
= stype
;
554 fixup
.TypeName
= typeQName
;
555 pendingMaps
.Enqueue (fixup
);
558 void BuildPendingMaps ()
560 while (pendingMaps
.Count
> 0) {
561 MapFixup fixup
= (MapFixup
) pendingMaps
.Dequeue ();
562 if (fixup
.Map
.ObjectMap
== null) {
563 BuildClassMap (fixup
.Map
, fixup
.TypeName
, fixup
.SchemaType
);
564 if (fixup
.Map
.ObjectMap
== null) pendingMaps
.Enqueue (fixup
);
569 void BuildPendingMap (XmlTypeMapping map
)
571 if (map
.ObjectMap
!= null) return;
573 foreach (MapFixup fixup
in pendingMaps
)
575 if (fixup
.Map
== map
) {
576 BuildClassMap (fixup
.Map
, fixup
.TypeName
, fixup
.SchemaType
);
580 throw new InvalidOperationException ("Can't complete map of type " + map
.XmlType
+ " : " + map
.Namespace
);
583 void BuildClassMap (XmlTypeMapping map
, XmlQualifiedName typeQName
, XmlSchemaComplexType stype
)
585 CodeIdentifiers classIds
= new CodeIdentifiers();
586 classIds
.AddReserved (map
.TypeData
.TypeName
);
588 ClassMap cmap
= new ClassMap ();
589 map
.ObjectMap
= cmap
;
590 bool isMixed
= stype
.IsMixed
;
592 if (stype
.Particle
!= null)
593 ImportParticleComplexContent (typeQName
, cmap
, stype
.Particle
, classIds
, isMixed
);
596 if (stype
.ContentModel
is XmlSchemaSimpleContent
) {
597 ImportSimpleContent (typeQName
, map
, (XmlSchemaSimpleContent
)stype
.ContentModel
, classIds
, isMixed
);
599 else if (stype
.ContentModel
is XmlSchemaComplexContent
) {
600 ImportComplexContent (typeQName
, map
, (XmlSchemaComplexContent
)stype
.ContentModel
, classIds
, isMixed
);
604 ImportAttributes (typeQName
, cmap
, stype
.Attributes
, stype
.AnyAttribute
, classIds
);
605 ImportExtensionTypes (typeQName
);
607 AddObjectDerivedMap (map
);
610 void ImportAttributes (XmlQualifiedName typeQName
, ClassMap cmap
, XmlSchemaObjectCollection atts
, XmlSchemaAnyAttribute anyat
, CodeIdentifiers classIds
)
614 XmlTypeMapMemberAnyAttribute member
= new XmlTypeMapMemberAnyAttribute ();
615 member
.Name
= classIds
.AddUnique ("AnyAttribute", member
);
616 member
.TypeData
= TypeTranslator
.GetTypeData (typeof(XmlAttribute
[]));
617 cmap
.AddMember (member
);
620 foreach (XmlSchemaObject at
in atts
)
622 if (at
is XmlSchemaAttribute
)
625 XmlSchemaAttribute attr
= (XmlSchemaAttribute
)at
;
626 XmlSchemaAttribute refAttr
= GetRefAttribute (typeQName
, attr
, out ns
);
627 XmlTypeMapMemberAttribute member
= new XmlTypeMapMemberAttribute ();
628 member
.Name
= classIds
.AddUnique (CodeIdentifier
.MakeValid (refAttr
.Name
), member
);
629 member
.Documentation
= GetDocumentation (attr
);
630 member
.AttributeName
= refAttr
.Name
;
631 member
.Namespace
= ns
;
632 member
.Form
= refAttr
.Form
;
633 member
.TypeData
= GetAttributeTypeData (typeQName
, attr
);
635 if (refAttr
.DefaultValue
!= null)
636 member
.DefaultValue
= XmlCustomFormatter
.FromXmlString (member
.TypeData
, refAttr
.DefaultValue
);
637 else if (member
.TypeData
.IsValueType
)
638 member
.IsOptionalValueType
= (refAttr
.ValidatedUse
!= XmlSchemaUse
.Required
);
640 if (member
.TypeData
.IsComplexType
)
641 member
.MappedType
= GetTypeMapping (member
.TypeData
);
642 cmap
.AddMember (member
);
644 else if (at
is XmlSchemaAttributeGroupRef
)
646 XmlSchemaAttributeGroupRef gref
= (XmlSchemaAttributeGroupRef
)at
;
647 XmlSchemaAttributeGroup grp
= FindRefAttributeGroup (gref
.RefName
);
648 ImportAttributes (typeQName
, cmap
, grp
.Attributes
, grp
.AnyAttribute
, classIds
);
653 ListMap
BuildArrayMap (XmlQualifiedName typeQName
, XmlSchemaComplexType stype
, out TypeData arrayTypeData
)
657 XmlSchemaComplexContent content
= stype
.ContentModel
as XmlSchemaComplexContent
;
658 XmlSchemaComplexContentRestriction rest
= content
.Content
as XmlSchemaComplexContentRestriction
;
659 XmlSchemaAttribute arrayTypeAt
= FindArrayAttribute (rest
.Attributes
);
661 if (arrayTypeAt
!= null)
663 XmlAttribute
[] uatts
= arrayTypeAt
.UnhandledAttributes
;
664 if (uatts
== null || uatts
.Length
== 0) throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName
);
666 XmlAttribute xat
= null;
667 foreach (XmlAttribute at
in uatts
)
668 if (at
.LocalName
== "arrayType" && at
.NamespaceURI
== XmlSerializer
.WsdlNamespace
)
672 throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName
);
674 string name
, ns
, dims
;
675 TypeTranslator
.ParseArrayType (xat
.Value
, out name
, out ns
, out dims
);
676 return BuildEncodedArrayMap (name
+ dims
, ns
, out arrayTypeData
);
680 XmlSchemaElement elem
= null;
681 XmlSchemaSequence seq
= rest
.Particle
as XmlSchemaSequence
;
682 if (seq
!= null && seq
.Items
.Count
== 1)
683 elem
= seq
.Items
[0] as XmlSchemaElement
;
685 XmlSchemaAll all
= rest
.Particle
as XmlSchemaAll
;
686 if (all
!= null && all
.Items
.Count
== 1)
687 elem
= all
.Items
[0] as XmlSchemaElement
;
690 throw new InvalidOperationException ("Unknown array format");
692 return BuildEncodedArrayMap (elem
.SchemaTypeName
.Name
+ "[]", elem
.SchemaTypeName
.Namespace
, out arrayTypeData
);
697 ClassMap cmap
= new ClassMap ();
698 CodeIdentifiers classIds
= new CodeIdentifiers();
699 ImportParticleComplexContent (typeQName
, cmap
, stype
.Particle
, classIds
, stype
.IsMixed
);
701 XmlTypeMapMemberFlatList list
= (cmap
.AllMembers
.Count
== 1) ? cmap
.AllMembers
[0] as XmlTypeMapMemberFlatList
: null;
702 if (list
!= null && list
.ChoiceMember
== null)
704 arrayTypeData
= list
.TypeData
;
709 arrayTypeData
= null;
715 ListMap
BuildEncodedArrayMap (string type
, string ns
, out TypeData arrayTypeData
)
717 ListMap map
= new ListMap ();
719 int i
= type
.LastIndexOf ("[");
720 if (i
== -1) throw new InvalidOperationException ("Invalid arrayType value: " + type
);
721 if (type
.IndexOf (",",i
) != -1) throw new InvalidOperationException ("Multidimensional arrays are not supported");
723 string itemType
= type
.Substring (0,i
);
725 TypeData itemTypeData
;
726 if (itemType
.IndexOf ("[") != -1)
728 ListMap innerListMap
= BuildEncodedArrayMap (itemType
, ns
, out itemTypeData
);
730 int dims
= itemType
.Split ('[').Length
- 1;
731 string name
= TypeTranslator
.GetArrayName (type
, dims
);
732 XmlQualifiedName qname
= new XmlQualifiedName (name
, ns
);
733 XmlTypeMapping tmap
= CreateArrayTypeMapping (qname
, itemTypeData
);
734 tmap
.ObjectMap
= innerListMap
;
738 itemTypeData
= GetTypeData (new XmlQualifiedName (itemType
, ns
), null);
741 arrayTypeData
= itemTypeData
.ListTypeData
;
743 map
.ItemInfo
= new XmlTypeMapElementInfoList();
744 map
.ItemInfo
.Add (CreateElementInfo ("", null, "Item", itemTypeData
, true, XmlSchemaForm
.None
));
748 XmlSchemaAttribute
FindArrayAttribute (XmlSchemaObjectCollection atts
)
750 foreach (object ob
in atts
)
752 XmlSchemaAttribute att
= ob
as XmlSchemaAttribute
;
753 if (att
!= null && att
.RefName
== arrayTypeRefName
) return att
;
755 XmlSchemaAttributeGroupRef gref
= ob
as XmlSchemaAttributeGroupRef
;
758 XmlSchemaAttributeGroup grp
= FindRefAttributeGroup (gref
.RefName
);
759 att
= FindArrayAttribute (grp
.Attributes
);
760 if (att
!= null) return att
;
766 void ImportParticleComplexContent (XmlQualifiedName typeQName
, ClassMap cmap
, XmlSchemaParticle particle
, CodeIdentifiers classIds
, bool isMixed
)
768 ImportParticleContent (typeQName
, cmap
, particle
, classIds
, false, ref isMixed
);
769 if (isMixed
&& cmap
.XmlTextCollector
== null)
771 XmlTypeMapMemberFlatList member
= new XmlTypeMapMemberFlatList ();
772 member
.Name
= classIds
.AddUnique ("Text", member
);
773 member
.TypeData
= TypeTranslator
.GetTypeData (typeof(string[]));
774 member
.ElementInfo
.Add (CreateTextElementInfo (typeQName
.Namespace
, member
, member
.TypeData
.ListItemTypeData
));
775 member
.IsXmlTextCollector
= true;
776 member
.ListMap
= new ListMap ();
777 member
.ListMap
.ItemInfo
= member
.ElementInfo
;
778 cmap
.AddMember (member
);
782 void ImportParticleContent (XmlQualifiedName typeQName
, ClassMap cmap
, XmlSchemaParticle particle
, CodeIdentifiers classIds
, bool multiValue
, ref bool isMixed
)
784 if (particle
== null) return;
786 if (particle
is XmlSchemaGroupRef
)
787 particle
= GetRefGroupParticle ((XmlSchemaGroupRef
)particle
);
789 if (particle
.MaxOccurs
> 1) multiValue
= true;
791 if (particle
is XmlSchemaSequence
) {
792 ImportSequenceContent (typeQName
, cmap
, ((XmlSchemaSequence
)particle
).Items
, classIds
, multiValue
, ref isMixed
);
794 else if (particle
is XmlSchemaChoice
) {
795 if (((XmlSchemaChoice
)particle
).Items
.Count
== 1)
796 ImportSequenceContent (typeQName
, cmap
, ((XmlSchemaChoice
)particle
).Items
, classIds
, multiValue
, ref isMixed
);
798 ImportChoiceContent (typeQName
, cmap
, (XmlSchemaChoice
)particle
, classIds
, multiValue
);
800 else if (particle
is XmlSchemaAll
) {
801 ImportSequenceContent (typeQName
, cmap
, ((XmlSchemaAll
)particle
).Items
, classIds
, multiValue
, ref isMixed
);
805 void ImportSequenceContent (XmlQualifiedName typeQName
, ClassMap cmap
, XmlSchemaObjectCollection items
, CodeIdentifiers classIds
, bool multiValue
, ref bool isMixed
)
807 foreach (XmlSchemaObject item
in items
)
809 if (item
is XmlSchemaElement
)
812 XmlSchemaElement elem
= (XmlSchemaElement
) item
;
814 TypeData typeData
= GetElementTypeData (typeQName
, elem
, null, out emap
);
815 XmlSchemaElement refElem
= GetRefElement (typeQName
, elem
, out ns
);
817 if (elem
.MaxOccurs
== 1 && !multiValue
)
819 XmlTypeMapMemberElement member
= null;
820 if (typeData
.SchemaType
!= SchemaTypes
.Array
)
822 member
= new XmlTypeMapMemberElement ();
823 if (refElem
.DefaultValue
!= null) member
.DefaultValue
= XmlCustomFormatter
.FromXmlString (typeData
, refElem
.DefaultValue
);
825 else if (GetTypeMapping (typeData
).IsSimpleType
)
827 // It is a simple list (space separated list).
828 // Since this is not supported, map as a single item value
829 // TODO: improve this
830 member
= new XmlTypeMapMemberElement ();
831 typeData
= typeData
.ListItemTypeData
;
834 member
= new XmlTypeMapMemberList ();
836 if (elem
.MinOccurs
== 0 && typeData
.IsValueType
)
837 member
.IsOptionalValueType
= true;
839 member
.Name
= classIds
.AddUnique(CodeIdentifier
.MakeValid(refElem
.Name
), member
);
840 member
.Documentation
= GetDocumentation (elem
);
841 member
.TypeData
= typeData
;
842 member
.ElementInfo
.Add (CreateElementInfo (ns
, member
, refElem
.Name
, typeData
, refElem
.IsNillable
, refElem
.Form
, emap
));
843 cmap
.AddMember (member
);
847 XmlTypeMapMemberFlatList member
= new XmlTypeMapMemberFlatList ();
848 member
.ListMap
= new ListMap ();
849 member
.Name
= classIds
.AddUnique(CodeIdentifier
.MakeValid(refElem
.Name
), member
);
850 member
.Documentation
= GetDocumentation (elem
);
851 member
.TypeData
= typeData
.ListTypeData
;
852 member
.ElementInfo
.Add (CreateElementInfo (ns
, member
, refElem
.Name
, typeData
, refElem
.IsNillable
, refElem
.Form
, emap
));
853 member
.ListMap
.ItemInfo
= member
.ElementInfo
;
854 cmap
.AddMember (member
);
857 else if (item
is XmlSchemaAny
)
859 XmlSchemaAny elem
= (XmlSchemaAny
) item
;
860 XmlTypeMapMemberAnyElement member
= new XmlTypeMapMemberAnyElement ();
861 member
.Name
= classIds
.AddUnique ("Any", member
);
862 member
.Documentation
= GetDocumentation (elem
);
865 if (elem
.MaxOccurs
!= 1 || multiValue
)
866 ctype
= isMixed
? typeof(XmlNode
[]) : typeof(XmlElement
[]);
868 ctype
= isMixed
? typeof(XmlNode
) : typeof(XmlElement
);
870 member
.TypeData
= TypeTranslator
.GetTypeData (ctype
);
871 XmlTypeMapElementInfo einfo
= new XmlTypeMapElementInfo (member
, member
.TypeData
);
872 einfo
.IsUnnamedAnyElement
= true;
873 member
.ElementInfo
.Add (einfo
);
877 einfo
= CreateTextElementInfo (typeQName
.Namespace
, member
, member
.TypeData
);
878 member
.ElementInfo
.Add (einfo
);
879 member
.IsXmlTextCollector
= true;
880 isMixed
= false; //Allow only one XmlTextAttribute
883 cmap
.AddMember (member
);
885 else if (item
is XmlSchemaParticle
) {
886 ImportParticleContent (typeQName
, cmap
, (XmlSchemaParticle
)item
, classIds
, multiValue
, ref isMixed
);
891 void ImportChoiceContent (XmlQualifiedName typeQName
, ClassMap cmap
, XmlSchemaChoice choice
, CodeIdentifiers classIds
, bool multiValue
)
893 XmlTypeMapElementInfoList choices
= new XmlTypeMapElementInfoList ();
894 multiValue
= ImportChoices (typeQName
, null, choices
, choice
.Items
) || multiValue
;
895 if (choices
.Count
== 0) return;
897 if (choice
.MaxOccurs
> 1) multiValue
= true;
899 XmlTypeMapMemberElement member
;
902 member
= new XmlTypeMapMemberFlatList ();
903 member
.Name
= classIds
.AddUnique ("Items", member
);
904 ListMap listMap
= new ListMap ();
905 listMap
.ItemInfo
= choices
;
906 ((XmlTypeMapMemberFlatList
)member
).ListMap
= listMap
;
910 member
= new XmlTypeMapMemberElement ();
911 member
.Name
= classIds
.AddUnique ("Item", member
);
914 // If all choices have the same type, use that type for the member.
915 // If not use System.Object.
916 // If there are at least two choices with the same type, use a choice
917 // identifier attribute
919 TypeData typeData
= null;
920 bool twoEqual
= false;
921 bool allEqual
= true;
922 Hashtable types
= new Hashtable ();
924 foreach (XmlTypeMapElementInfo einfo
in choices
)
926 if (types
.ContainsKey (einfo
.TypeData
)) twoEqual
= true;
927 else types
.Add (einfo
.TypeData
, einfo
);
929 TypeData choiceType
= einfo
.TypeData
;
930 if (choiceType
.SchemaType
== SchemaTypes
.Class
)
932 // When comparing class types, use the most generic class in the
933 // inheritance hierarchy
935 XmlTypeMapping choiceMap
= GetTypeMapping (choiceType
);
936 BuildPendingMap (choiceMap
);
937 while (choiceMap
.BaseMap
!= null) {
938 choiceMap
= choiceMap
.BaseMap
;
939 BuildPendingMap (choiceMap
);
940 choiceType
= choiceMap
.TypeData
;
944 if (typeData
== null) typeData
= choiceType
;
945 else if (typeData
!= choiceType
) allEqual
= false;
949 typeData
= TypeTranslator
.GetTypeData (typeof(object));
953 // Create the choice member
954 XmlTypeMapMemberElement choiceMember
= new XmlTypeMapMemberElement ();
955 choiceMember
.Ignore
= true;
956 choiceMember
.Name
= classIds
.AddUnique (member
.Name
+ "ElementName", choiceMember
);
957 member
.ChoiceMember
= choiceMember
.Name
;
959 // Create the choice enum
960 XmlTypeMapping enumMap
= CreateTypeMapping (new XmlQualifiedName (member
.Name
+ "ChoiceType", typeQName
.Namespace
), SchemaTypes
.Enum
, null);
961 enumMap
.IncludeInSchema
= false;
963 CodeIdentifiers codeIdents
= new CodeIdentifiers ();
964 EnumMap
.EnumMapMember
[] members
= new EnumMap
.EnumMapMember
[choices
.Count
];
965 for (int n
=0; n
<choices
.Count
; n
++)
967 XmlTypeMapElementInfo it
=(XmlTypeMapElementInfo
) choices
[n
];
968 bool extraNs
= (it
.Namespace
!= null && it
.Namespace
!= "" && it
.Namespace
!= typeQName
.Namespace
);
969 string xmlName
= extraNs
? it
.Namespace
+ ":" + it
.ElementName
: it
.ElementName
;
970 string enumName
= codeIdents
.AddUnique (CodeIdentifier
.MakeValid (it
.ElementName
), it
);
971 members
[n
] = new EnumMap
.EnumMapMember (xmlName
, enumName
);
973 enumMap
.ObjectMap
= new EnumMap (members
, false);
975 choiceMember
.TypeData
= multiValue
? enumMap
.TypeData
.ListTypeData
: enumMap
.TypeData
;
976 choiceMember
.ElementInfo
.Add (CreateElementInfo (typeQName
.Namespace
, choiceMember
, choiceMember
.Name
, choiceMember
.TypeData
, false, XmlSchemaForm
.None
));
977 cmap
.AddMember (choiceMember
);
981 typeData
= typeData
.ListTypeData
;
983 member
.ElementInfo
= choices
;
984 member
.Documentation
= GetDocumentation (choice
);
985 member
.TypeData
= typeData
;
986 cmap
.AddMember (member
);
989 bool ImportChoices (XmlQualifiedName typeQName
, XmlTypeMapMember member
, XmlTypeMapElementInfoList choices
, XmlSchemaObjectCollection items
)
991 bool multiValue
= false;
992 foreach (XmlSchemaObject titem
in items
)
994 XmlSchemaObject item
= titem
;
995 if (item
is XmlSchemaGroupRef
)
996 item
= GetRefGroupParticle ((XmlSchemaGroupRef
)item
);
998 if (item
is XmlSchemaElement
)
1001 XmlSchemaElement elem
= (XmlSchemaElement
) item
;
1002 XmlTypeMapping emap
;
1003 TypeData typeData
= GetElementTypeData (typeQName
, elem
, null, out emap
);
1004 XmlSchemaElement refElem
= GetRefElement (typeQName
, elem
, out ns
);
1005 choices
.Add (CreateElementInfo (ns
, member
, refElem
.Name
, typeData
, refElem
.IsNillable
, refElem
.Form
, emap
));
1006 if (elem
.MaxOccurs
> 1) multiValue
= true;
1008 else if (item
is XmlSchemaAny
)
1010 XmlTypeMapElementInfo einfo
= new XmlTypeMapElementInfo (member
, TypeTranslator
.GetTypeData(typeof(XmlElement
)));
1011 einfo
.IsUnnamedAnyElement
= true;
1012 choices
.Add (einfo
);
1014 else if (item
is XmlSchemaChoice
) {
1015 multiValue
= ImportChoices (typeQName
, member
, choices
, ((XmlSchemaChoice
)item
).Items
) || multiValue
;
1017 else if (item
is XmlSchemaSequence
) {
1018 multiValue
= ImportChoices (typeQName
, member
, choices
, ((XmlSchemaSequence
)item
).Items
) || multiValue
;
1024 void ImportSimpleContent (XmlQualifiedName typeQName
, XmlTypeMapping map
, XmlSchemaSimpleContent content
, CodeIdentifiers classIds
, bool isMixed
)
1026 XmlSchemaSimpleContentExtension ext
= content
.Content
as XmlSchemaSimpleContentExtension
;
1027 ClassMap cmap
= (ClassMap
)map
.ObjectMap
;
1028 XmlQualifiedName qname
= GetContentBaseType (content
.Content
);
1030 if (qname
.Namespace
!= XmlSchema
.Namespace
)
1032 // Add base map members to this map
1034 XmlTypeMapping baseMap
= ImportType (qname
, null);
1035 BuildPendingMap (baseMap
);
1036 ClassMap baseClassMap
= (ClassMap
)baseMap
.ObjectMap
;
1038 foreach (XmlTypeMapMember member
in baseClassMap
.AllMembers
)
1039 cmap
.AddMember (member
);
1041 map
.BaseMap
= baseMap
;
1042 baseMap
.DerivedTypes
.Add (map
);
1046 XmlTypeMapMemberElement member
= new XmlTypeMapMemberElement ();
1047 member
.Name
= classIds
.AddUnique("Value", member
);
1048 member
.TypeData
= FindBuiltInType (qname
);
1049 member
.ElementInfo
.Add (CreateTextElementInfo (typeQName
.Namespace
, member
, member
.TypeData
));
1050 member
.IsXmlTextCollector
= true;
1051 cmap
.AddMember (member
);
1055 ImportAttributes (typeQName
, cmap
, ext
.Attributes
, ext
.AnyAttribute
, classIds
);
1058 TypeData
FindBuiltInType (XmlQualifiedName qname
)
1060 if (qname
.Namespace
== XmlSchema
.Namespace
)
1061 return TypeTranslator
.GetPrimitiveTypeData (qname
.Name
);
1063 XmlSchemaComplexType ct
= (XmlSchemaComplexType
) schemas
.Find (qname
, typeof(XmlSchemaComplexType
));
1066 XmlSchemaSimpleContent sc
= ct
.ContentModel
as XmlSchemaSimpleContent
;
1067 if (sc
== null) throw new InvalidOperationException ("Invalid schema");
1068 return FindBuiltInType (GetContentBaseType (sc
.Content
));
1071 XmlSchemaSimpleType st
= (XmlSchemaSimpleType
) schemas
.Find (qname
, typeof(XmlSchemaSimpleType
));
1073 return FindBuiltInType (qname
, st
);
1075 throw new InvalidOperationException ("Definition of type " + qname
+ " not found");
1078 TypeData
FindBuiltInType (XmlQualifiedName qname
, XmlSchemaSimpleType st
)
1081 return ImportType (qname
, null).TypeData
;
1083 if (st
.Content
is XmlSchemaSimpleTypeRestriction
) {
1084 return FindBuiltInType (GetContentBaseType (st
.Content
));
1086 else if (st
.Content
is XmlSchemaSimpleTypeList
) {
1087 return FindBuiltInType (GetContentBaseType (st
.Content
)).ListTypeData
;
1089 else if (st
.Content
is XmlSchemaSimpleTypeUnion
)
1091 // Check if all types of the union are equal. If not, then will use anyType.
1092 XmlSchemaSimpleTypeUnion uni
= (XmlSchemaSimpleTypeUnion
) st
.Content
;
1093 TypeData utype
= null;
1095 // Anonymous types are unique
1096 if (uni
.BaseTypes
.Count
!= 0 && uni
.MemberTypes
.Length
!= 0)
1097 return FindBuiltInType (anyType
);
1099 foreach (XmlQualifiedName mt
in uni
.MemberTypes
)
1101 TypeData qn
= FindBuiltInType (mt
);
1102 if (utype
!= null && qn
!= utype
) return FindBuiltInType (anyType
);
1111 XmlQualifiedName
GetContentBaseType (XmlSchemaObject ob
)
1113 if (ob
is XmlSchemaSimpleContentExtension
)
1114 return ((XmlSchemaSimpleContentExtension
)ob
).BaseTypeName
;
1115 else if (ob
is XmlSchemaSimpleContentRestriction
)
1116 return ((XmlSchemaSimpleContentRestriction
)ob
).BaseTypeName
;
1117 else if (ob
is XmlSchemaSimpleTypeRestriction
)
1118 return ((XmlSchemaSimpleTypeRestriction
)ob
).BaseTypeName
;
1119 else if (ob
is XmlSchemaSimpleTypeList
)
1120 return ((XmlSchemaSimpleTypeList
)ob
).ItemTypeName
;
1125 void ImportComplexContent (XmlQualifiedName typeQName
, XmlTypeMapping map
, XmlSchemaComplexContent content
, CodeIdentifiers classIds
, bool isMixed
)
1127 ClassMap cmap
= (ClassMap
)map
.ObjectMap
;
1128 XmlQualifiedName qname
;
1130 XmlSchemaComplexContentExtension ext
= content
.Content
as XmlSchemaComplexContentExtension
;
1131 if (ext
!= null) qname
= ext
.BaseTypeName
;
1132 else qname
= ((XmlSchemaComplexContentRestriction
)content
.Content
).BaseTypeName
;
1134 if (qname
== typeQName
)
1135 throw new InvalidOperationException ("Cannot import schema for type '" + typeQName
.Name
+ "' from namespace '" + typeQName
.Namespace
+ "'. Redefine not supported");
1137 // Add base map members to this map
1139 XmlTypeMapping baseMap
= ImportType (qname
, null);
1140 BuildPendingMap (baseMap
);
1141 ClassMap baseClassMap
= (ClassMap
)baseMap
.ObjectMap
;
1143 foreach (XmlTypeMapMember member
in baseClassMap
.AllMembers
)
1144 cmap
.AddMember (member
);
1146 if (baseClassMap
.XmlTextCollector
!= null) isMixed
= false;
1147 else if (content
.IsMixed
) isMixed
= true;
1149 map
.BaseMap
= baseMap
;
1150 baseMap
.DerivedTypes
.Add (map
);
1153 // Add the members of this map
1154 ImportParticleComplexContent (typeQName
, cmap
, ext
.Particle
, classIds
, isMixed
);
1155 ImportAttributes (typeQName
, cmap
, ext
.Attributes
, ext
.AnyAttribute
, classIds
);
1158 if (isMixed
) ImportParticleComplexContent (typeQName
, cmap
, null, classIds
, true);
1162 void ImportExtensionTypes (XmlQualifiedName qname
)
1164 foreach (XmlSchema schema
in schemas
) {
1165 foreach (XmlSchemaObject sob
in schema
.Items
)
1167 XmlSchemaComplexType sct
= sob
as XmlSchemaComplexType
;
1168 if (sct
!= null && sct
.ContentModel
is XmlSchemaComplexContent
) {
1169 XmlQualifiedName exqname
;
1170 XmlSchemaComplexContentExtension ext
= sct
.ContentModel
.Content
as XmlSchemaComplexContentExtension
;
1171 if (ext
!= null) exqname
= ext
.BaseTypeName
;
1172 else exqname
= ((XmlSchemaComplexContentRestriction
)sct
.ContentModel
.Content
).BaseTypeName
;
1173 if (exqname
== qname
)
1174 ImportType (new XmlQualifiedName (sct
.Name
, schema
.TargetNamespace
), sct
, null);
1180 XmlTypeMapping
ImportClassSimpleType (XmlQualifiedName typeQName
, XmlSchemaSimpleType stype
, XmlQualifiedName root
)
1182 if (CanBeEnum (stype
))
1184 // Create an enum map
1186 CodeIdentifiers codeIdents
= new CodeIdentifiers ();
1187 XmlTypeMapping enumMap
= CreateTypeMapping (typeQName
, SchemaTypes
.Enum
, null);
1188 enumMap
.Documentation
= GetDocumentation (stype
);
1190 bool isFlags
= false;
1191 if (stype
.Content
is XmlSchemaSimpleTypeList
) {
1192 stype
= ((XmlSchemaSimpleTypeList
)stype
.Content
).ItemType
;
1195 XmlSchemaSimpleTypeRestriction rest
= (XmlSchemaSimpleTypeRestriction
)stype
.Content
;
1197 codeIdents
.AddReserved (enumMap
.TypeData
.TypeName
);
1199 EnumMap
.EnumMapMember
[] members
= new EnumMap
.EnumMapMember
[rest
.Facets
.Count
];
1200 for (int n
=0; n
<rest
.Facets
.Count
; n
++)
1202 XmlSchemaEnumerationFacet enu
= (XmlSchemaEnumerationFacet
) rest
.Facets
[n
];
1203 string enumName
= codeIdents
.AddUnique(CodeIdentifier
.MakeValid (enu
.Value
), enu
);
1204 members
[n
] = new EnumMap
.EnumMapMember (enu
.Value
, enumName
);
1205 members
[n
].Documentation
= GetDocumentation (enu
);
1207 enumMap
.ObjectMap
= new EnumMap (members
, isFlags
);
1208 enumMap
.IsSimpleType
= true;
1212 if (stype
.Content
is XmlSchemaSimpleTypeList
)
1214 XmlSchemaSimpleTypeList slist
= (XmlSchemaSimpleTypeList
)stype
.Content
;
1215 TypeData arrayTypeData
= FindBuiltInType (slist
.ItemTypeName
, stype
);
1217 ListMap listMap
= new ListMap ();
1219 listMap
.ItemInfo
= new XmlTypeMapElementInfoList ();
1220 listMap
.ItemInfo
.Add (CreateElementInfo (typeQName
.Namespace
, null, "Item", arrayTypeData
.ListItemTypeData
, false, XmlSchemaForm
.None
));
1222 XmlTypeMapping map
= CreateArrayTypeMapping (typeQName
, arrayTypeData
);
1223 map
.ObjectMap
= listMap
;
1224 map
.IsSimpleType
= true;
1228 // It is an extension of a primitive or known type
1230 TypeData typeData
= FindBuiltInType (typeQName
, stype
);
1231 return GetTypeMapping (typeData
);
1234 bool CanBeEnum (XmlSchemaSimpleType stype
)
1236 if (stype
.Content
is XmlSchemaSimpleTypeRestriction
)
1238 XmlSchemaSimpleTypeRestriction rest
= (XmlSchemaSimpleTypeRestriction
)stype
.Content
;
1239 if (rest
.Facets
.Count
== 0) return false;
1240 foreach (object ob
in rest
.Facets
)
1241 if (!(ob
is XmlSchemaEnumerationFacet
)) return false;
1244 else if (stype
.Content
is XmlSchemaSimpleTypeList
)
1246 XmlSchemaSimpleTypeList list
= (XmlSchemaSimpleTypeList
) stype
.Content
;
1247 return (list
.ItemType
!= null && CanBeEnum (list
.ItemType
));
1252 bool CanBeArray (XmlQualifiedName typeQName
, XmlSchemaComplexType stype
)
1256 XmlSchemaComplexContent content
= stype
.ContentModel
as XmlSchemaComplexContent
;
1257 if (content
== null) return false;
1258 XmlSchemaComplexContentRestriction rest
= content
.Content
as XmlSchemaComplexContentRestriction
;
1259 if (rest
== null) return false;
1260 return rest
.BaseTypeName
== arrayType
;
1264 if (stype
.Attributes
.Count
> 0 || stype
.AnyAttribute
!= null) return false;
1265 else return !stype
.IsMixed
&& CanBeArray (typeQName
, stype
.Particle
, false);
1269 bool CanBeArray (XmlQualifiedName typeQName
, XmlSchemaParticle particle
, bool multiValue
)
1271 // To be an array, there can't be a direct child of type typeQName
1273 if (particle
== null) return false;
1275 multiValue
= multiValue
|| particle
.MaxOccurs
> 1;
1277 if (particle
is XmlSchemaGroupRef
)
1278 return CanBeArray (typeQName
, GetRefGroupParticle ((XmlSchemaGroupRef
)particle
), multiValue
);
1280 if (particle
is XmlSchemaElement
)
1282 XmlSchemaElement elem
= (XmlSchemaElement
)particle
;
1283 if (!elem
.RefName
.IsEmpty
)
1284 return CanBeArray (typeQName
, FindRefElement (elem
), multiValue
);
1286 return multiValue
&& !typeQName
.Equals (((XmlSchemaElement
)particle
).SchemaTypeName
);
1289 if (particle
is XmlSchemaAny
)
1292 if (particle
is XmlSchemaSequence
)
1294 XmlSchemaSequence seq
= particle
as XmlSchemaSequence
;
1295 if (seq
.Items
.Count
!= 1) return false;
1296 return CanBeArray (typeQName
, (XmlSchemaParticle
)seq
.Items
[0], multiValue
);
1299 if (particle
is XmlSchemaChoice
)
1301 // Can be array if all choices have different types
1302 ArrayList types
= new ArrayList ();
1303 if(!CheckChoiceType (typeQName
, particle
, types
, ref multiValue
)) return false;
1310 bool CheckChoiceType (XmlQualifiedName typeQName
, XmlSchemaParticle particle
, ArrayList types
, ref bool multiValue
)
1312 XmlQualifiedName type
= null;
1314 multiValue
= multiValue
|| particle
.MaxOccurs
> 1;
1316 if (particle
is XmlSchemaGroupRef
)
1317 return CheckChoiceType (typeQName
, GetRefGroupParticle ((XmlSchemaGroupRef
)particle
), types
, ref multiValue
);
1319 if (particle
is XmlSchemaElement
) {
1321 XmlSchemaElement elem
= (XmlSchemaElement
)particle
;
1322 XmlSchemaElement refElem
= GetRefElement (typeQName
, elem
, out ns
);
1323 if (refElem
.SchemaType
!= null) return true;
1324 type
= refElem
.SchemaTypeName
;
1326 else if (particle
is XmlSchemaAny
) {
1329 else if (particle
is XmlSchemaSequence
)
1331 XmlSchemaSequence seq
= particle
as XmlSchemaSequence
;
1332 foreach (XmlSchemaParticle par
in seq
.Items
)
1333 if (!CheckChoiceType (typeQName
, par
, types
, ref multiValue
)) return false;
1336 else if (particle
is XmlSchemaChoice
)
1338 foreach (XmlSchemaParticle choice
in ((XmlSchemaChoice
)particle
).Items
)
1339 if (!CheckChoiceType (typeQName
, choice
, types
, ref multiValue
)) return false;
1343 if (typeQName
.Equals (type
)) return false;
1345 // For primitive types, compare using CLR types, since several
1346 // xml types can be mapped to a single CLR type
1349 if (type
.Namespace
== XmlSchema
.Namespace
)
1350 t
= TypeTranslator
.GetPrimitiveTypeData (type
.Name
).FullTypeName
+ ":" + type
.Namespace
;
1353 t
= type
.Name
+ ":" + type
.Namespace
;
1355 if (types
.Contains (t
)) return false;
1360 bool CanBeAnyElement (XmlSchemaComplexType stype
)
1362 XmlSchemaSequence seq
= stype
.Particle
as XmlSchemaSequence
;
1363 return (seq
!= null) && (seq
.Items
.Count
== 1) && (seq
.Items
[0] is XmlSchemaAny
);
1366 Type
GetAnyElementType (XmlSchemaComplexType stype
)
1368 XmlSchemaSequence seq
= stype
.Particle
as XmlSchemaSequence
;
1370 if ((seq
== null) || (seq
.Items
.Count
!= 1) || !(seq
.Items
[0] is XmlSchemaAny
))
1374 return typeof(object);
1376 XmlSchemaAny any
= seq
.Items
[0] as XmlSchemaAny
;
1377 if (any
.MaxOccurs
== 1)
1380 return typeof(XmlNode
);
1382 return typeof(XmlElement
);
1387 return typeof(XmlNode
[]);
1389 return typeof(XmlElement
[]);
1393 bool CanBeIXmlSerializable (XmlSchemaComplexType stype
)
1395 XmlSchemaSequence seq
= stype
.Particle
as XmlSchemaSequence
;
1396 if (seq
== null) return false;
1397 if (seq
.Items
.Count
!= 2) return false;
1398 XmlSchemaElement elem
= seq
.Items
[0] as XmlSchemaElement
;
1399 if (elem
== null) return false;
1400 if (elem
.RefName
!= new XmlQualifiedName ("schema",XmlSchema
.Namespace
)) return false;
1401 return (seq
.Items
[1] is XmlSchemaAny
);
1404 XmlTypeMapping
ImportXmlSerializableMapping (string ns
)
1406 XmlQualifiedName qname
= new XmlQualifiedName ("System.Data.DataSet",ns
);
1407 XmlTypeMapping map
= mappedTypes
[qname
] as XmlTypeMapping
;
1408 if (map
!= null) return map
;
1410 TypeData typeData
= new TypeData ("System.Data.DataSet", "System.Data.DataSet", "System.Data.DataSet", SchemaTypes
.XmlSerializable
, null);
1411 map
= new XmlTypeMapping ("System.Data.DataSet", "", typeData
, "System.Data.DataSet", ns
);
1412 map
.IncludeInSchema
= true;
1413 mappedTypes
[qname
] = map
;
1414 dataMappedTypes
[typeData
] = map
;
1418 XmlTypeMapElementInfo
CreateElementInfo (string ns
, XmlTypeMapMember member
, string name
, TypeData typeData
, bool isNillable
, XmlSchemaForm form
)
1420 if (typeData
.IsComplexType
)
1421 return CreateElementInfo (ns
, member
, name
, typeData
, isNillable
, form
, GetTypeMapping (typeData
));
1423 return CreateElementInfo (ns
, member
, name
, typeData
, isNillable
, form
, null);
1426 XmlTypeMapElementInfo
CreateElementInfo (string ns
, XmlTypeMapMember member
, string name
, TypeData typeData
, bool isNillable
, XmlSchemaForm form
, XmlTypeMapping emap
)
1428 XmlTypeMapElementInfo einfo
= new XmlTypeMapElementInfo (member
, typeData
);
1429 einfo
.ElementName
= name
;
1430 einfo
.Namespace
= ns
;
1431 einfo
.IsNullable
= isNillable
;
1433 if (typeData
.IsComplexType
)
1434 einfo
.MappedType
= emap
;
1438 XmlTypeMapElementInfo
CreateTextElementInfo (string ns
, XmlTypeMapMember member
, TypeData typeData
)
1440 XmlTypeMapElementInfo einfo
= new XmlTypeMapElementInfo (member
, typeData
);
1441 einfo
.IsTextElement
= true;
1442 einfo
.WrappedElement
= false;
1443 if (typeData
.IsComplexType
)
1444 einfo
.MappedType
= GetTypeMapping (typeData
);
1448 XmlTypeMapping
CreateTypeMapping (XmlQualifiedName typeQName
, SchemaTypes schemaType
, XmlQualifiedName root
)
1450 string typeName
= CodeIdentifier
.MakeValid (typeQName
.Name
);
1451 typeName
= typeIdentifiers
.AddUnique (typeName
, null);
1453 TypeData typeData
= new TypeData (typeName
, typeName
, typeName
, schemaType
, null);
1458 rootElem
= root
.Name
;
1459 rootNs
= root
.Namespace
;
1462 rootElem
= typeQName
.Name
;
1466 XmlTypeMapping map
= new XmlTypeMapping (rootElem
, rootNs
, typeData
, typeQName
.Name
, typeQName
.Namespace
);
1467 map
.IncludeInSchema
= true;
1468 mappedTypes
[typeQName
] = map
;
1469 dataMappedTypes
[typeData
] = map
;
1474 XmlTypeMapping
CreateArrayTypeMapping (XmlQualifiedName typeQName
, TypeData arrayTypeData
)
1477 if (encodedFormat
) map
= new XmlTypeMapping ("Array", XmlSerializer
.EncodingNamespace
, arrayTypeData
, "Array", XmlSerializer
.EncodingNamespace
);
1478 else map
= new XmlTypeMapping (arrayTypeData
.XmlType
, typeQName
.Namespace
, arrayTypeData
, arrayTypeData
.XmlType
, typeQName
.Namespace
);
1480 map
.IncludeInSchema
= true;
1481 mappedTypes
[typeQName
] = map
;
1482 dataMappedTypes
[arrayTypeData
] = map
;
1487 XmlSchemaElement
GetRefElement (XmlQualifiedName typeQName
, XmlSchemaElement elem
, out string ns
)
1490 if (!elem
.RefName
.IsEmpty
)
1492 ns
= elem
.RefName
.Namespace
;
1493 return FindRefElement (elem
);
1497 ns
= typeQName
.Namespace
;
1502 XmlSchemaAttribute
GetRefAttribute (XmlQualifiedName typeQName
, XmlSchemaAttribute attr
, out string ns
)
1504 if (!attr
.RefName
.IsEmpty
)
1506 ns
= attr
.RefName
.Namespace
;
1507 XmlSchemaAttribute at
= FindRefAttribute (attr
.RefName
);
1508 if (at
== null) throw new InvalidOperationException ("The attribute " + attr
.RefName
+ " is missing");
1513 ns
= typeQName
.Namespace
;
1518 TypeData
GetElementTypeData (XmlQualifiedName typeQName
, XmlSchemaElement elem
, XmlQualifiedName root
, out XmlTypeMapping map
)
1520 bool sharedAnnType
= false;
1523 if (!elem
.RefName
.IsEmpty
) {
1524 XmlSchemaElement refElem
= FindRefElement (elem
);
1525 if (refElem
== null) throw new InvalidOperationException ("Global element not found: " + elem
.RefName
);
1526 root
= elem
.RefName
;
1528 sharedAnnType
= true;
1532 if (!elem
.SchemaTypeName
.IsEmpty
) {
1533 td
= GetTypeData (elem
.SchemaTypeName
, root
);
1534 map
= GetRegisteredTypeMapping (elem
.SchemaTypeName
);
1536 else if (elem
.SchemaType
== null)
1537 td
= TypeTranslator
.GetTypeData (typeof(object));
1539 td
= GetTypeData (elem
.SchemaType
, typeQName
, elem
.Name
, sharedAnnType
, root
);
1541 if (map
== null && td
.IsComplexType
)
1542 map
= GetTypeMapping (td
);
1547 TypeData
GetAttributeTypeData (XmlQualifiedName typeQName
, XmlSchemaAttribute attr
)
1549 bool sharedAnnType
= false;
1551 if (!attr
.RefName
.IsEmpty
) {
1552 XmlSchemaAttribute refAtt
= FindRefAttribute (attr
.RefName
);
1553 if (refAtt
== null) throw new InvalidOperationException ("Global attribute not found: " + attr
.RefName
);
1555 sharedAnnType
= true;
1558 if (!attr
.SchemaTypeName
.IsEmpty
) return GetTypeData (attr
.SchemaTypeName
, null);
1559 if (attr
.SchemaType
== null) return TypeTranslator
.GetTypeData (typeof(string));
1560 else return GetTypeData (attr
.SchemaType
, typeQName
, attr
.Name
, sharedAnnType
, null);
1563 TypeData
GetTypeData (XmlQualifiedName typeQName
, XmlQualifiedName root
)
1565 if (typeQName
.Namespace
== XmlSchema
.Namespace
|| (encodedFormat
&& typeQName
.Namespace
== ""))
1566 return TypeTranslator
.GetPrimitiveTypeData (typeQName
.Name
);
1568 return ImportType (typeQName
, root
).TypeData
;
1571 TypeData
GetTypeData (XmlSchemaType stype
, XmlQualifiedName typeQNname
, string propertyName
, bool sharedAnnType
, XmlQualifiedName root
)
1577 // Anonymous types defined in root elements or attributes can be shared among all elements that
1578 // reference this root element or attribute
1579 TypeData std
= sharedAnonymousTypes
[stype
] as TypeData
;
1580 if (std
!= null) return std
;
1581 baseName
= propertyName
;
1584 baseName
= typeQNname
.Name
+ typeIdentifiers
.MakeRightCase (propertyName
);
1586 baseName
= elemIdentifiers
.AddUnique (baseName
, stype
);
1588 XmlQualifiedName newName
;
1589 newName
= new XmlQualifiedName (baseName
, typeQNname
.Namespace
);
1591 XmlTypeMapping map
= ImportType (newName
, stype
, root
);
1592 if (sharedAnnType
) sharedAnonymousTypes
[stype
] = map
.TypeData
;
1594 return map
.TypeData
;
1597 XmlTypeMapping
GetTypeMapping (TypeData typeData
)
1599 if (typeData
.Type
== typeof(object) && !anyTypeImported
)
1600 ImportAllObjectTypes ();
1602 XmlTypeMapping map
= (XmlTypeMapping
) dataMappedTypes
[typeData
];
1603 if (map
!= null) return map
;
1605 if (typeData
.IsListType
)
1607 // Create an array map for the type
1609 XmlTypeMapping itemMap
= GetTypeMapping (typeData
.ListItemTypeData
);
1611 map
= new XmlTypeMapping (typeData
.XmlType
, itemMap
.Namespace
, typeData
, typeData
.XmlType
, itemMap
.Namespace
);
1612 map
.IncludeInSchema
= true;
1614 ListMap listMap
= new ListMap ();
1615 listMap
.ItemInfo
= new XmlTypeMapElementInfoList();
1616 listMap
.ItemInfo
.Add (CreateElementInfo (itemMap
.Namespace
, null, typeData
.ListItemTypeData
.XmlType
, typeData
.ListItemTypeData
, false, XmlSchemaForm
.None
));
1617 map
.ObjectMap
= listMap
;
1619 mappedTypes
[new XmlQualifiedName(map
.ElementName
, map
.Namespace
)] = map
;
1620 dataMappedTypes
[typeData
] = map
;
1623 else if (typeData
.SchemaType
== SchemaTypes
.Primitive
|| typeData
.Type
== typeof(object) || typeof(XmlNode
).IsAssignableFrom(typeData
.Type
))
1625 return CreateSystemMap (typeData
);
1628 throw new InvalidOperationException ("Map for type " + typeData
.TypeName
+ " not found");
1631 void AddObjectDerivedMap (XmlTypeMapping map
)
1633 TypeData typeData
= TypeTranslator
.GetTypeData (typeof(object));
1634 XmlTypeMapping omap
= (XmlTypeMapping
) dataMappedTypes
[typeData
];
1636 omap
= CreateSystemMap (typeData
);
1637 omap
.DerivedTypes
.Add (map
);
1640 XmlTypeMapping
CreateSystemMap (TypeData typeData
)
1642 XmlTypeMapping map
= new XmlTypeMapping (typeData
.XmlType
, XmlSchema
.Namespace
, typeData
, typeData
.XmlType
, XmlSchema
.Namespace
);
1643 map
.IncludeInSchema
= false;
1644 map
.ObjectMap
= new ClassMap ();
1645 dataMappedTypes
[typeData
] = map
;
1649 void ImportAllObjectTypes ()
1651 // All complex types are subtypes of anyType, so all of them
1652 // must also be imported
1654 anyTypeImported
= true;
1655 foreach (XmlSchema schema
in schemas
) {
1656 foreach (XmlSchemaObject sob
in schema
.Items
)
1658 XmlSchemaComplexType sct
= sob
as XmlSchemaComplexType
;
1660 ImportType (new XmlQualifiedName (sct
.Name
, schema
.TargetNamespace
), sct
, null);
1666 XmlTypeMapping
GetRegisteredTypeMapping (XmlQualifiedName typeQName
)
1668 return (XmlTypeMapping
) mappedTypes
[typeQName
];
1671 XmlSchemaParticle
GetRefGroupParticle (XmlSchemaGroupRef refGroup
)
1673 XmlSchemaGroup grp
= (XmlSchemaGroup
) schemas
.Find (refGroup
.RefName
, typeof (XmlSchemaGroup
));
1674 return grp
.Particle
;
1677 XmlSchemaElement
FindRefElement (XmlSchemaElement elem
)
1679 if (elem
.RefName
.Namespace
== XmlSchema
.Namespace
)
1681 if (anyElement
!= null) return anyElement
;
1682 anyElement
= new XmlSchemaElement ();
1683 anyElement
.Name
= "any";
1684 anyElement
.SchemaTypeName
= anyType
;
1687 return (XmlSchemaElement
) schemas
.Find (elem
.RefName
, typeof(XmlSchemaElement
));
1690 XmlSchemaAttribute
FindRefAttribute (XmlQualifiedName refName
)
1692 if (refName
.Namespace
== XmlNamespace
)
1694 XmlSchemaAttribute at
= new XmlSchemaAttribute ();
1695 at
.Name
= refName
.Name
;
1696 at
.SchemaTypeName
= new XmlQualifiedName ("string",XmlSchema
.Namespace
);
1699 return (XmlSchemaAttribute
) schemas
.Find (refName
, typeof(XmlSchemaAttribute
));
1702 XmlSchemaAttributeGroup
FindRefAttributeGroup (XmlQualifiedName refName
)
1704 XmlSchemaAttributeGroup grp
= (XmlSchemaAttributeGroup
) schemas
.Find (refName
, typeof(XmlSchemaAttributeGroup
));
1705 foreach (XmlSchemaObject at
in grp
.Attributes
)
1707 if (at
is XmlSchemaAttributeGroupRef
&& ((XmlSchemaAttributeGroupRef
)at
).RefName
== refName
)
1708 throw new InvalidOperationException ("Cannot import attribute group '" + refName
.Name
+ "' from namespace '" + refName
.Namespace
+ "'. Redefine not supported");
1714 XmlTypeMapping
ReflectType (Type type
, string ns
)
1715 {
if (!encodedFormat
)
1717 if (auxXmlRefImporter
== null) auxXmlRefImporter
= new XmlReflectionImporter ();
1718 return auxXmlRefImporter
.ImportTypeMapping (type
, ns
);
1722 if (auxSoapRefImporter
== null) auxSoapRefImporter
= new SoapReflectionImporter ();
1723 return auxSoapRefImporter
.ImportTypeMapping (type
, ns
);
1728 string GetDocumentation (XmlSchemaAnnotated elem
)
1731 XmlSchemaAnnotation anot
= elem
.Annotation
;
1732 if (anot
== null || anot
.Items
== null) return null;
1734 foreach (object ob
in anot
.Items
)
1736 XmlSchemaDocumentation doc
= ob
as XmlSchemaDocumentation
;
1737 if (doc
!= null && doc
.Markup
!= null && doc
.Markup
.Length
> 0) {
1738 if (res
!= string.Empty
) res
+= "\n";
1739 foreach (XmlNode node
in doc
.Markup
)
1746 #endregion // Methods