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