**** Merged from MCS ****
[mono-project.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSchemaImporter.cs
bloba451a90b6eb5e8014e593e6ae0ef2888801ba072
1 //
2 // System.Xml.Serialization.XmlSchemaImporter
3 //
4 // Author:
5 // Tim Coleman (tim@timcoleman.com)
6 // Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // Copyright (C) Tim Coleman, 2002
9 //
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:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
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.
32 using System.Xml;
33 using System.Xml.Schema;
34 using System.Collections;
36 namespace System.Xml.Serialization
38 public class XmlSchemaImporter
39 #if NET_2_0
40 : SchemaImporter
41 #endif
43 #region Fields
45 XmlSchemas schemas;
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;
56 bool anyTypeImported;
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;
66 class MapFixup
68 public XmlTypeMapping Map;
69 public XmlSchemaComplexType SchemaType;
70 public XmlQualifiedName TypeName;
73 #endregion
75 #region Constructors
77 public XmlSchemaImporter (XmlSchemas schemas)
79 this.schemas = schemas;
80 typeIdentifiers = new CodeIdentifiers ();
83 public XmlSchemaImporter (XmlSchemas schemas, CodeIdentifiers typeIdentifiers)
84 : this (schemas)
86 this.typeIdentifiers = typeIdentifiers;
89 #if NET_2_0
90 [MonoTODO]
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);
99 else
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);
111 else
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;
131 #endif
133 internal bool UseEncodedFormat
135 get { return encodedFormat; }
136 set { encodedFormat = value; }
139 #endregion // Constructors
141 #region Methods
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);
156 else
158 XmlSchemaComplexType stype = (XmlSchemaComplexType) schemas.Find (typeName, typeof (XmlSchemaComplexType));
159 if (stype == null)
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;
186 XmlSchemaType stype;
188 if (encodedFormat)
190 qname = name;
191 stype = schemas.Find (name, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;
192 if (stype == null) throw new InvalidOperationException ("Schema type '" + name + "' not found or not valid");
194 else
196 if (!LocateElement (name, out qname, out stype) || stype == null)
197 return null;
200 XmlTypeMapping map = GetRegisteredTypeMapping (qname);
201 if (map != null)
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);
208 return map;
211 map = CreateTypeMapping (qname, SchemaTypes.Class, name);
212 map.Documentation = GetDocumentation (stype);
213 RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype);
215 BuildPendingMaps ();
216 SetMapBaseType (map, baseType);
218 return map;
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;
229 while (map != null)
231 if (map.TypeData.Type == baseType)
232 return;
233 topMap = map;
234 map = map.BaseMap;
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;
274 else
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;
283 if (stype == null)
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);
299 XmlTypeMapping tmap;
300 TypeData td = GetElementTypeData (typeQName, elem, names[n], out tmap);
302 mapping[n] = ImportMemberMapping (elem.Name, typeQName.Namespace, elem.IsNillable, td, tmap);
304 BuildPendingMaps ();
305 return new XmlMembersMapping (mapping);
308 #if NET_2_0
309 [MonoTODO]
310 public XmlMembersMapping ImportMembersMapping (string name, string ns, SoapSchemaMember[] members)
312 throw new NotImplementedException ();
315 [MonoTODO]
316 public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName)
318 throw new NotImplementedException ();
321 [MonoTODO]
322 public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName, Type baseType)
324 throw new NotImplementedException ();
327 [MonoTODO]
328 public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName, Type baseType, bool baseTypeCanBeIndirect)
330 throw new NotImplementedException ();
332 #endif
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);
343 BuildPendingMaps ();
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);
370 BuildPendingMaps ();
372 int n = 0;
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);
377 return mapping;
380 XmlMemberMapping ImportMemberMapping (string name, string ns, bool isNullable, TypeData type, XmlTypeMapping emap)
382 XmlTypeMapMemberElement mapMem;
384 if (type.IsListType)
385 mapMem = new XmlTypeMapMemberList ();
386 else
387 mapMem = new XmlTypeMapMemberElement ();
389 mapMem.Name = name;
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);
395 [MonoTODO]
396 public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names, Type baseType, bool baseTypeCanBeIndirect)
398 throw new NotImplementedException ();
401 public XmlTypeMapping ImportTypeMapping (XmlQualifiedName name)
403 XmlQualifiedName qname;
404 XmlSchemaType stype;
405 if (!LocateElement (name, out qname, out stype)) return null;
407 if (stype == 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);
420 BuildPendingMaps ();
421 return map;
424 bool LocateElement (XmlQualifiedName name, out XmlQualifiedName qname, out XmlSchemaType stype)
426 qname = null;
427 stype = null;
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;
437 qname = name;
439 else
441 if (elem.SchemaTypeName.IsEmpty) return false;
443 if (elem.SchemaTypeName.Namespace == XmlSchema.Namespace) {
444 qname = elem.SchemaTypeName;
445 return true;
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;
460 return true;
463 XmlTypeMapping ImportType (XmlQualifiedName name, XmlQualifiedName root)
465 XmlTypeMapping map = GetRegisteredTypeMapping (name);
466 if (map != null) {
467 map.UpdateRoot (root);
468 return map;
471 XmlSchemaType type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaComplexType));
472 if (type == null) type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaSimpleType));
474 if (type == null)
476 if (name.Namespace == XmlSerializer.EncodingNamespace)
477 throw new InvalidOperationException ("Referenced type '" + name + "' valid only for encoded SOAP");
478 else
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);
488 if (map != null) {
489 XmlSchemaComplexType ct = stype as XmlSchemaComplexType;
490 if (map.TypeData.SchemaType != SchemaTypes.Class || ct == null || !CanBeArray (name, ct)) {
491 map.UpdateRoot (root);
492 return map;
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)
509 XmlTypeMapping map;
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);
519 if (anyType != null)
520 return GetTypeMapping (TypeTranslator.GetTypeData(anyType));
522 if (CanBeArray (typeQName, stype))
524 TypeData typeData;
525 ListMap listMap = BuildArrayMap (typeQName, stype, out typeData);
526 if (listMap != null)
528 map = CreateArrayTypeMapping (typeQName, typeData);
529 map.ObjectMap = listMap;
530 return map;
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);
546 return map;
549 void RegisterMapFixup (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype)
551 MapFixup fixup = new MapFixup ();
552 fixup.Map = map;
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);
577 return;
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);
594 else
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)
612 if (anyat != null)
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)
624 string ns;
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)
655 if (encodedFormat)
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)
669 { xat = at; break; }
671 if (xat == null)
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);
678 else
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;
684 else {
685 XmlSchemaAll all = rest.Particle as XmlSchemaAll;
686 if (all != null && all.Items.Count == 1)
687 elem = all.Items[0] as XmlSchemaElement;
689 if (elem == null)
690 throw new InvalidOperationException ("Unknown array format");
692 return BuildEncodedArrayMap (elem.SchemaTypeName.Name + "[]", elem.SchemaTypeName.Namespace, out arrayTypeData);
695 else
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;
705 return list.ListMap;
707 else
709 arrayTypeData = null;
710 return 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;
736 else
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));
745 return map;
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;
756 if (gref != null)
758 XmlSchemaAttributeGroup grp = FindRefAttributeGroup (gref.RefName);
759 att = FindArrayAttribute (grp.Attributes);
760 if (att != null) return att;
763 return null;
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);
797 else
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)
811 string ns;
812 XmlSchemaElement elem = (XmlSchemaElement) item;
813 XmlTypeMapping emap;
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;
833 else
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);
845 else
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);
864 Type ctype;
865 if (elem.MaxOccurs != 1 || multiValue)
866 ctype = isMixed ? typeof(XmlNode[]) : typeof(XmlElement[]);
867 else
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);
875 if (isMixed)
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;
900 if (multiValue)
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;
908 else
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;
948 if (!allEqual)
949 typeData = TypeTranslator.GetTypeData (typeof(object));
951 if (twoEqual)
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);
980 if (multiValue)
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)
1000 string ns;
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;
1021 return 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);
1044 else
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);
1054 if (ext != null)
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));
1064 if (ct != null)
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));
1072 if (st != null)
1073 return FindBuiltInType (qname, st);
1075 throw new InvalidOperationException ("Definition of type " + qname + " not found");
1078 TypeData FindBuiltInType (XmlQualifiedName qname, XmlSchemaSimpleType st)
1080 if (CanBeEnum (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);
1103 else utype = qn;
1105 return utype;
1107 else
1108 return null;
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;
1121 else
1122 return null;
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);
1152 if (ext != null) {
1153 // Add the members of this map
1154 ImportParticleComplexContent (typeQName, cmap, ext.Particle, classIds, isMixed);
1155 ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds);
1157 else {
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;
1193 isFlags = true;
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;
1209 return enumMap;
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;
1225 return map;
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;
1242 return true;
1244 else if (stype.Content is XmlSchemaSimpleTypeList)
1246 XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList) stype.Content;
1247 return (list.ItemType != null && CanBeEnum (list.ItemType));
1249 return false;
1252 bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaComplexType stype)
1254 if (encodedFormat)
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;
1262 else
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);
1285 else
1286 return multiValue && !typeQName.Equals (((XmlSchemaElement)particle).SchemaTypeName);
1289 if (particle is XmlSchemaAny)
1290 return multiValue;
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;
1304 return multiValue;
1307 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) {
1320 string ns;
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) {
1327 type = anyType;
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;
1334 return true;
1336 else if (particle is XmlSchemaChoice)
1338 foreach (XmlSchemaParticle choice in ((XmlSchemaChoice)particle).Items)
1339 if (!CheckChoiceType (typeQName, choice, types, ref multiValue)) return false;
1340 return true;
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
1348 string t;
1349 if (type.Namespace == XmlSchema.Namespace)
1350 t = TypeTranslator.GetPrimitiveTypeData (type.Name).FullTypeName + ":" + type.Namespace;
1352 else
1353 t = type.Name + ":" + type.Namespace;
1355 if (types.Contains (t)) return false;
1356 types.Add (t);
1357 return true;
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))
1371 return null;
1373 if (encodedFormat)
1374 return typeof(object);
1376 XmlSchemaAny any = seq.Items[0] as XmlSchemaAny;
1377 if (any.MaxOccurs == 1)
1379 if (stype.IsMixed)
1380 return typeof(XmlNode);
1381 else
1382 return typeof(XmlElement);
1384 else
1386 if (stype.IsMixed)
1387 return typeof(XmlNode[]);
1388 else
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;
1415 return 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));
1422 else
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;
1432 einfo.Form = form;
1433 if (typeData.IsComplexType)
1434 einfo.MappedType = emap;
1435 return einfo;
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);
1445 return einfo;
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);
1455 string rootElem;
1456 string rootNs;
1457 if (root != null) {
1458 rootElem = root.Name;
1459 rootNs = root.Namespace;
1461 else {
1462 rootElem = typeQName.Name;
1463 rootNs = "";
1466 XmlTypeMapping map = new XmlTypeMapping (rootElem, rootNs, typeData, typeQName.Name, typeQName.Namespace);
1467 map.IncludeInSchema = true;
1468 mappedTypes [typeQName] = map;
1469 dataMappedTypes [typeData] = map;
1471 return map;
1474 XmlTypeMapping CreateArrayTypeMapping (XmlQualifiedName typeQName, TypeData arrayTypeData)
1476 XmlTypeMapping map;
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;
1484 return 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);
1495 else
1497 ns = typeQName.Namespace;
1498 return elem;
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");
1509 return at;
1511 else
1513 ns = typeQName.Namespace;
1514 return attr;
1518 TypeData GetElementTypeData (XmlQualifiedName typeQName, XmlSchemaElement elem, XmlQualifiedName root, out XmlTypeMapping map)
1520 bool sharedAnnType = false;
1521 map = null;
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;
1527 elem = refElem;
1528 sharedAnnType = true;
1531 TypeData td;
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));
1538 else
1539 td = GetTypeData (elem.SchemaType, typeQName, elem.Name, sharedAnnType, root);
1541 if (map == null && td.IsComplexType)
1542 map = GetTypeMapping (td);
1544 return 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);
1554 attr = refAtt;
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)
1573 string baseName;
1575 if (sharedAnnType)
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;
1583 else
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;
1621 return 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];
1635 if (omap == null)
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;
1646 return 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;
1659 if (sct != null)
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;
1685 return anyElement;
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);
1697 return at;
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");
1711 return grp;
1714 XmlTypeMapping ReflectType (Type type, string ns)
1715 { if (!encodedFormat)
1717 if (auxXmlRefImporter == null) auxXmlRefImporter = new XmlReflectionImporter ();
1718 return auxXmlRefImporter.ImportTypeMapping (type, ns);
1720 else
1722 if (auxSoapRefImporter == null) auxSoapRefImporter = new SoapReflectionImporter ();
1723 return auxSoapRefImporter.ImportTypeMapping (type, ns);
1728 string GetDocumentation (XmlSchemaAnnotated elem)
1730 string res = "";
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)
1740 res += node.Value;
1743 return res;
1746 #endregion // Methods