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