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