Toolbar mouse clicks fixes
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSchemaImporter.cs
1 // \r
2 // System.Xml.Serialization.XmlSchemaImporter\r
3 //\r
4 // Author:\r
5 //   Tim Coleman (tim@timcoleman.com)\r
6 //   Lluis Sanchez Gual (lluis@ximian.com)\r
7 //\r
8 // Copyright (C) Tim Coleman, 2002\r
9 //\r
10 \r
11 //\r
12 // Permission is hereby granted, free of charge, to any person obtaining\r
13 // a copy of this software and associated documentation files (the\r
14 // "Software"), to deal in the Software without restriction, including\r
15 // without limitation the rights to use, copy, modify, merge, publish,\r
16 // distribute, sublicense, and/or sell copies of the Software, and to\r
17 // permit persons to whom the Software is furnished to do so, subject to\r
18 // the following conditions:\r
19 // \r
20 // The above copyright notice and this permission notice shall be\r
21 // included in all copies or substantial portions of the Software.\r
22 // \r
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
30 //\r
31 \r
32 using System.Xml;\r
33 #if !TARGET_JVM\r
34 using System.CodeDom.Compiler;\r
35 #endif\r
36 using System.Xml.Schema;\r
37 using System.Collections;\r
38 \r
39 namespace System.Xml.Serialization \r
40 {\r
41         public class XmlSchemaImporter\r
42 #if NET_2_0\r
43                 : SchemaImporter\r
44 #endif\r
45         {\r
46                 #region Fields\r
47 \r
48                 XmlSchemas schemas;\r
49                 CodeIdentifiers typeIdentifiers;\r
50                 CodeIdentifiers elemIdentifiers = new CodeIdentifiers ();\r
51                 Hashtable mappedTypes = new Hashtable ();\r
52                 Hashtable dataMappedTypes = new Hashtable ();\r
53                 Queue pendingMaps = new Queue ();\r
54                 Hashtable sharedAnonymousTypes = new Hashtable ();\r
55                 bool encodedFormat = false;\r
56                 XmlReflectionImporter auxXmlRefImporter;\r
57                 SoapReflectionImporter auxSoapRefImporter;\r
58                 bool anyTypeImported;\r
59 \r
60 #if NET_2_0\r
61                 CodeGenerationOptions options;\r
62 #endif\r
63 \r
64                 static readonly XmlQualifiedName anyType = new XmlQualifiedName ("anyType",XmlSchema.Namespace);\r
65                 static readonly XmlQualifiedName arrayType = new XmlQualifiedName ("Array",XmlSerializer.EncodingNamespace);\r
66                 static readonly XmlQualifiedName arrayTypeRefName = new XmlQualifiedName ("arrayType",XmlSerializer.EncodingNamespace);\r
67                 \r
68                 const string XmlNamespace = "http://www.w3.org/XML/1998/namespace";\r
69                 \r
70                 XmlSchemaElement anyElement = null;\r
71 \r
72                 class MapFixup\r
73                 {\r
74                         public XmlTypeMapping Map;\r
75                         public XmlSchemaComplexType SchemaType;\r
76                         public XmlQualifiedName TypeName;\r
77                 }\r
78 \r
79                 #endregion\r
80 \r
81                 #region Constructors\r
82 \r
83                 public XmlSchemaImporter (XmlSchemas schemas)\r
84                 {\r
85                         this.schemas = schemas;\r
86                         typeIdentifiers = new CodeIdentifiers ();\r
87                 }\r
88 \r
89                 public XmlSchemaImporter (XmlSchemas schemas, CodeIdentifiers typeIdentifiers)\r
90                         : this (schemas)\r
91                 {\r
92                         this.typeIdentifiers = typeIdentifiers;\r
93                 }\r
94                 \r
95 #if NET_2_0\r
96 #if !TARGET_JVM\r
97                 [MonoTODO]\r
98                 public XmlSchemaImporter (XmlSchemas schemas, CodeGenerationOptions options, CodeDomProvider codeProvider, ImportContext context)\r
99                 {\r
100                         this.schemas = schemas;\r
101                         this.options = options;\r
102                         if (context != null) {\r
103                                 typeIdentifiers = context.TypeIdentifiers;\r
104                                 InitSharedData (context);\r
105                         }\r
106                         else\r
107                                 typeIdentifiers = new CodeIdentifiers ();\r
108                 }\r
109 #endif\r
110 \r
111                 public XmlSchemaImporter (XmlSchemas schemas, CodeGenerationOptions options, ImportContext context)\r
112                 {\r
113                         this.schemas = schemas;\r
114                         this.options = options;\r
115                         if (context != null) {\r
116                                 typeIdentifiers = context.TypeIdentifiers;\r
117                                 InitSharedData (context);\r
118                         }\r
119                         else\r
120                                 typeIdentifiers = new CodeIdentifiers ();\r
121                 }\r
122                 \r
123 \r
124                 public XmlSchemaImporter (XmlSchemas schemas, CodeIdentifiers typeIdentifiers, CodeGenerationOptions options)\r
125                 {\r
126                         this.typeIdentifiers = typeIdentifiers;\r
127                         this.schemas = schemas;\r
128                         this.options = options;\r
129                 }\r
130 \r
131                 void InitSharedData (ImportContext context)\r
132                 {\r
133                         if (context.ShareTypes) {\r
134                                 mappedTypes = context.MappedTypes;\r
135                                 dataMappedTypes = context.DataMappedTypes;\r
136                                 sharedAnonymousTypes = context.SharedAnonymousTypes;\r
137                         }\r
138                 }\r
139 #endif\r
140                 \r
141                 internal bool UseEncodedFormat\r
142                 {\r
143                         get { return encodedFormat; }\r
144                         set { encodedFormat = value; }\r
145                 }\r
146 \r
147                 #endregion // Constructors\r
148 \r
149                 #region Methods\r
150 \r
151                 public XmlMembersMapping ImportAnyType (XmlQualifiedName typeName, string elementName)\r
152                 {\r
153                         if (typeName == XmlQualifiedName.Empty)\r
154                         {\r
155                                 XmlTypeMapMemberAnyElement mapMem = new XmlTypeMapMemberAnyElement ();\r
156                                 mapMem.Name = typeName.Name;\r
157                                 mapMem.TypeData = TypeTranslator.GetTypeData(typeof(XmlNode));\r
158                                 mapMem.ElementInfo.Add (CreateElementInfo (typeName.Namespace, mapMem, typeName.Name, mapMem.TypeData, true, XmlSchemaForm.None));\r
159                                 \r
160                                 XmlMemberMapping[] mm = new XmlMemberMapping [1];\r
161                                 mm[0] = new XmlMemberMapping (typeName.Name, typeName.Namespace, mapMem, encodedFormat);\r
162                                 return new XmlMembersMapping (mm);\r
163                         }\r
164                         else\r
165                         {\r
166                                 XmlSchemaComplexType stype = (XmlSchemaComplexType) schemas.Find (typeName, typeof (XmlSchemaComplexType));\r
167                                 if (stype == null) \r
168                                         throw new InvalidOperationException ("Referenced type '" + typeName + "' not found");\r
169                                 \r
170                                 if (!CanBeAnyElement (stype))\r
171                                         throw new InvalidOperationException ("The type '" + typeName + "' is not valid for a collection of any elements");\r
172                                         \r
173                                 ClassMap cmap = new ClassMap ();\r
174                                 CodeIdentifiers classIds = new CodeIdentifiers ();\r
175                                 bool isMixed = stype.IsMixed;\r
176                                 ImportSequenceContent (typeName, cmap, ((XmlSchemaSequence) stype.Particle).Items, classIds, false, ref isMixed);\r
177                                 XmlTypeMapMemberAnyElement mapMem = (XmlTypeMapMemberAnyElement) cmap.AllMembers[0];\r
178                                 mapMem.Name = typeName.Name;\r
179                                 \r
180                                 XmlMemberMapping[] mm = new XmlMemberMapping [1];\r
181                                 mm[0] = new XmlMemberMapping (typeName.Name, typeName.Namespace, mapMem, encodedFormat);\r
182                                 return new XmlMembersMapping (mm);\r
183                         }\r
184                 }\r
185 \r
186                 public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, Type baseType)\r
187                 {\r
188                         return ImportDerivedTypeMapping (name, baseType, true);\r
189                 }\r
190                 \r
191                 public XmlTypeMapping ImportDerivedTypeMapping (XmlQualifiedName name, Type baseType, bool baseTypeCanBeIndirect)\r
192                 {\r
193                         XmlQualifiedName qname;\r
194                         XmlSchemaType stype;\r
195                         \r
196                         if (encodedFormat)\r
197                         {\r
198                                 qname = name;\r
199                                 stype = schemas.Find (name, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;\r
200                                 if (stype == null) throw new InvalidOperationException ("Schema type '" + name + "' not found or not valid");\r
201                         }\r
202                         else\r
203                         {\r
204                                 if (!LocateElement (name, out qname, out stype))\r
205                                         return null;\r
206                         }\r
207 \r
208                         XmlTypeMapping map = GetRegisteredTypeMapping (qname);\r
209                         if (map != null)\r
210                         {\r
211                                 // If the type has already been imported, make sure that the map \r
212                                 // has the requested base type\r
213                                 \r
214                                 SetMapBaseType (map, baseType);\r
215                                 map.UpdateRoot (name);\r
216                                 return map;\r
217                         }\r
218                         \r
219                         map = CreateTypeMapping (qname, SchemaTypes.Class, name);\r
220                         if (stype != null) {\r
221                                 map.Documentation = GetDocumentation (stype);\r
222                                 RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype);\r
223                         } else {\r
224                                 ClassMap cmap = new ClassMap ();\r
225                                 CodeIdentifiers classIds = new CodeIdentifiers ();\r
226                                 map.ObjectMap = cmap;\r
227                                 AddTextMember (qname, cmap, classIds);\r
228                         }\r
229                         \r
230                         BuildPendingMaps ();\r
231                         SetMapBaseType (map, baseType);\r
232                         \r
233                         return map;\r
234                 }\r
235                 \r
236                 void SetMapBaseType (XmlTypeMapping map, Type baseType)\r
237                 {\r
238                         // This method sets the base type for a given map.\r
239                         // If the map already inherits from this type, it does nothing.\r
240                         \r
241                         // Fiirst of all, check if the map already inherits from baseType\r
242                                 \r
243                         XmlTypeMapping topMap = null;\r
244                         while (map != null)\r
245                         {\r
246                                 if (map.TypeData.Type == baseType)\r
247                                         return;\r
248                                 topMap = map;\r
249                                 map = map.BaseMap;\r
250                         }\r
251                         \r
252                         // Does not have the requested base type.\r
253                         // Then, get/create a map for that base type.\r
254 \r
255                         XmlTypeMapping baseMap = ReflectType (baseType);\r
256                         \r
257                         // Add this map as a derived map of the base map\r
258 \r
259                         topMap.BaseMap = baseMap;\r
260                         baseMap.DerivedTypes.Add (topMap);\r
261                         baseMap.DerivedTypes.AddRange (topMap.DerivedTypes);\r
262                         \r
263                         // Now add the base type fields to all derived maps\r
264 \r
265                         ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;\r
266                         \r
267                         ClassMap cmap = (ClassMap)topMap.ObjectMap;\r
268                         foreach (XmlTypeMapMember member in baseClassMap.AllMembers)\r
269                                 cmap.AddMember (member);\r
270                                 \r
271                         foreach (XmlTypeMapping derivedMap in topMap.DerivedTypes)\r
272                         {\r
273                                 cmap = (ClassMap)derivedMap.ObjectMap;\r
274                                 foreach (XmlTypeMapMember member in baseClassMap.AllMembers)\r
275                                         cmap.AddMember (member);\r
276                         }\r
277                 }\r
278 \r
279                 public XmlMembersMapping ImportMembersMapping (XmlQualifiedName name)\r
280                 {\r
281                         XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));\r
282                         if (elem == null) throw new InvalidOperationException ("Schema element '" + name + "' not found or not valid");\r
283 \r
284                         XmlSchemaComplexType stype;\r
285                         if (elem.SchemaType != null)\r
286                         {\r
287                                 stype = elem.SchemaType as XmlSchemaComplexType;\r
288                         }\r
289                         else\r
290                         {\r
291                                 if (elem.SchemaTypeName.IsEmpty) return null;\r
292                                 object type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaComplexType));\r
293                                 if (type == null) {\r
294                                         if (IsPrimitiveTypeNamespace (elem.SchemaTypeName.Namespace)) return null;\r
295                                         throw new InvalidOperationException ("Schema type '" + elem.SchemaTypeName + "' not found");\r
296                                 }\r
297                                 stype = type as XmlSchemaComplexType;\r
298                         }\r
299                         \r
300                         if (stype == null) \r
301                                 throw new InvalidOperationException ("Schema element '" + name + "' not found or not valid");\r
302                         \r
303                         XmlMemberMapping[] mapping = ImportMembersMappingComposite (stype, name);                       \r
304                         return new XmlMembersMapping (name.Name, name.Namespace, mapping);\r
305                 }\r
306                 \r
307                 public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names)\r
308                 {\r
309                         XmlMemberMapping[] mapping = new XmlMemberMapping [names.Length];\r
310                         for (int n=0; n<names.Length; n++)\r
311                         {\r
312                                 XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (names[n], typeof (XmlSchemaElement));\r
313                                 if (elem == null) throw new InvalidOperationException ("Schema element '" + names[n] + "' not found");\r
314                                 \r
315                                 XmlQualifiedName typeQName = new XmlQualifiedName ("Message", names[n].Namespace);\r
316                                 XmlTypeMapping tmap;\r
317                                 TypeData td = GetElementTypeData (typeQName, elem, names[n], out tmap);\r
318                                 \r
319                                 mapping[n] = ImportMemberMapping (elem.Name, typeQName.Namespace, elem.IsNillable, td, tmap);\r
320                         }\r
321                         BuildPendingMaps ();\r
322                         return new XmlMembersMapping (mapping);\r
323                 }\r
324                 \r
325 #if NET_2_0\r
326                 [MonoTODO]\r
327                 public XmlMembersMapping ImportMembersMapping (string name, string ns, SoapSchemaMember[] members)\r
328                 {\r
329                         throw new NotImplementedException ();\r
330                 }\r
331                 \r
332                 [MonoTODO]\r
333                 public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName)\r
334                 {\r
335                         throw new NotImplementedException ();\r
336                 }\r
337                 \r
338                 [MonoTODO]\r
339                 public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName, Type baseType)\r
340                 {\r
341                         throw new NotImplementedException ();\r
342                 }\r
343                 \r
344                 [MonoTODO]\r
345                 public XmlTypeMapping ImportSchemaType (XmlQualifiedName typeName, Type baseType, bool baseTypeCanBeIndirect)\r
346                 {\r
347                         throw new NotImplementedException ();\r
348                 }\r
349 #endif\r
350                 \r
351                 internal XmlMembersMapping ImportEncodedMembersMapping (string name, string ns, SoapSchemaMember[] members, bool hasWrapperElement)\r
352                 {\r
353                         XmlMemberMapping[] mapping = new XmlMemberMapping [members.Length];\r
354                         for (int n=0; n<members.Length; n++)\r
355                         {\r
356                                 TypeData td = GetTypeData (members[n].MemberType, null);\r
357                                 XmlTypeMapping tmap = GetTypeMapping (td);\r
358                                 mapping[n] = ImportMemberMapping (members[n].MemberName, members[n].MemberType.Namespace, true, td, tmap);\r
359                         }\r
360                         BuildPendingMaps ();\r
361                         return new XmlMembersMapping (name, ns, hasWrapperElement, false, mapping);\r
362                 }\r
363                 \r
364                 internal XmlMembersMapping ImportEncodedMembersMapping (string name, string ns, SoapSchemaMember member)\r
365                 {\r
366                         XmlSchemaComplexType stype = schemas.Find (member.MemberType, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;\r
367                         if (stype == null) throw new InvalidOperationException ("Schema type '" + member.MemberType + "' not found or not valid");\r
368 \r
369                         XmlMemberMapping[] mapping = ImportMembersMappingComposite (stype, member.MemberType);                  \r
370                         return new XmlMembersMapping (name, ns, mapping);\r
371                 }\r
372                 \r
373                 XmlMemberMapping[] ImportMembersMappingComposite (XmlSchemaComplexType stype, XmlQualifiedName refer)\r
374                 {\r
375                         if (stype.Particle == null) \r
376                                 return new XmlMemberMapping [0];\r
377 \r
378                         ClassMap cmap = new ClassMap ();\r
379                         \r
380                         XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;\r
381                         if (seq == null) throw new InvalidOperationException ("Schema element '" + refer + "' cannot be imported as XmlMembersMapping");\r
382 \r
383                         CodeIdentifiers classIds = new CodeIdentifiers ();\r
384                         ImportParticleComplexContent (refer, cmap, seq, classIds, false);\r
385                         ImportAttributes (refer, cmap, stype.Attributes, stype.AnyAttribute, classIds);\r
386 \r
387                         BuildPendingMaps ();\r
388 \r
389                         int n = 0;\r
390                         XmlMemberMapping[] mapping = new XmlMemberMapping [cmap.AllMembers.Count];\r
391                         foreach (XmlTypeMapMember mapMem in cmap.AllMembers)\r
392                                 mapping[n++] = new XmlMemberMapping (mapMem.Name, refer.Namespace, mapMem, encodedFormat);\r
393                                 \r
394                         return mapping;\r
395                 }\r
396                 \r
397                 XmlMemberMapping ImportMemberMapping (string name, string ns, bool isNullable, TypeData type, XmlTypeMapping emap)\r
398                 {\r
399                         XmlTypeMapMemberElement mapMem;\r
400                         \r
401                         if (type.IsListType)\r
402                                 mapMem = new XmlTypeMapMemberList ();\r
403                         else\r
404                                 mapMem = new XmlTypeMapMemberElement ();\r
405                         \r
406                         mapMem.Name = name;\r
407                         mapMem.TypeData = type;\r
408                         mapMem.ElementInfo.Add (CreateElementInfo (ns, mapMem, name, type, isNullable, XmlSchemaForm.None, emap));\r
409                         return new XmlMemberMapping (name, ns, mapMem, encodedFormat);\r
410                 }\r
411                 \r
412                 [MonoTODO]\r
413                 public XmlMembersMapping ImportMembersMapping (XmlQualifiedName[] names, Type baseType, bool baseTypeCanBeIndirect)\r
414                 {\r
415                         throw new NotImplementedException ();\r
416                 }\r
417 \r
418                 public XmlTypeMapping ImportTypeMapping (XmlQualifiedName name)\r
419                 {\r
420                         XmlQualifiedName qname;\r
421                         XmlSchemaType stype;\r
422 \r
423                         XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));\r
424                         if (!LocateElement (elem, out qname, out stype)) return null;\r
425                         \r
426                         if (stype == null) {\r
427                                 // Importing a primitive type\r
428                                 TypeData td = TypeTranslator.GetPrimitiveTypeData (qname.Name);\r
429                                 return ReflectType (td, name.Namespace);\r
430                         }\r
431                         \r
432                         XmlTypeMapping map = GetRegisteredTypeMapping (qname);\r
433                         if (map != null) return map;\r
434                         \r
435                         map = CreateTypeMapping (qname, SchemaTypes.Class, name);\r
436                         map.Documentation = GetDocumentation (stype);\r
437                         map.IsNullable = elem.IsNillable;\r
438                         RegisterMapFixup (map, qname, (XmlSchemaComplexType)stype);\r
439                         \r
440                         BuildPendingMaps ();\r
441                         return map;\r
442                 }\r
443 \r
444                 bool LocateElement (XmlQualifiedName name, out XmlQualifiedName qname, out XmlSchemaType stype)\r
445                 {\r
446                         XmlSchemaElement elem = (XmlSchemaElement) schemas.Find (name, typeof (XmlSchemaElement));\r
447                         return LocateElement (elem, out qname, out stype);\r
448                 }\r
449 \r
450                 bool LocateElement (XmlSchemaElement elem, out XmlQualifiedName qname, out XmlSchemaType stype)\r
451                 {\r
452                         qname = null;\r
453                         stype = null;\r
454                         \r
455                         if (elem == null) return false;\r
456 \r
457                         // The root element must be an element with complex type\r
458 \r
459                         if (elem.SchemaType != null)\r
460                         {\r
461                                 stype = elem.SchemaType;\r
462                                 qname = elem.QualifiedName;\r
463                         }\r
464                         else\r
465                         {\r
466                                 if (elem.SchemaTypeName.IsEmpty) return false;\r
467                                 \r
468                                 object type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaComplexType));\r
469                                 if (type == null) type = schemas.Find (elem.SchemaTypeName, typeof (XmlSchemaSimpleType));\r
470                                 if (type == null) {\r
471                                         if (IsPrimitiveTypeNamespace (elem.SchemaTypeName.Namespace)) {\r
472                                                 qname = elem.SchemaTypeName;\r
473                                                 return true;\r
474                                         }\r
475                                         throw new InvalidOperationException ("Schema type '" + elem.SchemaTypeName + "' not found");\r
476                                 }\r
477                                 stype = (XmlSchemaType) type;\r
478                                 qname = stype.QualifiedName;\r
479                                 \r
480                                 XmlSchemaType btype = stype.BaseSchemaType as XmlSchemaType;\r
481                                 if (btype != null && btype.QualifiedName == elem.SchemaTypeName)\r
482                                         throw new InvalidOperationException ("Cannot import schema for type '" + elem.SchemaTypeName.Name + "' from namespace '" + elem.SchemaTypeName.Namespace + "'. Redefine not supported");\r
483                         }\r
484 \r
485                         if (stype is XmlSchemaSimpleType) return false;\r
486                         return true;\r
487                 }\r
488 \r
489                 XmlTypeMapping ImportType (XmlQualifiedName name, XmlQualifiedName root, bool throwOnError)\r
490                 {\r
491                         XmlTypeMapping map = GetRegisteredTypeMapping (name);\r
492                         if (map != null) {\r
493                                 map.UpdateRoot (root);\r
494                                 return map;\r
495                         }\r
496 \r
497                         XmlSchemaType type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaComplexType));\r
498                         if (type == null) type = (XmlSchemaType) schemas.Find (name, typeof (XmlSchemaSimpleType));\r
499                         \r
500                         if (type == null) \r
501                         {\r
502                                 if (throwOnError) {\r
503                                         if (name.Namespace == XmlSerializer.EncodingNamespace)\r
504                                                 throw new InvalidOperationException ("Referenced type '" + name + "' valid only for encoded SOAP.");\r
505                                         else\r
506                                                 throw new InvalidOperationException ("Referenced type '" + name + "' not found.");\r
507                                 } else\r
508                                         return null;\r
509                         }\r
510 \r
511                         return ImportType (name, type, root);\r
512                 }\r
513 \r
514                 XmlTypeMapping ImportClass (XmlQualifiedName name)\r
515                 {\r
516                         XmlTypeMapping map = ImportType (name, null, true);\r
517                         if (map.TypeData.SchemaType == SchemaTypes.Class) return map;\r
518                         XmlSchemaComplexType stype = schemas.Find (name, typeof (XmlSchemaComplexType)) as XmlSchemaComplexType;\r
519                         return CreateClassMap (name, stype, new XmlQualifiedName (map.ElementName, map.Namespace));\r
520                 }\r
521                 \r
522                 XmlTypeMapping ImportType (XmlQualifiedName name, XmlSchemaType stype, XmlQualifiedName root)\r
523                 {\r
524                         XmlTypeMapping map = GetRegisteredTypeMapping (name);\r
525                         if (map != null) {\r
526                                 XmlSchemaComplexType ct = stype as XmlSchemaComplexType;\r
527                                 if (map.TypeData.SchemaType != SchemaTypes.Class || ct == null || !CanBeArray (name, ct)) {\r
528                                         map.UpdateRoot (root);\r
529                                         return map;\r
530                                 }\r
531                                         \r
532                                 // The map was initially imported as a class, but it turns out that it is an\r
533                                 // array. It has to be imported now as array.\r
534                         }\r
535                         \r
536                         if (stype is XmlSchemaComplexType)\r
537                                 return ImportClassComplexType (name, (XmlSchemaComplexType) stype, root);\r
538                         else if (stype is XmlSchemaSimpleType)\r
539                                 return ImportClassSimpleType (name, (XmlSchemaSimpleType) stype, root);\r
540 \r
541                         throw new NotSupportedException ("Schema type not supported: " + stype.GetType ());\r
542                 }\r
543 \r
544                 XmlTypeMapping ImportClassComplexType (XmlQualifiedName typeQName, XmlSchemaComplexType stype, XmlQualifiedName root)\r
545                 {\r
546                         // The need for fixups: If the complex type is an array, then to get the type of the\r
547                         // array we need first to get the type of the items of the array.\r
548                         // But if one of the item types or its children has a referece to this type array,\r
549                         // then we enter in an infinite loop. This does not happen with class types because\r
550                         // the class map is registered before parsing the children. We can't do the same\r
551                         // with the array type because to register the array map we need the type of the array.\r
552 \r
553                         Type anyType = GetAnyElementType (stype);\r
554                         if (anyType != null)\r
555                                 return GetTypeMapping (TypeTranslator.GetTypeData(anyType));\r
556                                 \r
557                         if (CanBeArray (typeQName, stype))\r
558                         {\r
559                                 TypeData typeData;\r
560                                 ListMap listMap = BuildArrayMap (typeQName, stype, out typeData);\r
561                                 if (listMap != null)\r
562                                 {\r
563                                         XmlTypeMapping map = CreateArrayTypeMapping (typeQName, typeData);\r
564                                         map.ObjectMap = listMap;\r
565                                         return map;\r
566                                 }\r
567 \r
568                                 // After all, it is not an array. Create a class map then.\r
569                         }\r
570                         else if (CanBeIXmlSerializable (stype))\r
571                         {\r
572                                 return ImportXmlSerializableMapping (typeQName.Namespace);\r
573                         }\r
574 \r
575                         // Register the map right now but do not build it,\r
576                         // This will avoid loops.\r
577 \r
578                         return CreateClassMap (typeQName, stype, root);\r
579                 }\r
580                 \r
581                 XmlTypeMapping CreateClassMap (XmlQualifiedName typeQName, XmlSchemaComplexType stype, XmlQualifiedName root)\r
582                 {\r
583                         XmlTypeMapping map = CreateTypeMapping (typeQName, SchemaTypes.Class, root);\r
584                         map.Documentation = GetDocumentation (stype);\r
585                         RegisterMapFixup (map, typeQName, stype);\r
586                         return map;\r
587                 }\r
588 \r
589                 void RegisterMapFixup (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype)\r
590                 {\r
591                         MapFixup fixup = new MapFixup ();\r
592                         fixup.Map = map;\r
593                         fixup.SchemaType = stype;\r
594                         fixup.TypeName = typeQName;\r
595                         pendingMaps.Enqueue (fixup);\r
596                 }\r
597 \r
598                 void BuildPendingMaps ()\r
599                 {\r
600                         while (pendingMaps.Count > 0) {\r
601                                 MapFixup fixup  = (MapFixup) pendingMaps.Dequeue ();\r
602                                 if (fixup.Map.ObjectMap == null) {\r
603                                         BuildClassMap (fixup.Map, fixup.TypeName, fixup.SchemaType);\r
604                                         if (fixup.Map.ObjectMap == null) pendingMaps.Enqueue (fixup);\r
605                                 }\r
606                         }\r
607                 }\r
608 \r
609                 void BuildPendingMap (XmlTypeMapping map)\r
610                 {\r
611                         if (map.ObjectMap != null) return;\r
612 \r
613                         foreach (MapFixup fixup in pendingMaps)\r
614                         {\r
615                                 if (fixup.Map == map) {\r
616                                         BuildClassMap (fixup.Map, fixup.TypeName, fixup.SchemaType);\r
617                                         return;\r
618                                 }\r
619                         }\r
620                         throw new InvalidOperationException ("Can't complete map of type " + map.XmlType + " : " + map.Namespace);\r
621                 }\r
622 \r
623                 void BuildClassMap (XmlTypeMapping map, XmlQualifiedName typeQName, XmlSchemaComplexType stype)\r
624                 {\r
625                         CodeIdentifiers classIds = new CodeIdentifiers();\r
626                         classIds.AddReserved (map.TypeData.TypeName);\r
627 \r
628                         ClassMap cmap = new ClassMap ();\r
629                         map.ObjectMap = cmap;\r
630                         bool isMixed = stype.IsMixed;\r
631 \r
632                         if (stype.Particle != null)\r
633                                 ImportParticleComplexContent (typeQName, cmap, stype.Particle, classIds, isMixed);\r
634                         else\r
635                         {\r
636                                 if (stype.ContentModel is XmlSchemaSimpleContent) {\r
637                                         ImportSimpleContent (typeQName, map, (XmlSchemaSimpleContent)stype.ContentModel, classIds, isMixed);\r
638                                 }\r
639                                 else if (stype.ContentModel is XmlSchemaComplexContent) {\r
640                                         ImportComplexContent (typeQName, map, (XmlSchemaComplexContent)stype.ContentModel, classIds, isMixed);\r
641                                 }\r
642                         }\r
643 \r
644                         ImportAttributes (typeQName, cmap, stype.Attributes, stype.AnyAttribute, classIds);\r
645                         ImportExtensionTypes (typeQName);\r
646 \r
647                         if (isMixed) AddTextMember (typeQName, cmap, classIds);\r
648                         \r
649                         AddObjectDerivedMap (map);\r
650                 }\r
651                 \r
652                 void ImportAttributes (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaObjectCollection atts, XmlSchemaAnyAttribute anyat, CodeIdentifiers classIds)\r
653                 {\r
654                         if (anyat != null)\r
655                         {\r
656                         XmlTypeMapMemberAnyAttribute member = new XmlTypeMapMemberAnyAttribute ();\r
657                                 member.Name = classIds.AddUnique ("AnyAttribute", member);\r
658                                 member.TypeData = TypeTranslator.GetTypeData (typeof(XmlAttribute[]));\r
659                                 cmap.AddMember (member);\r
660                         }\r
661                         \r
662                         foreach (XmlSchemaObject at in atts)\r
663                         {\r
664                                 if (at is XmlSchemaAttribute)\r
665                                 {\r
666                                         string ns;\r
667                                         XmlSchemaAttribute attr = (XmlSchemaAttribute)at;\r
668                                         XmlSchemaAttribute refAttr = GetRefAttribute (typeQName, attr, out ns);\r
669                                         XmlTypeMapMemberAttribute member = new XmlTypeMapMemberAttribute ();\r
670                                         member.Name = classIds.AddUnique (CodeIdentifier.MakeValid (refAttr.Name), member);\r
671                                         member.Documentation = GetDocumentation (attr);\r
672                                         member.AttributeName = refAttr.Name;\r
673                                         member.Namespace = ns;\r
674                                         member.Form = refAttr.Form;\r
675                                         member.TypeData = GetAttributeTypeData (typeQName, attr);\r
676                                         \r
677                                         if (refAttr.DefaultValue != null) \r
678                                                 member.DefaultValue = ImportDefaultValue (member.TypeData, refAttr.DefaultValue);\r
679                                         else if (member.TypeData.IsValueType)\r
680                                                 member.IsOptionalValueType = (refAttr.ValidatedUse != XmlSchemaUse.Required);\r
681                                                 \r
682                                         if (member.TypeData.IsComplexType)\r
683                                                 member.MappedType = GetTypeMapping (member.TypeData);\r
684                                         cmap.AddMember (member);\r
685                                 }\r
686                                 else if (at is XmlSchemaAttributeGroupRef)\r
687                                 {\r
688                                         XmlSchemaAttributeGroupRef gref = (XmlSchemaAttributeGroupRef)at;\r
689                                         XmlSchemaAttributeGroup grp = FindRefAttributeGroup (gref.RefName);\r
690                                         ImportAttributes (typeQName, cmap, grp.Attributes, grp.AnyAttribute, classIds);\r
691                                 }\r
692                         }\r
693                 }\r
694 \r
695                 ListMap BuildArrayMap (XmlQualifiedName typeQName, XmlSchemaComplexType stype, out TypeData arrayTypeData)\r
696                 {\r
697                         if (encodedFormat)\r
698                         {\r
699                                 XmlSchemaComplexContent content = stype.ContentModel as XmlSchemaComplexContent;\r
700                                 XmlSchemaComplexContentRestriction rest = content.Content as XmlSchemaComplexContentRestriction;\r
701                                 XmlSchemaAttribute arrayTypeAt = FindArrayAttribute (rest.Attributes);\r
702                                 \r
703                                 if (arrayTypeAt != null)\r
704                                 {\r
705                                         XmlAttribute[] uatts = arrayTypeAt.UnhandledAttributes;\r
706                                         if (uatts == null || uatts.Length == 0) throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName);\r
707                                         \r
708                                         XmlAttribute xat = null;\r
709                                         foreach (XmlAttribute at in uatts)\r
710                                                 if (at.LocalName == "arrayType" && at.NamespaceURI == XmlSerializer.WsdlNamespace)\r
711                                                         { xat = at; break; }\r
712                                         \r
713                                         if (xat == null) \r
714                                                 throw new InvalidOperationException ("arrayType attribute not specified in array declaration: " + typeQName);\r
715         \r
716                                         string name, ns, dims;\r
717                                         TypeTranslator.ParseArrayType (xat.Value, out name, out ns, out dims);\r
718                                         return BuildEncodedArrayMap (name + dims, ns, out arrayTypeData);\r
719                                 }\r
720                                 else\r
721                                 {\r
722                                         XmlSchemaElement elem = null;\r
723                                         XmlSchemaSequence seq = rest.Particle as XmlSchemaSequence;\r
724                                         if (seq != null && seq.Items.Count == 1) \r
725                                                 elem = seq.Items[0] as XmlSchemaElement;\r
726                                         else {\r
727                                                 XmlSchemaAll all = rest.Particle as XmlSchemaAll;\r
728                                                 if (all != null && all.Items.Count == 1)\r
729                                                         elem = all.Items[0] as XmlSchemaElement;\r
730                                         }\r
731                                         if (elem == null)\r
732                                                 throw new InvalidOperationException ("Unknown array format");\r
733                                                 \r
734                                         return BuildEncodedArrayMap (elem.SchemaTypeName.Name + "[]", elem.SchemaTypeName.Namespace, out arrayTypeData);\r
735                                 }\r
736                         }\r
737                         else\r
738                         {\r
739                                 ClassMap cmap = new ClassMap ();\r
740                                 CodeIdentifiers classIds = new CodeIdentifiers();\r
741                                 ImportParticleComplexContent (typeQName, cmap, stype.Particle, classIds, stype.IsMixed);\r
742 \r
743                                 XmlTypeMapMemberFlatList list = (cmap.AllMembers.Count == 1) ? cmap.AllMembers[0] as XmlTypeMapMemberFlatList : null;\r
744                                 if (list != null && list.ChoiceMember == null)\r
745                                 {\r
746                                         arrayTypeData = list.TypeData;\r
747                                         return list.ListMap;\r
748                                 }\r
749                                 else\r
750                                 {\r
751                                         arrayTypeData = null;\r
752                                         return null;\r
753                                 }\r
754                         }\r
755                 }\r
756                 \r
757                 ListMap BuildEncodedArrayMap (string type, string ns, out TypeData arrayTypeData)\r
758                 {\r
759                         ListMap map = new ListMap ();\r
760                         \r
761                         int i = type.LastIndexOf ("[");\r
762                         if (i == -1) throw new InvalidOperationException ("Invalid arrayType value: " + type);\r
763                         if (type.IndexOf (",",i) != -1) throw new InvalidOperationException ("Multidimensional arrays are not supported");\r
764                         \r
765                         string itemType = type.Substring (0,i);\r
766                         \r
767                         TypeData itemTypeData;\r
768                         if (itemType.IndexOf ("[") != -1) \r
769                         {\r
770                                 ListMap innerListMap = BuildEncodedArrayMap (itemType, ns, out itemTypeData);\r
771                                 \r
772                                 int dims = itemType.Split ('[').Length - 1;\r
773                                 string name = TypeTranslator.GetArrayName (type, dims);\r
774                                 XmlQualifiedName qname = new XmlQualifiedName (name, ns);\r
775                                 XmlTypeMapping tmap = CreateArrayTypeMapping (qname, itemTypeData);\r
776                                 tmap.ObjectMap = innerListMap;\r
777                         }\r
778                         else\r
779                         {\r
780                                 itemTypeData = GetTypeData (new XmlQualifiedName (itemType, ns), null);\r
781                         }\r
782                         \r
783                         arrayTypeData = itemTypeData.ListTypeData;\r
784                         \r
785                         map.ItemInfo = new XmlTypeMapElementInfoList();\r
786                         map.ItemInfo.Add (CreateElementInfo ("", null, "Item", itemTypeData, true, XmlSchemaForm.None));\r
787                         return map;\r
788                 }\r
789                 \r
790                 XmlSchemaAttribute FindArrayAttribute (XmlSchemaObjectCollection atts)\r
791                 {\r
792                         foreach (object ob in atts)\r
793                         {\r
794                                 XmlSchemaAttribute att = ob as XmlSchemaAttribute;\r
795                                 if (att != null && att.RefName == arrayTypeRefName) return att;\r
796                                 \r
797                                 XmlSchemaAttributeGroupRef gref = ob as XmlSchemaAttributeGroupRef;\r
798                                 if (gref != null)\r
799                                 {\r
800                                         XmlSchemaAttributeGroup grp = FindRefAttributeGroup (gref.RefName);\r
801                                         att = FindArrayAttribute (grp.Attributes);\r
802                                         if (att != null) return att;\r
803                                 }\r
804                         }\r
805                         return null;\r
806                 }\r
807 \r
808                 void ImportParticleComplexContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaParticle particle, CodeIdentifiers classIds, bool isMixed)\r
809                 {\r
810                         ImportParticleContent (typeQName, cmap, particle, classIds, false, ref isMixed);\r
811                         if (isMixed) AddTextMember (typeQName, cmap, classIds);\r
812                 }\r
813                 \r
814                 void AddTextMember (XmlQualifiedName typeQName, ClassMap cmap, CodeIdentifiers classIds)\r
815                 {\r
816                         if (cmap.XmlTextCollector == null)\r
817                         {\r
818                                 XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();\r
819                                 member.Name = classIds.AddUnique ("Text", member);\r
820                                 member.TypeData = TypeTranslator.GetTypeData (typeof(string[]));\r
821                                 member.ElementInfo.Add (CreateTextElementInfo (typeQName.Namespace, member, member.TypeData.ListItemTypeData));\r
822                                 member.IsXmlTextCollector = true;\r
823                                 member.ListMap = new ListMap ();\r
824                                 member.ListMap.ItemInfo = member.ElementInfo;\r
825                                 cmap.AddMember (member);\r
826                         }\r
827                 }\r
828                 \r
829                 void ImportParticleContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaParticle particle, CodeIdentifiers classIds, bool multiValue, ref bool isMixed)\r
830                 {\r
831                         if (particle == null) return;\r
832                         \r
833                         if (particle is XmlSchemaGroupRef)\r
834                                 particle = GetRefGroupParticle ((XmlSchemaGroupRef)particle);\r
835 \r
836                         if (particle.MaxOccurs > 1) multiValue = true;\r
837                         \r
838                         if (particle is XmlSchemaSequence) {\r
839                                 ImportSequenceContent (typeQName, cmap, ((XmlSchemaSequence)particle).Items, classIds, multiValue, ref isMixed);\r
840                         }\r
841                         else if (particle is XmlSchemaChoice) {\r
842                                 if (((XmlSchemaChoice)particle).Items.Count == 1)\r
843                                         ImportSequenceContent (typeQName, cmap, ((XmlSchemaChoice)particle).Items, classIds, multiValue, ref isMixed);\r
844                                 else\r
845                                         ImportChoiceContent (typeQName, cmap, (XmlSchemaChoice)particle, classIds, multiValue);\r
846                         }\r
847                         else if (particle is XmlSchemaAll) {\r
848                                 ImportSequenceContent (typeQName, cmap, ((XmlSchemaAll)particle).Items, classIds, multiValue, ref isMixed);\r
849                         }\r
850                 }\r
851 \r
852                 void ImportSequenceContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaObjectCollection items, CodeIdentifiers classIds, bool multiValue, ref bool isMixed)\r
853                 {\r
854                         foreach (XmlSchemaObject item in items)\r
855                         {\r
856                                 if (item is XmlSchemaElement)\r
857                                 {\r
858                                         string ns;\r
859                                         XmlSchemaElement elem = (XmlSchemaElement) item;\r
860                                         XmlTypeMapping emap;\r
861                                         TypeData typeData = GetElementTypeData (typeQName, elem, null, out emap);\r
862                                         XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);\r
863 \r
864                                         if (elem.MaxOccurs == 1 && !multiValue)\r
865                                         {\r
866                                                 XmlTypeMapMemberElement member = null;\r
867                                                 if (typeData.SchemaType != SchemaTypes.Array)\r
868                                                 {\r
869                                                         member = new XmlTypeMapMemberElement ();\r
870                                                         if (refElem.DefaultValue != null) member.DefaultValue = ImportDefaultValue (typeData, refElem.DefaultValue);\r
871                                                 }\r
872                                                 else if (GetTypeMapping (typeData).IsSimpleType)\r
873                                                 {\r
874                                                         // It is a simple list (space separated list).\r
875                                                         // Since this is not supported, map as a single item value\r
876                                                         member = new XmlTypeMapMemberElement ();\r
877 #if NET_2_0\r
878                                                         // In MS.NET those types are mapped to a string\r
879                                                         typeData = TypeTranslator.GetTypeData(typeof(string));\r
880 #else\r
881                                                         typeData = typeData.ListItemTypeData;\r
882 #endif\r
883                                                 }\r
884                                                 else\r
885                                                         member = new XmlTypeMapMemberList ();\r
886 \r
887                                                 if (elem.MinOccurs == 0 && typeData.IsValueType)\r
888                                                         member.IsOptionalValueType = true;\r
889 \r
890                                                 member.Name = classIds.AddUnique(CodeIdentifier.MakeValid(refElem.Name), member);\r
891                                                 member.Documentation = GetDocumentation (elem);\r
892                                                 member.TypeData = typeData;\r
893                                                 member.ElementInfo.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap));\r
894                                                 cmap.AddMember (member);\r
895                                         }\r
896                                         else\r
897                                         {\r
898                                                 XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();\r
899                                                 member.ListMap = new ListMap ();\r
900                                                 member.Name = classIds.AddUnique(CodeIdentifier.MakeValid(refElem.Name), member);\r
901                                                 member.Documentation = GetDocumentation (elem);\r
902                                                 member.TypeData = typeData.ListTypeData;\r
903                                                 member.ElementInfo.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap));\r
904                                                 member.ListMap.ItemInfo = member.ElementInfo;\r
905                                                 cmap.AddMember (member);\r
906                                         }\r
907                                 }\r
908                                 else if (item is XmlSchemaAny)\r
909                                 {\r
910                                         XmlSchemaAny elem = (XmlSchemaAny) item;\r
911                                         XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement ();\r
912                                         member.Name = classIds.AddUnique ("Any", member);\r
913                                         member.Documentation = GetDocumentation (elem);\r
914                                         \r
915                                         Type ctype;\r
916                                         if (elem.MaxOccurs != 1 || multiValue)\r
917                                                 ctype = isMixed ? typeof(XmlNode[]) : typeof(XmlElement[]);\r
918                                         else\r
919                                                 ctype = isMixed ? typeof(XmlNode) : typeof(XmlElement);\r
920 \r
921                                         member.TypeData = TypeTranslator.GetTypeData (ctype);\r
922                                         XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, member.TypeData);\r
923                                         einfo.IsUnnamedAnyElement = true;\r
924                                         member.ElementInfo.Add (einfo);\r
925 \r
926                                         if (isMixed)\r
927                                         {\r
928                                                 einfo = CreateTextElementInfo (typeQName.Namespace, member, member.TypeData);\r
929                                                 member.ElementInfo.Add (einfo);\r
930                                                 member.IsXmlTextCollector = true;\r
931                                                 isMixed = false;        //Allow only one XmlTextAttribute\r
932                                         }\r
933                                         \r
934                                         cmap.AddMember (member);\r
935                                 }\r
936                                 else if (item is XmlSchemaParticle) {\r
937                                         ImportParticleContent (typeQName, cmap, (XmlSchemaParticle)item, classIds, multiValue, ref isMixed);\r
938                                 }\r
939                         }\r
940                 }\r
941                 \r
942                 object ImportDefaultValue (TypeData typeData, string value)\r
943                 {\r
944                         if (typeData.SchemaType == SchemaTypes.Enum) {\r
945                                 XmlTypeMapping map = GetTypeMapping (typeData);\r
946                                 EnumMap emap = (EnumMap) map.ObjectMap;\r
947                                 string res = emap.GetEnumName (map.TypeFullName, value);\r
948                                 if (res == null) throw new InvalidOperationException ("'" + value + "' is not a valid enumeration value");\r
949                                 return res;\r
950                         } else\r
951                                 return XmlCustomFormatter.FromXmlString (typeData, value);\r
952                 }\r
953                 \r
954                 void ImportChoiceContent (XmlQualifiedName typeQName, ClassMap cmap, XmlSchemaChoice choice, CodeIdentifiers classIds, bool multiValue)\r
955                 {\r
956                         XmlTypeMapElementInfoList choices = new XmlTypeMapElementInfoList ();\r
957                         multiValue = ImportChoices (typeQName, null, choices, choice.Items) || multiValue;\r
958                         if (choices.Count == 0) return;\r
959 \r
960                         if (choice.MaxOccurs > 1) multiValue = true;\r
961 \r
962                         XmlTypeMapMemberElement member;\r
963                         if (multiValue)\r
964                         {\r
965                                 member = new XmlTypeMapMemberFlatList ();\r
966                                 member.Name = classIds.AddUnique ("Items", member);\r
967                                 ListMap listMap = new ListMap ();\r
968                                 listMap.ItemInfo = choices;\r
969                                 ((XmlTypeMapMemberFlatList)member).ListMap = listMap;\r
970                         }\r
971                         else\r
972                         {\r
973                                 member = new XmlTypeMapMemberElement ();\r
974                                 member.Name = classIds.AddUnique ("Item", member);\r
975                         }\r
976                         \r
977                         // If all choices have the same type, use that type for the member.\r
978                         // If not use System.Object.\r
979                         // If there are at least two choices with the same type, use a choice\r
980                         // identifier attribute\r
981 \r
982                         TypeData typeData = null;\r
983                         bool twoEqual = false;\r
984                         bool allEqual = true;\r
985                         Hashtable types = new Hashtable ();\r
986 \r
987                         for (int n = choices.Count - 1; n >= 0; n--)\r
988                         {\r
989                                 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) choices [n];\r
990                                 \r
991                                 // In some complex schemas, we may end up with several options\r
992                                 // with the same name. It is better to ignore the extra options\r
993                                 // than to crash. It's the best we can do, and btw it works\r
994                                 // better than in MS.NET.\r
995                                 \r
996                                 if (cmap.GetElement (einfo.ElementName, einfo.Namespace) != null ||\r
997                                         choices.IndexOfElement (einfo.ElementName, einfo.Namespace) != n)\r
998                                 {\r
999                                         choices.RemoveAt (n);\r
1000                                         continue;\r
1001                                 }\r
1002                                         \r
1003                                 if (types.ContainsKey (einfo.TypeData)) twoEqual = true;\r
1004                                 else types.Add (einfo.TypeData, einfo);\r
1005 \r
1006                                 TypeData choiceType = einfo.TypeData;\r
1007                                 if (choiceType.SchemaType == SchemaTypes.Class)\r
1008                                 {\r
1009                                         // When comparing class types, use the most generic class in the\r
1010                                         // inheritance hierarchy\r
1011 \r
1012                                         XmlTypeMapping choiceMap = GetTypeMapping (choiceType);\r
1013                                         BuildPendingMap (choiceMap);\r
1014                                         while (choiceMap.BaseMap != null) {\r
1015                                                 choiceMap = choiceMap.BaseMap;\r
1016                                                 BuildPendingMap (choiceMap);\r
1017                                                 choiceType = choiceMap.TypeData;\r
1018                                         }\r
1019                                 }\r
1020                                 \r
1021                                 if (typeData == null) typeData = choiceType;\r
1022                                 else if (typeData != choiceType) allEqual = false;\r
1023                         }\r
1024 \r
1025                         if (!allEqual)\r
1026                                 typeData = TypeTranslator.GetTypeData (typeof(object));\r
1027 \r
1028                         if (twoEqual)\r
1029                         {\r
1030                                 // Create the choice member\r
1031                                 XmlTypeMapMemberElement choiceMember = new XmlTypeMapMemberElement ();\r
1032                                 choiceMember.Ignore = true;\r
1033                                 choiceMember.Name = classIds.AddUnique (member.Name + "ElementName", choiceMember);\r
1034                                 member.ChoiceMember = choiceMember.Name;\r
1035 \r
1036                                 // Create the choice enum\r
1037                                 XmlTypeMapping enumMap = CreateTypeMapping (new XmlQualifiedName (member.Name + "ChoiceType", typeQName.Namespace), SchemaTypes.Enum, null);\r
1038                                 enumMap.IncludeInSchema = false;\r
1039 \r
1040                                 CodeIdentifiers codeIdents = new CodeIdentifiers ();\r
1041                                 EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember [choices.Count];\r
1042                                 for (int n=0; n<choices.Count; n++)\r
1043                                 {\r
1044                                         XmlTypeMapElementInfo it =(XmlTypeMapElementInfo) choices[n];\r
1045                                         bool extraNs = (it.Namespace != null && it.Namespace != "" && it.Namespace != typeQName.Namespace);\r
1046                                         string xmlName = extraNs ? it.Namespace + ":" + it.ElementName : it.ElementName;\r
1047                                         string enumName = codeIdents.AddUnique (CodeIdentifier.MakeValid (it.ElementName), it);\r
1048                                         members [n] = new EnumMap.EnumMapMember (xmlName, enumName);\r
1049                                 }\r
1050                                 enumMap.ObjectMap = new EnumMap (members, false);\r
1051 \r
1052                                 choiceMember.TypeData = multiValue ? enumMap.TypeData.ListTypeData : enumMap.TypeData;\r
1053                                 choiceMember.ElementInfo.Add (CreateElementInfo (typeQName.Namespace, choiceMember, choiceMember.Name, choiceMember.TypeData, false, XmlSchemaForm.None));\r
1054                                 cmap.AddMember (choiceMember);\r
1055                         }\r
1056                         \r
1057                         if (typeData == null)\r
1058                                 return;\r
1059         \r
1060                         if (multiValue)\r
1061                                 typeData = typeData.ListTypeData;\r
1062 \r
1063                         member.ElementInfo = choices;\r
1064                         member.Documentation = GetDocumentation (choice);\r
1065                         member.TypeData = typeData;\r
1066                         cmap.AddMember (member);\r
1067                 }\r
1068 \r
1069                 bool ImportChoices (XmlQualifiedName typeQName, XmlTypeMapMember member, XmlTypeMapElementInfoList choices, XmlSchemaObjectCollection items)\r
1070                 {\r
1071                         bool multiValue = false;\r
1072                         foreach (XmlSchemaObject titem in items)\r
1073                         {\r
1074                                 XmlSchemaObject item = titem;\r
1075                                 if (item is XmlSchemaGroupRef)\r
1076                                         item = GetRefGroupParticle ((XmlSchemaGroupRef)item);\r
1077 \r
1078                                 if (item is XmlSchemaElement)\r
1079                                 {\r
1080                                         string ns;\r
1081                                         XmlSchemaElement elem = (XmlSchemaElement) item;\r
1082                                         XmlTypeMapping emap;\r
1083                                         TypeData typeData = GetElementTypeData (typeQName, elem, null, out emap);\r
1084                                         XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);\r
1085                                         choices.Add (CreateElementInfo (ns, member, refElem.Name, typeData, refElem.IsNillable, refElem.Form, emap));\r
1086                                         if (elem.MaxOccurs > 1) multiValue = true;\r
1087                                 }\r
1088                                 else if (item is XmlSchemaAny)\r
1089                                 {\r
1090                                         XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));\r
1091                                         einfo.IsUnnamedAnyElement = true;\r
1092                                         choices.Add (einfo);\r
1093                                 }\r
1094                                 else if (item is XmlSchemaChoice) {\r
1095                                         multiValue = ImportChoices (typeQName, member, choices, ((XmlSchemaChoice)item).Items) || multiValue;\r
1096                                 }\r
1097                                 else if (item is XmlSchemaSequence) {\r
1098                                         multiValue = ImportChoices (typeQName, member, choices, ((XmlSchemaSequence)item).Items) || multiValue;\r
1099                                 }\r
1100                         }\r
1101                         return multiValue;\r
1102                 }\r
1103 \r
1104                 void ImportSimpleContent (XmlQualifiedName typeQName, XmlTypeMapping map, XmlSchemaSimpleContent content, CodeIdentifiers classIds, bool isMixed)\r
1105                 {\r
1106                         XmlSchemaSimpleContentExtension ext = content.Content as XmlSchemaSimpleContentExtension;\r
1107                         ClassMap cmap = (ClassMap)map.ObjectMap;\r
1108                         XmlQualifiedName qname = GetContentBaseType (content.Content);\r
1109                         TypeData simpleType = null;\r
1110                         \r
1111                         if (!IsPrimitiveTypeNamespace (qname.Namespace))\r
1112                         {\r
1113                                 // Add base map members to this map\r
1114         \r
1115                                 XmlTypeMapping baseMap = ImportType (qname, null, true);\r
1116                                 BuildPendingMap (baseMap);\r
1117                                 \r
1118                                 if (baseMap.IsSimpleType) {\r
1119                                         simpleType = baseMap.TypeData;\r
1120                                 } else {\r
1121                                         ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;\r
1122                 \r
1123                                         foreach (XmlTypeMapMember member in baseClassMap.AllMembers)\r
1124                                                 cmap.AddMember (member);\r
1125                 \r
1126                                         map.BaseMap = baseMap;\r
1127                                         baseMap.DerivedTypes.Add (map);\r
1128                                 }\r
1129                         }\r
1130                         else\r
1131                                 simpleType = FindBuiltInType (qname);\r
1132                                 \r
1133                         if (simpleType != null) {\r
1134                                 XmlTypeMapMemberElement member = new XmlTypeMapMemberElement ();\r
1135                                 member.Name = classIds.AddUnique("Value", member);\r
1136                                 member.TypeData = simpleType;\r
1137                                 member.ElementInfo.Add (CreateTextElementInfo (typeQName.Namespace, member, member.TypeData));\r
1138                                 member.IsXmlTextCollector = true;\r
1139                                 cmap.AddMember (member);\r
1140                         }\r
1141                         \r
1142                         if (ext != null)\r
1143                                 ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds);\r
1144                 }\r
1145 \r
1146                 TypeData FindBuiltInType (XmlQualifiedName qname)\r
1147                 {\r
1148                         XmlSchemaComplexType ct = (XmlSchemaComplexType) schemas.Find (qname, typeof(XmlSchemaComplexType));\r
1149                         if (ct != null)\r
1150                         {\r
1151                                 XmlSchemaSimpleContent sc = ct.ContentModel as XmlSchemaSimpleContent;\r
1152                                 if (sc == null) throw new InvalidOperationException ("Invalid schema");\r
1153                                 return FindBuiltInType (GetContentBaseType (sc.Content));\r
1154                         }\r
1155                         \r
1156                         XmlSchemaSimpleType st = (XmlSchemaSimpleType) schemas.Find (qname, typeof(XmlSchemaSimpleType));\r
1157                         if (st != null)\r
1158                                 return FindBuiltInType (qname, st);\r
1159 \r
1160                         if (IsPrimitiveTypeNamespace (qname.Namespace))\r
1161                                 return TypeTranslator.GetPrimitiveTypeData (qname.Name);\r
1162 \r
1163                         throw new InvalidOperationException ("Definition of type '" + qname + "' not found");\r
1164                 }\r
1165 \r
1166                 TypeData FindBuiltInType (XmlQualifiedName qname, XmlSchemaSimpleType st)\r
1167                 {\r
1168                         if (CanBeEnum (st) && qname != null)\r
1169                                 return ImportType (qname, null, true).TypeData;\r
1170 \r
1171                         if (st.Content is XmlSchemaSimpleTypeRestriction) {\r
1172                                 XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction) st.Content;\r
1173                                 XmlQualifiedName bn = GetContentBaseType (rest);\r
1174                                 if (bn == XmlQualifiedName.Empty && rest.BaseType != null)\r
1175                                         return FindBuiltInType (qname, rest.BaseType);\r
1176                                 else\r
1177                                         return FindBuiltInType (bn);\r
1178                         }\r
1179                         else if (st.Content is XmlSchemaSimpleTypeList) {\r
1180                                 return FindBuiltInType (GetContentBaseType (st.Content)).ListTypeData;\r
1181                         }\r
1182                         else if (st.Content is XmlSchemaSimpleTypeUnion) {\r
1183                                 // MS.NET always import simple unions as string\r
1184                                 return FindBuiltInType (new XmlQualifiedName ("string", XmlSchema.Namespace));\r
1185                         }\r
1186                         else\r
1187                                 return null;\r
1188                 }\r
1189 \r
1190                 XmlQualifiedName GetContentBaseType (XmlSchemaObject ob)\r
1191                 {\r
1192                         if (ob is XmlSchemaSimpleContentExtension)\r
1193                                 return ((XmlSchemaSimpleContentExtension)ob).BaseTypeName;\r
1194                         else if (ob is XmlSchemaSimpleContentRestriction)\r
1195                                 return ((XmlSchemaSimpleContentRestriction)ob).BaseTypeName;\r
1196                         else if (ob is XmlSchemaSimpleTypeRestriction)\r
1197                                 return ((XmlSchemaSimpleTypeRestriction)ob).BaseTypeName;\r
1198                         else if (ob is XmlSchemaSimpleTypeList)\r
1199                                 return ((XmlSchemaSimpleTypeList)ob).ItemTypeName;\r
1200                         else\r
1201                                 return null;\r
1202                 }\r
1203 \r
1204                 void ImportComplexContent (XmlQualifiedName typeQName, XmlTypeMapping map, XmlSchemaComplexContent content, CodeIdentifiers classIds, bool isMixed)\r
1205                 {\r
1206                         ClassMap cmap = (ClassMap)map.ObjectMap;\r
1207                         XmlQualifiedName qname;\r
1208 \r
1209                         XmlSchemaComplexContentExtension ext = content.Content as XmlSchemaComplexContentExtension;\r
1210                         if (ext != null) qname = ext.BaseTypeName;\r
1211                         else qname = ((XmlSchemaComplexContentRestriction)content.Content).BaseTypeName;\r
1212                         \r
1213                         if (qname == typeQName)\r
1214                                 throw new InvalidOperationException ("Cannot import schema for type '" + typeQName.Name + "' from namespace '" + typeQName.Namespace + "'. Redefine not supported");\r
1215                         \r
1216                         // Add base map members to this map\r
1217 \r
1218                         XmlTypeMapping baseMap = ImportClass (qname);\r
1219                         BuildPendingMap (baseMap);\r
1220                         ClassMap baseClassMap = (ClassMap)baseMap.ObjectMap;\r
1221 \r
1222                         foreach (XmlTypeMapMember member in baseClassMap.AllMembers)\r
1223                                 cmap.AddMember (member);\r
1224 \r
1225                         if (baseClassMap.XmlTextCollector != null) isMixed = false;\r
1226                         else if (content.IsMixed) isMixed = true;\r
1227 \r
1228                         map.BaseMap = baseMap;\r
1229                         baseMap.DerivedTypes.Add (map);\r
1230 \r
1231                         if (ext != null) {\r
1232                                 // Add the members of this map\r
1233                                 ImportParticleComplexContent (typeQName, cmap, ext.Particle, classIds, isMixed);\r
1234                                 ImportAttributes (typeQName, cmap, ext.Attributes, ext.AnyAttribute, classIds);\r
1235                         }\r
1236                         else {\r
1237                                 if (isMixed) ImportParticleComplexContent (typeQName, cmap, null, classIds, true);\r
1238                         }\r
1239                 }\r
1240                 \r
1241                 void ImportExtensionTypes (XmlQualifiedName qname)\r
1242                 {\r
1243                         foreach (XmlSchema schema in schemas) {\r
1244                                 foreach (XmlSchemaObject sob in schema.Items) \r
1245                                 {\r
1246                                         XmlSchemaComplexType sct = sob as XmlSchemaComplexType;\r
1247                                         if (sct != null && sct.ContentModel is XmlSchemaComplexContent) {\r
1248                                                 XmlQualifiedName exqname;\r
1249                                                 XmlSchemaComplexContentExtension ext = sct.ContentModel.Content as XmlSchemaComplexContentExtension;\r
1250                                                 if (ext != null) exqname = ext.BaseTypeName;\r
1251                                                 else exqname = ((XmlSchemaComplexContentRestriction)sct.ContentModel.Content).BaseTypeName;\r
1252                                                 if (exqname == qname)\r
1253                                                         ImportType (new XmlQualifiedName (sct.Name, schema.TargetNamespace), sct, null);\r
1254                                         }\r
1255                                 }\r
1256                         }                                       \r
1257                 }\r
1258 \r
1259                 XmlTypeMapping ImportClassSimpleType (XmlQualifiedName typeQName, XmlSchemaSimpleType stype, XmlQualifiedName root)\r
1260                 {\r
1261                         if (CanBeEnum (stype))\r
1262                         {\r
1263                                 // Create an enum map\r
1264 \r
1265                                 CodeIdentifiers codeIdents = new CodeIdentifiers ();\r
1266                                 XmlTypeMapping enumMap = CreateTypeMapping (typeQName, SchemaTypes.Enum, null);\r
1267                                 enumMap.Documentation = GetDocumentation (stype);\r
1268                                 \r
1269                                 bool isFlags = false;\r
1270                                 if (stype.Content is XmlSchemaSimpleTypeList) {\r
1271                                         stype = ((XmlSchemaSimpleTypeList)stype.Content).ItemType;\r
1272                                         isFlags = true;\r
1273                                 }\r
1274                                 XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction)stype.Content;\r
1275 \r
1276                                 codeIdents.AddReserved (enumMap.TypeData.TypeName);\r
1277 \r
1278                                 EnumMap.EnumMapMember[] members = new EnumMap.EnumMapMember [rest.Facets.Count];\r
1279                                 for (int n=0; n<rest.Facets.Count; n++)\r
1280                                 {\r
1281                                         XmlSchemaEnumerationFacet enu = (XmlSchemaEnumerationFacet) rest.Facets[n];\r
1282                                         string enumName = codeIdents.AddUnique(CodeIdentifier.MakeValid (enu.Value), enu);\r
1283                                         members [n] = new EnumMap.EnumMapMember (enu.Value, enumName);\r
1284                                         members [n].Documentation = GetDocumentation (enu);\r
1285                                 }\r
1286                                 enumMap.ObjectMap = new EnumMap (members, isFlags);\r
1287                                 enumMap.IsSimpleType = true;\r
1288                                 return enumMap;\r
1289                         }\r
1290 \r
1291                         if (stype.Content is XmlSchemaSimpleTypeList)\r
1292                         {\r
1293                                 XmlSchemaSimpleTypeList slist = (XmlSchemaSimpleTypeList)stype.Content;\r
1294                                 TypeData arrayTypeData = FindBuiltInType (slist.ItemTypeName, stype);\r
1295 \r
1296                                 ListMap listMap = new ListMap ();\r
1297 \r
1298                                 listMap.ItemInfo = new XmlTypeMapElementInfoList ();\r
1299                                 listMap.ItemInfo.Add (CreateElementInfo (typeQName.Namespace, null, "Item", arrayTypeData.ListItemTypeData, false, XmlSchemaForm.None));\r
1300 \r
1301                                 XmlTypeMapping map = CreateArrayTypeMapping (typeQName, arrayTypeData);\r
1302                                 map.ObjectMap = listMap;\r
1303                                 map.IsSimpleType = true;\r
1304                                 return map;\r
1305                         }\r
1306 \r
1307                         // It is an extension of a primitive or known type\r
1308                         \r
1309                         TypeData typeData = FindBuiltInType (typeQName, stype);\r
1310                         XmlTypeMapping rmap = GetTypeMapping (typeData);\r
1311                         \r
1312                         // The resulting map must be a simple type. It needs to be explicitely set for arrays\r
1313                         rmap.IsSimpleType = true;\r
1314                         return rmap;\r
1315                 }\r
1316 \r
1317                 bool CanBeEnum (XmlSchemaSimpleType stype)\r
1318                 {\r
1319                         if (stype.Content is XmlSchemaSimpleTypeRestriction)\r
1320                         {\r
1321                                 XmlSchemaSimpleTypeRestriction rest = (XmlSchemaSimpleTypeRestriction)stype.Content;\r
1322                                 if (rest.Facets.Count == 0) return false;\r
1323                                 foreach (object ob in rest.Facets)\r
1324                                         if (!(ob is XmlSchemaEnumerationFacet)) return false;\r
1325                                 return true;\r
1326                         }\r
1327                         else if (stype.Content is XmlSchemaSimpleTypeList)\r
1328                         {\r
1329                                 XmlSchemaSimpleTypeList list = (XmlSchemaSimpleTypeList) stype.Content;\r
1330                                 return (list.ItemType != null && CanBeEnum (list.ItemType));\r
1331                         }\r
1332                         return false;\r
1333                 }\r
1334 \r
1335                 bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaComplexType stype)\r
1336                 {\r
1337                         if (encodedFormat)\r
1338                         {\r
1339                                 XmlSchemaComplexContent content = stype.ContentModel as XmlSchemaComplexContent;\r
1340                                 if (content == null) return false;\r
1341                                 XmlSchemaComplexContentRestriction rest = content.Content as XmlSchemaComplexContentRestriction;\r
1342                                 if (rest == null) return false;\r
1343                                 return rest.BaseTypeName == arrayType;\r
1344                         }\r
1345                         else\r
1346                         {\r
1347                                 if (stype.Attributes.Count > 0 || stype.AnyAttribute != null) return false;\r
1348                                 else return !stype.IsMixed && CanBeArray (typeQName, stype.Particle, false);\r
1349                         }\r
1350                 }\r
1351 \r
1352                 bool CanBeArray (XmlQualifiedName typeQName, XmlSchemaParticle particle, bool multiValue)\r
1353                 {\r
1354                         // To be an array, there can't be a direct child of type typeQName\r
1355 \r
1356                         if (particle == null) return false;\r
1357 \r
1358                         multiValue = multiValue || particle.MaxOccurs > 1;\r
1359 \r
1360                         if (particle is XmlSchemaGroupRef)\r
1361                                 return CanBeArray (typeQName, GetRefGroupParticle ((XmlSchemaGroupRef)particle), multiValue);\r
1362 \r
1363                         if (particle is XmlSchemaElement)\r
1364                         {\r
1365                                 XmlSchemaElement elem = (XmlSchemaElement)particle;\r
1366                                 if (!elem.RefName.IsEmpty)\r
1367                                         return CanBeArray (typeQName, FindRefElement (elem), multiValue);\r
1368                                 else\r
1369                                         return multiValue && !typeQName.Equals (((XmlSchemaElement)particle).SchemaTypeName);\r
1370                         }\r
1371 \r
1372                         if (particle is XmlSchemaAny)\r
1373                                 return multiValue;\r
1374 \r
1375                         if (particle is XmlSchemaSequence)\r
1376                         {\r
1377                                 XmlSchemaSequence seq = particle as XmlSchemaSequence;\r
1378                                 if (seq.Items.Count != 1) return false;\r
1379                                 return CanBeArray (typeQName, (XmlSchemaParticle)seq.Items[0], multiValue);\r
1380                         }\r
1381 \r
1382                         if (particle is XmlSchemaChoice)\r
1383                         {\r
1384                                 // Can be array if all choices have different types\r
1385                                 ArrayList types = new ArrayList ();\r
1386                                 if(!CheckChoiceType (typeQName, particle, types, ref multiValue)) return false;\r
1387                                 return multiValue;\r
1388                         }\r
1389 \r
1390                         return false;\r
1391                 }\r
1392 \r
1393                 bool CheckChoiceType (XmlQualifiedName typeQName, XmlSchemaParticle particle, ArrayList types, ref bool multiValue)\r
1394                 {\r
1395                         XmlQualifiedName type = null;\r
1396 \r
1397                         multiValue = multiValue || particle.MaxOccurs > 1;\r
1398 \r
1399                         if (particle is XmlSchemaGroupRef)\r
1400                                 return CheckChoiceType (typeQName, GetRefGroupParticle ((XmlSchemaGroupRef)particle), types, ref multiValue);\r
1401 \r
1402                         if (particle is XmlSchemaElement) {\r
1403                                 string ns;\r
1404                                 XmlSchemaElement elem = (XmlSchemaElement)particle;\r
1405                                 XmlSchemaElement refElem = GetRefElement (typeQName, elem, out ns);\r
1406                                 if (refElem.SchemaType != null) return true;\r
1407                                 type = refElem.SchemaTypeName;\r
1408                         }\r
1409                         else if (particle is XmlSchemaAny) {\r
1410                                 type = anyType;\r
1411                         }\r
1412                         else if (particle is XmlSchemaSequence)\r
1413                         {\r
1414                                 XmlSchemaSequence seq = particle as XmlSchemaSequence;\r
1415                                 foreach (XmlSchemaParticle par in seq.Items)\r
1416                                         if (!CheckChoiceType (typeQName, par, types, ref multiValue)) return false;\r
1417                                 return true;\r
1418                         }\r
1419                         else if (particle is XmlSchemaChoice)\r
1420                         {\r
1421                                 foreach (XmlSchemaParticle choice in ((XmlSchemaChoice)particle).Items)\r
1422                                         if (!CheckChoiceType (typeQName, choice, types, ref multiValue)) return false;\r
1423                                 return true;\r
1424                         }\r
1425 \r
1426                         if (typeQName.Equals (type)) return false;\r
1427 \r
1428                         // For primitive types, compare using CLR types, since several\r
1429                         // xml types can be mapped to a single CLR type\r
1430 \r
1431                         string t;\r
1432                         if (IsPrimitiveTypeNamespace (type.Namespace))\r
1433                                 t = TypeTranslator.GetPrimitiveTypeData (type.Name).FullTypeName + ":" + type.Namespace;\r
1434 \r
1435                         else\r
1436                                 t = type.Name + ":" + type.Namespace;\r
1437 \r
1438                         if (types.Contains (t)) return false;\r
1439                         types.Add (t);\r
1440                         return true;\r
1441                 }\r
1442                 \r
1443                 bool CanBeAnyElement (XmlSchemaComplexType stype)\r
1444                 {\r
1445                         XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;\r
1446                         return (seq != null) && (seq.Items.Count == 1) && (seq.Items[0] is XmlSchemaAny);\r
1447                 }\r
1448                 \r
1449                 Type GetAnyElementType (XmlSchemaComplexType stype)\r
1450                 {\r
1451                         XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;\r
1452                         \r
1453                         if ((seq == null) || (seq.Items.Count != 1) || !(seq.Items[0] is XmlSchemaAny))\r
1454                                 return null;\r
1455                         \r
1456                         if (encodedFormat) \r
1457                                 return typeof(object);\r
1458 \r
1459                         XmlSchemaAny any = seq.Items[0] as XmlSchemaAny;\r
1460                         if (any.MaxOccurs == 1)\r
1461                         {\r
1462                                 if (stype.IsMixed)\r
1463                                         return typeof(XmlNode);\r
1464                                 else\r
1465                                         return typeof(XmlElement);\r
1466                         }\r
1467                         else\r
1468                         {\r
1469                                 if (stype.IsMixed)\r
1470                                         return typeof(XmlNode[]);\r
1471                                 else\r
1472                                         return typeof(XmlElement[]);\r
1473                         }\r
1474                 }\r
1475 \r
1476                 bool CanBeIXmlSerializable (XmlSchemaComplexType stype)\r
1477                 {\r
1478                         XmlSchemaSequence seq = stype.Particle as XmlSchemaSequence;\r
1479                         if (seq == null) return false;\r
1480                         if (seq.Items.Count != 2) return false;\r
1481                         XmlSchemaElement elem = seq.Items[0] as XmlSchemaElement;\r
1482                         if (elem == null) return false;\r
1483                         if (elem.RefName != new XmlQualifiedName ("schema",XmlSchema.Namespace)) return false;\r
1484                         return (seq.Items[1] is XmlSchemaAny);\r
1485                 }\r
1486                 \r
1487                 XmlTypeMapping ImportXmlSerializableMapping (string ns)\r
1488                 {\r
1489                         XmlQualifiedName qname = new XmlQualifiedName ("System.Data.DataSet",ns);\r
1490                         XmlTypeMapping map = mappedTypes [qname] as XmlTypeMapping;\r
1491                         if (map != null) return map;\r
1492                         \r
1493                         TypeData typeData = new TypeData ("System.Data.DataSet", "System.Data.DataSet", "System.Data.DataSet", SchemaTypes.XmlSerializable, null);\r
1494                         map = new XmlTypeMapping ("System.Data.DataSet", "", typeData, "System.Data.DataSet", ns);\r
1495                         map.IncludeInSchema = true;\r
1496                         mappedTypes [qname] = map;\r
1497                         dataMappedTypes [typeData] = map;\r
1498                         return map;\r
1499                 }\r
1500                 \r
1501                 XmlTypeMapElementInfo CreateElementInfo (string ns, XmlTypeMapMember member, string name, TypeData typeData, bool isNillable, XmlSchemaForm form)\r
1502                 {\r
1503                         if (typeData.IsComplexType)\r
1504                                 return CreateElementInfo (ns, member, name, typeData, isNillable, form, GetTypeMapping (typeData));\r
1505                         else\r
1506                                 return CreateElementInfo (ns, member, name, typeData, isNillable, form, null);\r
1507                 }\r
1508                 \r
1509                 XmlTypeMapElementInfo CreateElementInfo (string ns, XmlTypeMapMember member, string name, TypeData typeData, bool isNillable, XmlSchemaForm form, XmlTypeMapping emap)\r
1510                 {\r
1511                         XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, typeData);\r
1512                         einfo.ElementName = name;\r
1513                         einfo.Namespace = ns;\r
1514                         einfo.IsNullable = isNillable;\r
1515                         einfo.Form = form;\r
1516                         if (typeData.IsComplexType)\r
1517                                 einfo.MappedType = emap;\r
1518                         return einfo;\r
1519                 }\r
1520 \r
1521                 XmlTypeMapElementInfo CreateTextElementInfo (string ns, XmlTypeMapMember member, TypeData typeData)\r
1522                 {\r
1523                         XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (member, typeData);\r
1524                         einfo.IsTextElement = true;\r
1525                         einfo.WrappedElement = false;\r
1526                         if (typeData.IsComplexType)\r
1527                                 einfo.MappedType = GetTypeMapping (typeData);\r
1528                         return einfo;\r
1529                 }\r
1530 \r
1531                 XmlTypeMapping CreateTypeMapping (XmlQualifiedName typeQName, SchemaTypes schemaType, XmlQualifiedName root)\r
1532                 {\r
1533                         string typeName = CodeIdentifier.MakeValid (typeQName.Name);\r
1534                         typeName = typeIdentifiers.AddUnique (typeName, null);\r
1535 \r
1536                         TypeData typeData = new TypeData (typeName, typeName, typeName, schemaType, null);\r
1537 \r
1538                         string rootElem;\r
1539                         string rootNs;\r
1540                         if (root != null) {\r
1541                                 rootElem = root.Name;\r
1542                                 rootNs = root.Namespace;\r
1543                         }\r
1544                         else {\r
1545                                 rootElem = typeQName.Name;\r
1546                                 rootNs = "";\r
1547                         }\r
1548                         \r
1549                         XmlTypeMapping map = new XmlTypeMapping (rootElem, rootNs, typeData, typeQName.Name, typeQName.Namespace);\r
1550                         map.IncludeInSchema = true;\r
1551                         mappedTypes [typeQName] = map;\r
1552                         dataMappedTypes [typeData] = map;\r
1553 \r
1554                         return map;\r
1555                 }\r
1556 \r
1557                 XmlTypeMapping CreateArrayTypeMapping (XmlQualifiedName typeQName, TypeData arrayTypeData)\r
1558                 {\r
1559                         XmlTypeMapping map;\r
1560                         if (encodedFormat) map = new XmlTypeMapping ("Array", XmlSerializer.EncodingNamespace, arrayTypeData, "Array", XmlSerializer.EncodingNamespace);\r
1561                         else map = new XmlTypeMapping (arrayTypeData.XmlType, typeQName.Namespace, arrayTypeData, arrayTypeData.XmlType, typeQName.Namespace);\r
1562                         \r
1563                         map.IncludeInSchema = true;\r
1564                         mappedTypes [typeQName] = map;\r
1565                         dataMappedTypes [arrayTypeData] = map;\r
1566 \r
1567                         return map;\r
1568                 }\r
1569 \r
1570                 XmlSchemaElement GetRefElement (XmlQualifiedName typeQName, XmlSchemaElement elem, out string ns)\r
1571                 {\r
1572 \r
1573                         if (!elem.RefName.IsEmpty)\r
1574                         {\r
1575                                 ns = elem.RefName.Namespace;\r
1576                                 return FindRefElement (elem);\r
1577                         }\r
1578                         else\r
1579                         {\r
1580                                 ns = typeQName.Namespace;\r
1581                                 return elem;\r
1582                         }\r
1583                 }\r
1584 \r
1585                 XmlSchemaAttribute GetRefAttribute (XmlQualifiedName typeQName, XmlSchemaAttribute attr, out string ns)\r
1586                 {\r
1587                         if (!attr.RefName.IsEmpty)\r
1588                         {\r
1589                                 ns = attr.RefName.Namespace;\r
1590                                 XmlSchemaAttribute at = FindRefAttribute (attr.RefName);\r
1591                                 if (at == null) throw new InvalidOperationException ("The attribute " + attr.RefName + " is missing");\r
1592                                 return at;\r
1593                         }\r
1594                         else\r
1595                         {\r
1596                                 ns = typeQName.Namespace;\r
1597                                 return attr;\r
1598                         }\r
1599                 }\r
1600 \r
1601                 TypeData GetElementTypeData (XmlQualifiedName typeQName, XmlSchemaElement elem, XmlQualifiedName root, out XmlTypeMapping map)\r
1602                 {\r
1603                         bool sharedAnnType = false;\r
1604                         map = null;\r
1605                         \r
1606                         if (!elem.RefName.IsEmpty) {\r
1607                                 XmlSchemaElement refElem = FindRefElement (elem);\r
1608                                 if (refElem == null) throw new InvalidOperationException ("Global element not found: " + elem.RefName);\r
1609                                 root = elem.RefName;\r
1610                                 elem = refElem;\r
1611                                 sharedAnnType = true;\r
1612                         }\r
1613 \r
1614                         TypeData td;\r
1615                         if (!elem.SchemaTypeName.IsEmpty) {\r
1616                                 td = GetTypeData (elem.SchemaTypeName, root);\r
1617                                 map = GetRegisteredTypeMapping (elem.SchemaTypeName);\r
1618                         }\r
1619                         else if (elem.SchemaType == null) \r
1620                                 td = TypeTranslator.GetTypeData (typeof(object));\r
1621                         else \r
1622                                 td = GetTypeData (elem.SchemaType, typeQName, elem.Name, sharedAnnType, root);\r
1623                         \r
1624                         if (map == null && td.IsComplexType)\r
1625                                 map = GetTypeMapping (td);\r
1626                                 \r
1627                         return td;\r
1628                 }\r
1629 \r
1630                 TypeData GetAttributeTypeData (XmlQualifiedName typeQName, XmlSchemaAttribute attr)\r
1631                 {\r
1632                         bool sharedAnnType = false;\r
1633 \r
1634                         if (!attr.RefName.IsEmpty) {\r
1635                                 XmlSchemaAttribute refAtt = FindRefAttribute (attr.RefName);\r
1636                                 if (refAtt == null) throw new InvalidOperationException ("Global attribute not found: " + attr.RefName);\r
1637                                 attr = refAtt;\r
1638                                 sharedAnnType = true;\r
1639                         }\r
1640                         \r
1641                         if (!attr.SchemaTypeName.IsEmpty) return GetTypeData (attr.SchemaTypeName, null);\r
1642                         if (attr.SchemaType == null) return TypeTranslator.GetTypeData (typeof(string));\r
1643                         else return GetTypeData (attr.SchemaType, typeQName, attr.Name, sharedAnnType, null);\r
1644                 }\r
1645 \r
1646                 TypeData GetTypeData (XmlQualifiedName typeQName, XmlQualifiedName root)\r
1647                 {\r
1648                         if (IsPrimitiveTypeNamespace (typeQName.Namespace)) {\r
1649                                 XmlTypeMapping map = ImportType (typeQName, root, false);\r
1650                                 if (map != null) return map.TypeData;\r
1651                                 else return TypeTranslator.GetPrimitiveTypeData (typeQName.Name);\r
1652                         }\r
1653                         \r
1654                         if (encodedFormat && typeQName.Namespace == "")\r
1655                                 return TypeTranslator.GetPrimitiveTypeData (typeQName.Name);\r
1656 \r
1657                         return ImportType (typeQName, root, true).TypeData;\r
1658                 }\r
1659 \r
1660                 TypeData GetTypeData (XmlSchemaType stype, XmlQualifiedName typeQNname, string propertyName, bool sharedAnnType, XmlQualifiedName root)\r
1661                 {\r
1662                         string baseName;\r
1663 \r
1664                         if (sharedAnnType)\r
1665                         {\r
1666                                 // Anonymous types defined in root elements or attributes can be shared among all elements that\r
1667                                 // reference this root element or attribute\r
1668                                 TypeData std = sharedAnonymousTypes [stype] as TypeData;\r
1669                                 if (std != null) return std;\r
1670                                 baseName = propertyName;\r
1671                         }\r
1672                         else\r
1673                                 baseName = typeQNname.Name + typeIdentifiers.MakeRightCase (propertyName);\r
1674 \r
1675                         baseName = elemIdentifiers.AddUnique (baseName, stype);\r
1676                         \r
1677                         XmlQualifiedName newName;\r
1678                         newName = new XmlQualifiedName (baseName, typeQNname.Namespace);\r
1679 \r
1680                         XmlTypeMapping map = ImportType (newName, stype, root);\r
1681                         if (sharedAnnType) sharedAnonymousTypes [stype] = map.TypeData;\r
1682 \r
1683                         return map.TypeData;\r
1684                 }\r
1685 \r
1686                 XmlTypeMapping GetTypeMapping (TypeData typeData)\r
1687                 {\r
1688                         if (typeData.Type == typeof(object) && !anyTypeImported)\r
1689                                 ImportAllObjectTypes ();\r
1690                                 \r
1691                         XmlTypeMapping map = (XmlTypeMapping) dataMappedTypes [typeData];\r
1692                         if (map != null) return map;\r
1693                         \r
1694                         if (typeData.IsListType)\r
1695                         {\r
1696                                 // Create an array map for the type\r
1697 \r
1698                                 XmlTypeMapping itemMap = GetTypeMapping (typeData.ListItemTypeData);\r
1699                                 \r
1700                                 map = new XmlTypeMapping (typeData.XmlType, itemMap.Namespace, typeData, typeData.XmlType, itemMap.Namespace);\r
1701                                 map.IncludeInSchema = true;\r
1702 \r
1703                                 ListMap listMap = new ListMap ();\r
1704                                 listMap.ItemInfo = new XmlTypeMapElementInfoList();\r
1705                                 listMap.ItemInfo.Add (CreateElementInfo (itemMap.Namespace, null, typeData.ListItemTypeData.XmlType, typeData.ListItemTypeData, false, XmlSchemaForm.None));\r
1706                                 map.ObjectMap = listMap;\r
1707                                 \r
1708                                 mappedTypes [new XmlQualifiedName(map.ElementName, map.Namespace)] = map;\r
1709                                 dataMappedTypes [typeData] = map;\r
1710                                 return map;\r
1711                         }\r
1712                         else if (typeData.SchemaType == SchemaTypes.Primitive || typeData.Type == typeof(object) || typeof(XmlNode).IsAssignableFrom(typeData.Type))\r
1713                         {\r
1714                                 return CreateSystemMap (typeData);\r
1715                         }\r
1716                         \r
1717                         throw new InvalidOperationException ("Map for type " + typeData.TypeName + " not found");\r
1718                 }\r
1719                 \r
1720                 void AddObjectDerivedMap (XmlTypeMapping map)\r
1721                 {\r
1722                         TypeData typeData = TypeTranslator.GetTypeData (typeof(object));\r
1723                         XmlTypeMapping omap = (XmlTypeMapping) dataMappedTypes [typeData];\r
1724                         if (omap == null)\r
1725                                 omap = CreateSystemMap (typeData);\r
1726                         omap.DerivedTypes.Add (map);\r
1727                 }\r
1728                 \r
1729                 XmlTypeMapping CreateSystemMap (TypeData typeData)\r
1730                 {\r
1731                         XmlTypeMapping map = new XmlTypeMapping (typeData.XmlType, XmlSchema.Namespace, typeData, typeData.XmlType, XmlSchema.Namespace);\r
1732                         map.IncludeInSchema = false;\r
1733                         map.ObjectMap = new ClassMap ();\r
1734                         dataMappedTypes [typeData] = map;\r
1735                         return map;\r
1736                 }\r
1737                 \r
1738                 void ImportAllObjectTypes ()\r
1739                 {\r
1740                         // All complex types are subtypes of anyType, so all of them \r
1741                         // must also be imported\r
1742                         \r
1743                         anyTypeImported = true;\r
1744                         foreach (XmlSchema schema in schemas) {\r
1745                                 foreach (XmlSchemaObject sob in schema.Items) \r
1746                                 {\r
1747                                         XmlSchemaComplexType sct = sob as XmlSchemaComplexType;\r
1748                                         if (sct != null)\r
1749                                                 ImportType (new XmlQualifiedName (sct.Name, schema.TargetNamespace), sct, null);\r
1750                                 }\r
1751                         }                                       \r
1752                 }\r
1753                 \r
1754 \r
1755                 XmlTypeMapping GetRegisteredTypeMapping (XmlQualifiedName typeQName)\r
1756                 {\r
1757                         return (XmlTypeMapping) mappedTypes [typeQName];\r
1758                 }\r
1759 \r
1760                 XmlSchemaParticle GetRefGroupParticle (XmlSchemaGroupRef refGroup)\r
1761                 {\r
1762                         XmlSchemaGroup grp = (XmlSchemaGroup) schemas.Find (refGroup.RefName, typeof (XmlSchemaGroup));\r
1763                         return grp.Particle;\r
1764                 }\r
1765 \r
1766                 XmlSchemaElement FindRefElement (XmlSchemaElement elem)\r
1767                 {\r
1768                         XmlSchemaElement refelem = (XmlSchemaElement) schemas.Find (elem.RefName, typeof(XmlSchemaElement));\r
1769                         if (refelem != null) return refelem;\r
1770                         \r
1771                         if (IsPrimitiveTypeNamespace (elem.RefName.Namespace))\r
1772                         {\r
1773                                 if (anyElement != null) return anyElement;\r
1774                                 anyElement = new XmlSchemaElement ();\r
1775                                 anyElement.Name = "any";\r
1776                                 anyElement.SchemaTypeName = anyType;\r
1777                                 return anyElement;\r
1778                         } else\r
1779                                 return null;\r
1780                 }\r
1781                 \r
1782                 XmlSchemaAttribute FindRefAttribute (XmlQualifiedName refName)\r
1783                 {\r
1784                         if (refName.Namespace == XmlNamespace)\r
1785                         {\r
1786                                 XmlSchemaAttribute at = new XmlSchemaAttribute ();\r
1787                                 at.Name = refName.Name;\r
1788                                 at.SchemaTypeName = new XmlQualifiedName ("string",XmlSchema.Namespace);\r
1789                                 return at;\r
1790                         }\r
1791                         return (XmlSchemaAttribute) schemas.Find (refName, typeof(XmlSchemaAttribute));\r
1792                 }\r
1793                 \r
1794                 XmlSchemaAttributeGroup FindRefAttributeGroup (XmlQualifiedName refName)\r
1795                 {\r
1796                         XmlSchemaAttributeGroup grp = (XmlSchemaAttributeGroup) schemas.Find (refName, typeof(XmlSchemaAttributeGroup));\r
1797                         foreach (XmlSchemaObject at in grp.Attributes)\r
1798                         {\r
1799                                 if (at is XmlSchemaAttributeGroupRef && ((XmlSchemaAttributeGroupRef)at).RefName == refName)\r
1800                                         throw new InvalidOperationException ("Cannot import attribute group '" + refName.Name + "' from namespace '" + refName.Namespace + "'. Redefine not supported");\r
1801                                         \r
1802                         }\r
1803                         return grp;\r
1804                 }\r
1805 \r
1806                 XmlTypeMapping ReflectType (Type type)\r
1807                 {\r
1808                         TypeData typeData = TypeTranslator.GetTypeData (type);\r
1809                         return ReflectType (typeData, (string) null);\r
1810                 }\r
1811 \r
1812                 XmlTypeMapping ReflectType (TypeData typeData, string ns)\r
1813                 {\r
1814                         if (!encodedFormat)\r
1815                         {\r
1816                                 if (auxXmlRefImporter == null) auxXmlRefImporter = new XmlReflectionImporter ();\r
1817                                 return auxXmlRefImporter.ImportTypeMapping (typeData, ns);\r
1818                         }\r
1819                         else\r
1820                         {\r
1821                                 if (auxSoapRefImporter == null) auxSoapRefImporter = new SoapReflectionImporter ();\r
1822                                 return auxSoapRefImporter.ImportTypeMapping (typeData, ns);\r
1823                         }\r
1824                 }\r
1825 \r
1826 \r
1827                 string GetDocumentation (XmlSchemaAnnotated elem)\r
1828                 {\r
1829                         string res = "";\r
1830                         XmlSchemaAnnotation anot = elem.Annotation;\r
1831                         if (anot == null || anot.Items == null) return null;\r
1832                         \r
1833                         foreach (object ob in anot.Items)\r
1834                         {\r
1835                                 XmlSchemaDocumentation doc = ob as XmlSchemaDocumentation;\r
1836                                 if (doc != null && doc.Markup != null && doc.Markup.Length > 0) {\r
1837                                         if (res != string.Empty) res += "\n";\r
1838                                         foreach (XmlNode node in doc.Markup)\r
1839                                                 res += node.Value;\r
1840                                 }\r
1841                         }\r
1842                         return res;\r
1843                 }\r
1844                 \r
1845                 bool IsPrimitiveTypeNamespace (string ns)\r
1846                 {\r
1847                         return (ns == XmlSchema.Namespace) || (encodedFormat && ns == XmlSerializer.EncodingNamespace);\r
1848                 }\r
1849 \r
1850                 #endregion // Methods\r
1851         }\r
1852 }\r