Moved chain building and validation from Mono.Security to System
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSchemaExporter.cs
1 // 
2 // System.Xml.Serialization.XmlSchemaExporter 
3 //
4 // Author:
5 //   Tim Coleman (tim@timcoleman.com)
6 //   Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // Copyright (C) Tim Coleman, 2002
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 using System.Xml;
33 using System.Xml.Schema;
34 using System.Collections;
35
36 namespace System.Xml.Serialization {
37         public class XmlSchemaExporter {
38
39                 #region Fields
40
41                 XmlSchemas schemas;
42                 Hashtable exportedMaps = new Hashtable();
43                 Hashtable exportedElements = new Hashtable();
44                 bool encodedFormat = false;
45                 XmlDocument xmlDoc;
46                 
47                 #endregion
48
49                 #region Constructors
50
51                 public XmlSchemaExporter (XmlSchemas schemas)
52                 {
53                         this.schemas = schemas;
54                 }
55
56                 internal XmlSchemaExporter (XmlSchemas schemas, bool encodedFormat)
57                 {
58                         this.encodedFormat = encodedFormat;
59                         this.schemas = schemas;
60                 }
61
62                 #endregion // Constructors
63
64                 #region Methods
65
66                 [MonoTODO]
67                 public string ExportAnyType (string ns)
68                 {
69                         throw new NotImplementedException ();
70                 }
71
72 #if NET_2_0
73                 [MonoNotSupported("")]
74                 public string ExportAnyType (XmlMembersMapping members)
75                 {
76                         throw new NotImplementedException ();
77                 }
78 #endif
79
80                 public void ExportMembersMapping (XmlMembersMapping xmlMembersMapping)
81                 {
82                         ExportMembersMapping (xmlMembersMapping, true);
83                 }
84
85 #if NET_2_0
86                 public
87 #else
88                 internal 
89 #endif
90                 void ExportMembersMapping (XmlMembersMapping xmlMembersMapping, bool exportEnclosingType)
91                 {
92                         ClassMap cmap = (ClassMap) xmlMembersMapping.ObjectMap;
93
94                         if (xmlMembersMapping.HasWrapperElement && exportEnclosingType)
95                         {
96                                 XmlSchema schema = GetSchema (xmlMembersMapping.Namespace);
97                                 XmlSchemaComplexType stype = new XmlSchemaComplexType ();
98         
99                                 XmlSchemaSequence particle;
100                                 XmlSchemaAnyAttribute anyAttribute;
101                                 ExportMembersMapSchema (schema, cmap, null, stype.Attributes, out particle, out anyAttribute);
102                                 stype.Particle = particle;
103                                 stype.AnyAttribute = anyAttribute;
104                                 
105                                 if (encodedFormat)
106                                 {
107                                         stype.Name = xmlMembersMapping.ElementName;
108                                         schema.Items.Add (stype);
109                                 }
110                                 else
111                                 {
112                                         XmlSchemaElement selem = new XmlSchemaElement ();
113                                         selem.Name = xmlMembersMapping.ElementName;
114                                         selem.SchemaType = stype;
115                                         schema.Items.Add (selem);
116                                 }
117                         }
118                         else
119                         {
120                                 ICollection members = cmap.ElementMembers;
121                                 if (members != null)
122                                 {
123                                         foreach (XmlTypeMapMemberElement member in members)
124                                         {
125                                                 if (member is XmlTypeMapMemberAnyElement && member.TypeData.IsListType)
126                                                 {
127                                                         XmlSchema mschema = GetSchema (xmlMembersMapping.Namespace);
128                                                         XmlSchemaParticle par = GetSchemaArrayElement (mschema, member.ElementInfo);
129                                                         if (par is XmlSchemaAny)
130                                                         {
131                                                                 XmlSchemaComplexType ct = FindComplexType (mschema.Items, "any");
132                                                                 if (ct != null) continue;
133                                                                 
134                                                                 ct = new XmlSchemaComplexType ();
135                                                                 ct.Name = "any";
136                                                                 ct.IsMixed = true;
137                                                                 XmlSchemaSequence seq = new XmlSchemaSequence ();
138                                                                 ct.Particle = seq;
139                                                                 seq.Items.Add (par);
140                                                                 mschema.Items.Add (ct);
141                                                                 continue;
142                                                         }
143                                                 }
144                                                 
145                                                 
146                                                 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo [0];
147                                                 XmlSchema schema;
148
149                                                 if (encodedFormat)
150                                                 {
151                                                         schema = GetSchema (xmlMembersMapping.Namespace);
152                                                         ImportNamespace (schema, XmlSerializer.EncodingNamespace);
153                                                 }
154                                                 else
155                                                         schema = GetSchema (einfo.Namespace);
156                                                 
157                                                 
158                                                 XmlSchemaElement exe = FindElement (schema.Items, einfo.ElementName);
159                                                 XmlSchemaElement elem;
160                                                 
161                                                 XmlSchemaObjectContainer container = null;
162                                                 // In encoded format, the schema elements are not needed
163                                                 if (!encodedFormat)
164                                                         container = new XmlSchemaObjectContainer (schema);
165
166                                                 Type memType = member.GetType();
167                                                 if (member is XmlTypeMapMemberFlatList)
168                                                         throw new InvalidOperationException ("Unwrapped arrays not supported as parameters");
169                                                 else if (memType == typeof(XmlTypeMapMemberElement))
170                                                         elem = (XmlSchemaElement) GetSchemaElement (schema,
171                                                                 einfo, member.DefaultValue, false, container);
172                                                 else
173                                                         elem = (XmlSchemaElement) GetSchemaElement (schema,
174                                                                 einfo, false, container);
175                                                 
176                                                 if (exe != null)
177                                                 {
178                                                         if (exe.SchemaTypeName.Equals (elem.SchemaTypeName))
179                                                                 schema.Items.Remove (elem);
180                                                         else
181                                                         {
182                                                                 string s = "The XML element named '" + einfo.ElementName + "' ";
183                                                                 s += "from namespace '" + schema.TargetNamespace + "' references distinct types " + elem.SchemaTypeName.Name + " and " + exe.SchemaTypeName.Name + ". ";
184                                                                 s += "Use XML attributes to specify another XML name or namespace for the element or types.";
185                                                                 throw new InvalidOperationException (s);
186                                                         }
187                                                 }
188                                         }
189                                 }
190                         }
191                         
192                         CompileSchemas ();
193                 }
194
195                 [MonoTODO]
196                 public XmlQualifiedName ExportTypeMapping (XmlMembersMapping xmlMembersMapping)
197                 {
198                         throw new NotImplementedException ();
199                 }
200
201                 public void ExportTypeMapping (XmlTypeMapping xmlTypeMapping)
202                 {
203                         if (!xmlTypeMapping.IncludeInSchema) return;
204                         if (IsElementExported (xmlTypeMapping)) return;
205                         
206                         if (encodedFormat)
207                         {
208                                 ExportClassSchema (xmlTypeMapping);
209                                 XmlSchema schema = GetSchema (xmlTypeMapping.XmlTypeNamespace);
210                                 ImportNamespace (schema, XmlSerializer.EncodingNamespace);
211                         }
212                         else
213                         {
214                                 XmlSchema schema = GetSchema (xmlTypeMapping.Namespace);
215                                 XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (null, xmlTypeMapping.TypeData);
216                                 einfo.Namespace = xmlTypeMapping.Namespace;
217                                 einfo.ElementName = xmlTypeMapping.ElementName;
218                                 if (xmlTypeMapping.TypeData.IsComplexType)
219                                         einfo.MappedType = xmlTypeMapping;
220                                 einfo.IsNullable = xmlTypeMapping.IsNullable;
221                                 GetSchemaElement (schema, einfo, false, new XmlSchemaObjectContainer (schema));
222                                 SetElementExported (xmlTypeMapping);
223                         }
224                         
225                         CompileSchemas ();
226                 }
227
228                 void ExportXmlSerializableSchema (XmlSchema currentSchema, XmlSerializableMapping map)
229                 {
230                 if (IsMapExported (map)) return;
231                 SetMapExported (map);
232                 
233                 if (map.Schema == null) return;
234
235                         string targetNs = map.Schema.TargetNamespace;
236                 XmlSchema existingSchema = schemas [targetNs];
237                 if (existingSchema == null)
238                 {
239                                 schemas.Add (map.Schema);
240                                 ImportNamespace (currentSchema, targetNs);
241                 }
242                 else if (existingSchema != map.Schema && !CanBeDuplicated (existingSchema, map.Schema))
243                 {
244                                 throw new InvalidOperationException("The namespace '" + targetNs +"' defined by the class '" + map.TypeFullName + "' is a duplicate.");
245                 }
246                 }
247
248                 private static bool CanBeDuplicated (XmlSchema existingSchema, XmlSchema schema)
249                 {
250                         if(XmlSchemas.IsDataSet (existingSchema) && XmlSchemas.IsDataSet (schema)
251                                 && existingSchema.Id == schema.Id)
252                                 return true;
253                         return false;
254                 }
255
256                 void ExportClassSchema (XmlTypeMapping map)
257                 {
258                         if (IsMapExported (map)) return;
259                         SetMapExported (map);
260                         
261                         if (map.TypeData.Type == typeof(object))
262                         {
263                                 foreach (XmlTypeMapping dmap in map.DerivedTypes)
264                                         if (dmap.TypeData.SchemaType == SchemaTypes.Class) ExportClassSchema (dmap);
265                                 return;
266                         }
267
268                         XmlSchema schema = GetSchema (map.XmlTypeNamespace);
269                         XmlSchemaComplexType stype = new XmlSchemaComplexType ();
270                         stype.Name = map.XmlType;
271                         schema.Items.Add (stype);
272
273                         ClassMap cmap = (ClassMap)map.ObjectMap;
274
275                         if (cmap.HasSimpleContent)
276                         {
277                                 XmlSchemaSimpleContent simple = new XmlSchemaSimpleContent ();
278                                 stype.ContentModel = simple;
279                                 XmlSchemaSimpleContentExtension ext = new XmlSchemaSimpleContentExtension ();
280                                 simple.Content = ext;
281                                 XmlSchemaSequence particle;
282                                 XmlSchemaAnyAttribute anyAttribute;
283                                 ExportMembersMapSchema (schema, cmap, map.BaseMap, ext.Attributes, out particle, out anyAttribute);
284                                 ext.AnyAttribute = anyAttribute;
285                                 if (map.BaseMap == null)
286                                         ext.BaseTypeName = cmap.SimpleContentBaseType;
287                                 else {
288                                         ext.BaseTypeName = new XmlQualifiedName (map.BaseMap.XmlType, map.BaseMap.XmlTypeNamespace);
289                                         ImportNamespace (schema, map.BaseMap.XmlTypeNamespace);
290                                         ExportClassSchema (map.BaseMap);
291                                 }
292                         }
293                         else if (map.BaseMap != null && map.BaseMap.IncludeInSchema)
294                         {
295                                 XmlSchemaComplexContent cstype = new XmlSchemaComplexContent ();
296                                 XmlSchemaComplexContentExtension ext = new XmlSchemaComplexContentExtension ();
297                                 ext.BaseTypeName = new XmlQualifiedName (map.BaseMap.XmlType, map.BaseMap.XmlTypeNamespace);
298                                 cstype.Content = ext;
299                                 stype.ContentModel = cstype;
300
301                                 XmlSchemaSequence particle;
302                                 XmlSchemaAnyAttribute anyAttribute;
303                                 ExportMembersMapSchema (schema, cmap, map.BaseMap, ext.Attributes, out particle, out anyAttribute);
304                                 ext.Particle = particle;
305                                 ext.AnyAttribute = anyAttribute;
306                                 stype.IsMixed = HasMixedContent (map);
307                                 cstype.IsMixed = BaseHasMixedContent (map);
308
309                                 ImportNamespace (schema, map.BaseMap.XmlTypeNamespace);
310                                 ExportClassSchema (map.BaseMap);
311                         }
312                         else
313                         {
314                                 XmlSchemaSequence particle;
315                                 XmlSchemaAnyAttribute anyAttribute;
316                                 ExportMembersMapSchema (schema, cmap, map.BaseMap, stype.Attributes, out particle, out anyAttribute);
317                                 stype.Particle = particle;
318                                 stype.AnyAttribute = anyAttribute;
319                                 stype.IsMixed = cmap.XmlTextCollector != null;
320                         }
321                         
322                         foreach (XmlTypeMapping dmap in map.DerivedTypes)
323                                 if (dmap.TypeData.SchemaType == SchemaTypes.Class) ExportClassSchema (dmap);
324                 }
325                 
326                 bool BaseHasMixedContent (XmlTypeMapping map)
327                 {
328                         ClassMap cmap = (ClassMap)map.ObjectMap;
329                         return (cmap.XmlTextCollector != null && (map.BaseMap != null && DefinedInBaseMap (map.BaseMap, cmap.XmlTextCollector)));
330                 }
331
332                 bool HasMixedContent (XmlTypeMapping map)
333                 {
334                         ClassMap cmap = (ClassMap)map.ObjectMap;
335                         return (cmap.XmlTextCollector != null && (map.BaseMap == null || !DefinedInBaseMap (map.BaseMap, cmap.XmlTextCollector)));
336                 }
337
338                 void ExportMembersMapSchema (XmlSchema schema, ClassMap map, XmlTypeMapping baseMap, XmlSchemaObjectCollection outAttributes, out XmlSchemaSequence particle, out XmlSchemaAnyAttribute anyAttribute)
339                 {
340                         particle = null;
341                         XmlSchemaSequence seq = new XmlSchemaSequence ();
342
343                         ICollection members = map.ElementMembers;
344                         if (members != null && !map.HasSimpleContent)
345                         {
346                                 foreach (XmlTypeMapMemberElement member in members)
347                                 {
348                                         if (baseMap != null && DefinedInBaseMap (baseMap, member)) continue;
349
350                                         Type memType = member.GetType();
351                                         if (memType == typeof(XmlTypeMapMemberFlatList))
352                                         {
353                                                 XmlSchemaParticle part = GetSchemaArrayElement (schema, member.ElementInfo);
354                                                 if (part != null) seq.Items.Add (part);
355                                         }
356                                         else if (memType == typeof(XmlTypeMapMemberAnyElement))
357                                         {
358                                                 seq.Items.Add (GetSchemaArrayElement (schema, member.ElementInfo));
359                                         }
360                                         else if (memType == typeof(XmlTypeMapMemberElement))
361                                         {
362                                                 GetSchemaElement (schema, (XmlTypeMapElementInfo) member.ElementInfo [0], 
363                                                         member.DefaultValue, true, new XmlSchemaObjectContainer (seq));
364                                         }
365                                         else
366                                         {
367                                                 GetSchemaElement (schema, (XmlTypeMapElementInfo) member.ElementInfo[0], 
368                                                         true, new XmlSchemaObjectContainer (seq));
369                                         }
370                                 }
371                         }
372
373                         if (seq.Items.Count > 0)
374                                 particle = seq;
375
376                         // Write attributes
377
378                         ICollection attributes = map.AttributeMembers;
379                         if (attributes != null)
380                         {
381                                 foreach (XmlTypeMapMemberAttribute attr in attributes) {
382                                         if (baseMap != null && DefinedInBaseMap (baseMap, attr)) continue;
383                                         outAttributes.Add (GetSchemaAttribute (schema, attr, true));
384                                 }
385                         }
386
387                         XmlTypeMapMember anyAttrMember = map.DefaultAnyAttributeMember;
388                         if (anyAttrMember != null)
389                                 anyAttribute = new XmlSchemaAnyAttribute ();
390                         else
391                                 anyAttribute = null;
392                 }
393                 
394                 XmlSchemaElement FindElement (XmlSchemaObjectCollection col, string name)
395                 {
396                         foreach (XmlSchemaObject ob in col)
397                         {
398                                 XmlSchemaElement elem = ob as XmlSchemaElement;
399                                 if (elem != null && elem.Name == name) return elem;
400                         }
401                         return null;
402                 }
403
404                 XmlSchemaComplexType FindComplexType (XmlSchemaObjectCollection col, string name)
405                 {
406                         foreach (XmlSchemaObject ob in col)
407                         {
408                                 XmlSchemaComplexType ctype = ob as XmlSchemaComplexType;
409                                 if (ctype != null && ctype.Name == name) return ctype;
410                         }
411                         return null;
412                 }
413
414                 XmlSchemaAttribute GetSchemaAttribute (XmlSchema currentSchema, XmlTypeMapMemberAttribute attinfo, bool isTypeMember)
415                 {
416                         XmlSchemaAttribute sat = new XmlSchemaAttribute ();
417                         if (attinfo.DefaultValue != System.DBNull.Value) {
418                                 sat.DefaultValue = ExportDefaultValue (attinfo.TypeData,
419                                         attinfo.MappedType, attinfo.DefaultValue);
420                         } else {
421                                 if (!attinfo.IsOptionalValueType && attinfo.TypeData.IsValueType)
422                                         sat.Use = XmlSchemaUse.Required;
423                         }
424
425                         ImportNamespace (currentSchema, attinfo.Namespace);
426
427                         XmlSchema memberSchema;
428                         if (attinfo.Namespace.Length == 0 && attinfo.Form != XmlSchemaForm.Qualified)
429                                 memberSchema = currentSchema;
430                         else
431                                 memberSchema = GetSchema (attinfo.Namespace);
432
433                         if (currentSchema == memberSchema || encodedFormat)
434                         {
435                                 sat.Name = attinfo.AttributeName;
436                                 if (isTypeMember) sat.Form = attinfo.Form;
437                                 if (attinfo.TypeData.SchemaType == SchemaTypes.Enum)
438                                 {
439                                         ImportNamespace (currentSchema, attinfo.DataTypeNamespace);
440                                         ExportEnumSchema (attinfo.MappedType);
441                                         sat.SchemaTypeName = new XmlQualifiedName (attinfo.TypeData.XmlType, attinfo.DataTypeNamespace);
442                                 }
443                                 else if (attinfo.TypeData.SchemaType == SchemaTypes.Array && TypeTranslator.IsPrimitive (attinfo.TypeData.ListItemType))
444                                 {
445                                         sat.SchemaType = GetSchemaSimpleListType (attinfo.TypeData);
446                                 }
447                                 else
448                                         sat.SchemaTypeName = new XmlQualifiedName (attinfo.TypeData.XmlType, attinfo.DataTypeNamespace);;
449                         }
450                         else
451                         {
452                                 sat.RefName = new XmlQualifiedName (attinfo.AttributeName, attinfo.Namespace);
453                                 foreach (XmlSchemaObject ob in memberSchema.Items)
454                                         if (ob is XmlSchemaAttribute && ((XmlSchemaAttribute)ob).Name == attinfo.AttributeName)
455                                                 return sat;
456                                                 
457                                 memberSchema.Items.Add (GetSchemaAttribute (memberSchema, attinfo, false));
458                         }
459                         return sat;
460                 }
461
462                 XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, bool isTypeMember)
463                 {
464                         return GetSchemaElement (currentSchema, einfo, System.DBNull.Value, 
465                                 isTypeMember, (XmlSchemaObjectContainer) null);
466                 }
467                 
468                 XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, bool isTypeMember, XmlSchemaObjectContainer container)
469                 {
470                         return GetSchemaElement (currentSchema, einfo, System.DBNull.Value, isTypeMember, container);
471                 }
472
473                 XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, object defaultValue, bool isTypeMember, XmlSchemaObjectContainer container)
474                 {
475                         if (einfo.IsTextElement) return null;
476
477                         if (einfo.IsUnnamedAnyElement)
478                         {
479                                 XmlSchemaAny any = new XmlSchemaAny ();
480                                 any.MinOccurs = 0;
481                                 any.MaxOccurs = 1;
482                                 if (container != null)
483                                         container.Items.Add (any);
484                                 return any;
485                         }
486                         
487                         XmlSchemaElement selem = new XmlSchemaElement ();
488                         selem.IsNillable = einfo.IsNullable;
489                         if (container != null)
490                                 container.Items.Add (selem);
491
492                         if (isTypeMember)
493                         {
494                                 selem.MaxOccurs = 1;
495                                 selem.MinOccurs = einfo.IsNullable ? 1 : 0;
496
497                                 if ((defaultValue == DBNull.Value && einfo.TypeData.IsValueType && einfo.Member != null && !einfo.Member.IsOptionalValueType) || encodedFormat)
498                                         selem.MinOccurs = 1;
499                         }
500
501                         XmlSchema memberSchema = null;
502                         
503                         if (!encodedFormat)
504                         {
505                                 memberSchema = GetSchema (einfo.Namespace);
506                                 ImportNamespace (currentSchema, einfo.Namespace);
507                         }
508                         
509                         if (currentSchema == memberSchema || encodedFormat || !isTypeMember)
510                         {
511                                 if (isTypeMember) selem.IsNillable = einfo.IsNullable;
512                                 selem.Name = einfo.ElementName;
513
514                                 if (defaultValue != System.DBNull.Value)
515                                         selem.DefaultValue = ExportDefaultValue (einfo.TypeData,
516                                                 einfo.MappedType, defaultValue);
517
518                                 if (einfo.Form != XmlSchemaForm.Qualified)
519                                         selem.Form = einfo.Form;
520
521                                 switch (einfo.TypeData.SchemaType)
522                                 {
523                                         case SchemaTypes.XmlNode: 
524                                                 selem.SchemaType = GetSchemaXmlNodeType ();
525                                                 break;
526
527                                         case SchemaTypes.XmlSerializable:
528                                                 SetSchemaXmlSerializableType (einfo.MappedType as XmlSerializableMapping, selem);
529                                                 ExportXmlSerializableSchema (currentSchema, einfo.MappedType as XmlSerializableMapping);
530                                                 break;
531
532                                         case SchemaTypes.Enum:
533                                                 selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);
534                                                 ImportNamespace (currentSchema, einfo.MappedType.XmlTypeNamespace);
535                                                 ExportEnumSchema (einfo.MappedType);
536                                                 break;
537
538                                         case SchemaTypes.Array: 
539                                                 XmlQualifiedName atypeName = ExportArraySchema (einfo.MappedType, currentSchema.TargetNamespace); 
540                                                 selem.SchemaTypeName = atypeName;
541                                                 ImportNamespace (currentSchema, atypeName.Namespace);
542                                                 break;
543
544                                         case SchemaTypes.Class:
545                                                 if (einfo.MappedType.TypeData.Type != typeof(object)) {
546                                                         selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);
547                                                         ImportNamespace (currentSchema, einfo.MappedType.XmlTypeNamespace);
548                                                 }
549                                                 else if (encodedFormat)
550                                                         selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);
551                                                         
552                                                 ExportClassSchema (einfo.MappedType);
553                                                 break;
554
555                                         case SchemaTypes.Primitive:
556                                                 selem.SchemaTypeName = new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);
557                                                 if (!einfo.TypeData.IsXsdType) {
558                                                         ImportNamespace (currentSchema, einfo.MappedType.XmlTypeNamespace);
559                                                         ExportDerivedSchema (einfo.MappedType);
560                                                 }
561                                                 break;
562                                 }
563                         }
564                         else
565                         {
566                                 selem.RefName = new XmlQualifiedName (einfo.ElementName, einfo.Namespace);
567                                 foreach (XmlSchemaObject ob in memberSchema.Items)
568                                         if (ob is XmlSchemaElement && ((XmlSchemaElement)ob).Name == einfo.ElementName)
569                                                 return selem;
570
571                                 GetSchemaElement (memberSchema, einfo, defaultValue, false,
572                                         new XmlSchemaObjectContainer (memberSchema));
573                         }
574                         return selem;
575                 }
576
577                 void ImportNamespace (XmlSchema schema, string ns)
578                 {
579                         if (ns == null || ns.Length == 0 ||
580                                 ns == schema.TargetNamespace || ns == XmlSchema.Namespace) return;
581
582                         foreach (XmlSchemaObject sob in schema.Includes)
583                                 if ((sob is XmlSchemaImport) && ((XmlSchemaImport)sob).Namespace == ns) return;
584
585                         XmlSchemaImport imp = new XmlSchemaImport ();
586                         imp.Namespace = ns;
587                         schema.Includes.Add (imp);
588                 }
589
590                 bool DefinedInBaseMap (XmlTypeMapping map, XmlTypeMapMember member)
591                 {
592                         if (((ClassMap)map.ObjectMap).FindMember (member.Name) != null)
593                                 return true;
594                         else if (map.BaseMap != null)
595                                 return DefinedInBaseMap (map.BaseMap, member);
596                         else
597                                 return false;
598                 }
599
600                 XmlSchemaType GetSchemaXmlNodeType ()
601                 {
602                         XmlSchemaComplexType stype = new XmlSchemaComplexType ();
603                         stype.IsMixed = true;
604                         XmlSchemaSequence seq = new XmlSchemaSequence ();
605                         seq.Items.Add (new XmlSchemaAny ());
606                         stype.Particle = seq;
607                         return stype;
608                 }
609
610                 void SetSchemaXmlSerializableType (XmlSerializableMapping map, XmlSchemaElement elem)
611                 {
612 #if NET_2_0
613                         if (map.SchemaType != null && map.Schema != null) {
614                                 elem.SchemaType = map.SchemaType;
615                                 return;
616                         }
617
618                         if (map.SchemaType == null && map.SchemaTypeName != null) {
619                                 elem.SchemaTypeName = map.SchemaTypeName;
620                                 elem.Name = map.SchemaTypeName.Name;
621                                 return;
622                         }
623 #endif
624                         XmlSchemaComplexType stype = new XmlSchemaComplexType ();
625                         XmlSchemaSequence seq = new XmlSchemaSequence ();
626                         if (map.Schema == null) {
627                                 XmlSchemaElement selem = new XmlSchemaElement ();
628                                 selem.RefName = new XmlQualifiedName ("schema",XmlSchema.Namespace);
629                                 seq.Items.Add (selem);
630                                 seq.Items.Add (new XmlSchemaAny ());
631                         } else {
632                                 XmlSchemaAny any = new XmlSchemaAny ();
633                                 any.Namespace = map.Schema.TargetNamespace;
634                                 seq.Items.Add (any);
635                         }
636                         stype.Particle = seq;
637                         elem.SchemaType = stype;
638                 }
639
640                 XmlSchemaSimpleType GetSchemaSimpleListType (TypeData typeData)
641                 {
642                         XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
643                         XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList ();
644                         TypeData itemTypeData = TypeTranslator.GetTypeData (typeData.ListItemType);
645                         list.ItemTypeName = new XmlQualifiedName (itemTypeData.XmlType, XmlSchema.Namespace);
646                         stype.Content = list;
647                         return stype;
648                 }
649
650                 XmlSchemaParticle GetSchemaArrayElement (XmlSchema currentSchema, XmlTypeMapElementInfoList infos)
651                 {
652                         int numInfos = infos.Count;
653                         if (numInfos > 0 && ((XmlTypeMapElementInfo)infos[0]).IsTextElement) numInfos--;
654                         if (numInfos == 0) return null;
655
656                         if (numInfos == 1)
657                         {
658                                 XmlSchemaParticle selem = GetSchemaElement (currentSchema, (XmlTypeMapElementInfo) infos[infos.Count-1], true);
659                                 selem.MinOccursString = "0";
660                                 selem.MaxOccursString = "unbounded";
661                                 return selem;
662                         }
663                         else
664                         {
665                                 XmlSchemaChoice schoice = new XmlSchemaChoice ();
666                                 schoice.MinOccursString = "0";
667                                 schoice.MaxOccursString = "unbounded";
668                                 foreach (XmlTypeMapElementInfo einfo in infos)
669                                 {
670                                         if (einfo.IsTextElement) continue;
671                                         schoice.Items.Add (GetSchemaElement (currentSchema, einfo, true));
672                                 }
673                                 return schoice;
674                         }
675                 }
676
677                 string ExportDefaultValue (TypeData typeData, XmlTypeMapping map, object defaultValue)
678                 {
679                         if (typeData.SchemaType == SchemaTypes.Enum) {
680                                 EnumMap enumMap = (EnumMap) map.ObjectMap;
681                                 // get corresponding xml name
682                                 return enumMap.GetXmlName (map.TypeFullName, defaultValue);
683                 }
684                         return XmlCustomFormatter.ToXmlString (typeData, defaultValue);
685                 }
686
687                 void ExportDerivedSchema(XmlTypeMapping map) {
688                         if (IsMapExported (map)) return;
689                         SetMapExported (map);
690
691                         XmlSchema schema = GetSchema (map.XmlTypeNamespace);
692                         for (int i = 0; i < schema.Items.Count; i++) {
693                                 XmlSchemaSimpleType item = schema.Items [i] as XmlSchemaSimpleType;
694                                 if (item != null && item.Name == map.ElementName)
695                                         return;
696                         }
697                         XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
698                         stype.Name = map.ElementName;
699                         schema.Items.Add (stype);
700
701                         XmlSchemaSimpleTypeRestriction rest = new XmlSchemaSimpleTypeRestriction ();
702                         rest.BaseTypeName = new XmlQualifiedName (map.TypeData.MappedType.XmlType, XmlSchema.Namespace);
703                         XmlSchemaPatternFacet facet = map.TypeData.XmlSchemaPatternFacet;
704                         if (facet != null)
705                                 rest.Facets.Add(facet);
706                         stype.Content = rest;
707                 }
708
709                 void ExportEnumSchema (XmlTypeMapping map)
710                 {
711                         if (IsMapExported (map)) return;
712                         SetMapExported (map);
713
714                         XmlSchema schema = GetSchema (map.XmlTypeNamespace);
715                         XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
716                         stype.Name = map.ElementName;
717                         schema.Items.Add (stype);
718
719                         XmlSchemaSimpleTypeRestriction rest = new XmlSchemaSimpleTypeRestriction ();
720                         rest.BaseTypeName = new XmlQualifiedName ("string",XmlSchema.Namespace);
721                         EnumMap emap = (EnumMap) map.ObjectMap;
722
723                         foreach (EnumMap.EnumMapMember emem in emap.Members)
724                         {
725                                 XmlSchemaEnumerationFacet ef = new XmlSchemaEnumerationFacet ();
726                                 ef.Value = emem.XmlName;
727                                 rest.Facets.Add (ef);
728                         }
729
730                         if (emap.IsFlags) {
731                                 XmlSchemaSimpleTypeList slist = new XmlSchemaSimpleTypeList ();
732                                 XmlSchemaSimpleType restrictionType = new XmlSchemaSimpleType ();
733                                 restrictionType.Content = rest;
734                                 slist.ItemType = restrictionType;
735                                 stype.Content = slist;
736                         } else {
737                                 stype.Content = rest;
738                         }
739                 }
740
741                 XmlQualifiedName ExportArraySchema (XmlTypeMapping map, string defaultNamespace)
742                 {
743                         ListMap lmap = (ListMap) map.ObjectMap;
744
745                         if (encodedFormat)
746                         {
747                                 string name, ns, schemaNs;
748                                 lmap.GetArrayType (-1, out name, out ns);                               
749                                 if (ns == XmlSchema.Namespace) schemaNs = defaultNamespace;
750                                 else schemaNs = ns;
751
752                                 if (IsMapExported (map)) return new XmlQualifiedName (lmap.GetSchemaArrayName (), schemaNs);
753                                 SetMapExported (map);
754
755                                 XmlSchema schema = GetSchema (schemaNs);
756                                 XmlSchemaComplexType stype = new XmlSchemaComplexType ();
757                                 stype.Name = lmap.GetSchemaArrayName ();
758                                 schema.Items.Add (stype);
759                                 
760                                 XmlSchemaComplexContent content = new XmlSchemaComplexContent();
761                                 content.IsMixed = false;
762                                 stype.ContentModel = content;
763                                 
764                                 XmlSchemaComplexContentRestriction rest = new XmlSchemaComplexContentRestriction ();
765                                 content.Content = rest;
766                                 rest.BaseTypeName = new XmlQualifiedName ("Array", XmlSerializer.EncodingNamespace);
767                                 XmlSchemaAttribute at = new XmlSchemaAttribute ();
768                                 rest.Attributes.Add (at);
769                                 at.RefName = new XmlQualifiedName ("arrayType", XmlSerializer.EncodingNamespace);
770                                 
771                                 XmlAttribute arrayType = Document.CreateAttribute ("arrayType", XmlSerializer.WsdlNamespace);
772                                 arrayType.Value = ns + (ns != "" ? ":" : "") + name;
773                                 at.UnhandledAttributes = new XmlAttribute [] { arrayType };
774                                 ImportNamespace (schema, XmlSerializer.WsdlNamespace);
775                         
776                                 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) lmap.ItemInfo[0];
777                                 if (einfo.MappedType != null)
778                                 {
779                                         switch (einfo.TypeData.SchemaType)
780                                         {
781                                                 case SchemaTypes.Enum:
782                                                         ExportEnumSchema (einfo.MappedType);
783                                                         break;
784                                                 case SchemaTypes.Array: 
785                                                         ExportArraySchema (einfo.MappedType, schemaNs); 
786                                                         break;
787                                                 case SchemaTypes.Class:
788                                                         ExportClassSchema (einfo.MappedType);
789                                                         break;
790                                         }
791                                 }
792                                 
793                                 return new XmlQualifiedName (lmap.GetSchemaArrayName (), schemaNs);
794                         }
795                         else
796                         {
797                                 if (IsMapExported (map)) return new XmlQualifiedName (map.XmlType, map.XmlTypeNamespace);
798                                 
799                                 SetMapExported (map);
800                                 XmlSchema schema = GetSchema (map.XmlTypeNamespace);
801                                 XmlSchemaComplexType stype = new XmlSchemaComplexType ();
802                                 stype.Name = map.ElementName;
803                                 schema.Items.Add (stype);
804
805                                 XmlSchemaParticle spart = GetSchemaArrayElement (schema, lmap.ItemInfo);
806                                 if (spart is XmlSchemaChoice)
807                                         stype.Particle = spart;
808                                 else
809                                 {
810                                         XmlSchemaSequence seq = new XmlSchemaSequence ();
811                                         seq.Items.Add (spart);
812                                         stype.Particle = seq;
813                                 }
814                                         
815                                 return new XmlQualifiedName (map.XmlType, map.XmlTypeNamespace);
816                         }
817                 }
818                 
819                 XmlDocument Document
820                 {
821                         get
822                         {
823                                 if (xmlDoc == null) xmlDoc = new XmlDocument ();
824                                 return xmlDoc;
825                         }
826                 }
827
828                 bool IsMapExported (XmlTypeMapping map)
829                 {
830                         if (exportedMaps.ContainsKey (GetMapKey(map))) return true;
831                         return false;
832                 }
833
834                 void SetMapExported (XmlTypeMapping map)
835                 {
836                         exportedMaps [GetMapKey(map)] = map;
837                 }
838
839                 bool IsElementExported (XmlTypeMapping map)
840                 {
841                         if (exportedElements.ContainsKey (GetMapKey(map))) return true;
842                         if (map.TypeData.Type == typeof(object)) return true;
843                         return false;
844                 }
845
846                 void SetElementExported (XmlTypeMapping map)
847                 {
848                         exportedElements [GetMapKey(map)] = map;
849                 }
850                 
851                 string GetMapKey (XmlTypeMapping map)
852                 {
853                         // Don't use type name for array types, since we can have different
854                         // classes that represent the same array type (for example
855                         // StringCollection and string[]).
856                         
857                         if (map.TypeData.IsListType)
858                                 return GetArrayKeyName (map.TypeData) + " " + map.XmlType + " " + map.XmlTypeNamespace;
859                         else
860                                 return map.TypeData.FullTypeName + " " + map.XmlType + " " + map.XmlTypeNamespace;
861                 }
862                 
863                 string GetArrayKeyName (TypeData td)
864                 {
865                         TypeData etd = td.ListItemTypeData;
866                         return "*arrayof*" + (etd.IsListType ? GetArrayKeyName (etd) : etd.FullTypeName);
867                 }
868                 
869                 void CompileSchemas ()
870                 {
871 //                      foreach (XmlSchema sc in schemas)
872 //                              sc.Compile (null);
873                 }
874
875                 XmlSchema GetSchema (string ns)
876                 {
877                         XmlSchema schema = schemas [ns];
878                         if (schema == null)
879                         {
880                                 schema = new XmlSchema ();
881                                 if (ns != null && ns.Length > 0)
882                                         schema.TargetNamespace = ns;
883                                 if (!encodedFormat)
884                                         schema.ElementFormDefault = XmlSchemaForm.Qualified;
885                                 schemas.Add (schema);
886                         }
887                         return schema;
888                 }
889
890                 #endregion // Methods
891
892                 private class XmlSchemaObjectContainer
893                 {
894                         private readonly XmlSchemaObject _xmlSchemaObject;
895
896                         public XmlSchemaObjectContainer (XmlSchema schema)
897                         {
898                                 _xmlSchemaObject = schema;
899                         }
900
901                         public XmlSchemaObjectContainer (XmlSchemaGroupBase group)
902                         {
903                                 _xmlSchemaObject = group;
904                         }
905
906                         public XmlSchemaObjectCollection Items {
907                                 get {
908                                         if (_xmlSchemaObject is XmlSchema) {
909                                                 return ((XmlSchema) _xmlSchemaObject).Items;
910                                         } else {
911                                                 return ((XmlSchemaGroupBase) _xmlSchemaObject).Items;
912                                         }
913                                 }
914                         }
915                 }
916         }
917 }