2006-02-21 Atsushi Enomoto <atsushi@ximian.com>
[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                 public void ExportMembersMapping (XmlMembersMapping xmlMembersMapping)
73                 {
74                         ExportMembersMapping (xmlMembersMapping, true);
75                 }
76
77 #if NET_2_0
78                 public
79 #else
80                 internal 
81 #endif
82                 void ExportMembersMapping (XmlMembersMapping xmlMembersMapping, bool exportEnclosingType)
83                 {
84                         ClassMap cmap = (ClassMap) xmlMembersMapping.ObjectMap;
85
86                         if (xmlMembersMapping.HasWrapperElement && exportEnclosingType)
87                         {
88                                 XmlSchema schema = GetSchema (xmlMembersMapping.Namespace);
89                                 XmlSchemaComplexType stype = new XmlSchemaComplexType ();
90         
91                                 XmlSchemaSequence particle;
92                                 XmlSchemaAnyAttribute anyAttribute;
93                                 ExportMembersMapSchema (schema, cmap, null, stype.Attributes, out particle, out anyAttribute);
94                                 stype.Particle = particle;
95                                 stype.AnyAttribute = anyAttribute;
96                                 
97                                 if (encodedFormat)
98                                 {
99                                         stype.Name = xmlMembersMapping.ElementName;
100                                         schema.Items.Add (stype);
101                                 }
102                                 else
103                                 {
104                                         XmlSchemaElement selem = new XmlSchemaElement ();
105                                         selem.Name = xmlMembersMapping.ElementName;
106                                         selem.SchemaType = stype;
107                                         schema.Items.Add (selem);
108                                 }
109                         }
110                         else
111                         {
112                                 ICollection members = cmap.ElementMembers;
113                                 if (members != null)
114                                 {
115                                         foreach (XmlTypeMapMemberElement member in members)
116                                         {
117                                                 if (member is XmlTypeMapMemberAnyElement && member.TypeData.IsListType)
118                                                 {
119                                                         XmlSchema mschema = GetSchema (xmlMembersMapping.Namespace);
120                                                         XmlSchemaParticle par = GetSchemaArrayElement (mschema, member.ElementInfo);
121                                                         if (par is XmlSchemaAny)
122                                                         {
123                                                                 XmlSchemaComplexType ct = FindComplexType (mschema.Items, "any");
124                                                                 if (ct != null) continue;
125                                                                 
126                                                                 ct = new XmlSchemaComplexType ();
127                                                                 ct.Name = "any";
128                                                                 ct.IsMixed = true;
129                                                                 XmlSchemaSequence seq = new XmlSchemaSequence ();
130                                                                 ct.Particle = seq;
131                                                                 seq.Items.Add (par);
132                                                                 mschema.Items.Add (ct);
133                                                                 continue;
134                                                         }
135                                                 }
136                                                 
137                                                 
138                                                 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) member.ElementInfo [0];
139                                                 XmlSchema schema;
140
141                                                 if (encodedFormat)
142                                                 {
143                                                         schema = GetSchema (xmlMembersMapping.Namespace);
144                                                         ImportNamespace (schema, XmlSerializer.EncodingNamespace);
145                                                 }
146                                                 else
147                                                         schema = GetSchema (einfo.Namespace);
148                                                 
149                                                 
150                                                 XmlSchemaElement exe = FindElement (schema.Items, einfo.ElementName);
151                                                 XmlSchemaElement elem;
152                                                 
153                                                 Type memType = member.GetType();
154                                                 if (member is XmlTypeMapMemberFlatList)
155                                                         throw new InvalidOperationException ("Unwrapped arrays not supported as parameters");
156                                                 else if (memType == typeof(XmlTypeMapMemberElement))
157                                                         elem = (XmlSchemaElement) GetSchemaElement (schema, einfo, member.DefaultValue, false);
158                                                 else
159                                                         elem = (XmlSchemaElement) GetSchemaElement (schema, einfo, false);
160                                                 
161                                                 // In encoded format, the schema elements are not needed
162                                                 if (!encodedFormat)
163                                                         schema.Items.Add (elem);
164                                                 
165                                                 if (exe != null)
166                                                 {
167                                                         if (exe.SchemaTypeName.Equals (elem.SchemaTypeName))
168                                                                 schema.Items.Remove (elem);
169                                                         else
170                                                         {
171                                                                 string s = "The XML element named '" + einfo.ElementName + "' ";
172                                                                 s += "from namespace '" + schema.TargetNamespace + "' references distinct types " + elem.SchemaTypeName.Name + " and " + exe.SchemaTypeName.Name + ". ";
173                                                                 s += "Use XML attributes to specify another XML name or namespace for the element or types.";
174                                                                 throw new InvalidOperationException (s);
175                                                         }
176                                                 }
177                                         }
178                                 }
179                         }
180                         
181                         CompileSchemas ();
182                 }
183
184                 [MonoTODO]
185                 public XmlQualifiedName ExportTypeMapping (XmlMembersMapping xmlMembersMapping)
186                 {
187                         throw new NotImplementedException ();
188                 }
189
190                 public void ExportTypeMapping (XmlTypeMapping xmlTypeMapping)
191                 {
192                         if (!xmlTypeMapping.IncludeInSchema) return;
193                         if (IsElementExported (xmlTypeMapping)) return;
194                         
195                         if (encodedFormat)
196                         {
197                                 ExportClassSchema (xmlTypeMapping);
198                                 XmlSchema schema = GetSchema (xmlTypeMapping.XmlTypeNamespace);
199                                 ImportNamespace (schema, XmlSerializer.EncodingNamespace);
200                         }
201                         else
202                         {
203                                 XmlSchema schema = GetSchema (xmlTypeMapping.Namespace);
204                                 XmlTypeMapElementInfo einfo = new XmlTypeMapElementInfo (null, xmlTypeMapping.TypeData);
205                                 einfo.Namespace = xmlTypeMapping.Namespace;
206                                 einfo.ElementName = xmlTypeMapping.ElementName;
207                                 if (xmlTypeMapping.TypeData.IsComplexType)
208                                         einfo.MappedType = xmlTypeMapping;
209                                 einfo.IsNullable = false;
210                                 schema.Items.Add (GetSchemaElement (schema, einfo, false));
211                                 SetElementExported (xmlTypeMapping);
212                         }
213                         
214                         CompileSchemas ();
215                 }
216
217                 void ExportXmlSerializableSchema (XmlSchema currentSchema, XmlSerializableMapping map)
218                 {
219                 if (IsMapExported (map)) return;
220                 SetMapExported (map);
221                 
222                 if (map.Schema == null) return;
223
224                         string targetNs = map.Schema.TargetNamespace;
225                 XmlSchema existingSchema = schemas [targetNs];
226                 if (existingSchema == null)
227                 {
228                                 schemas.Add (map.Schema);
229                                 ImportNamespace (currentSchema, targetNs);
230                 }
231                 else if (existingSchema != map.Schema)
232                 {
233                                 throw new InvalidOperationException("The namespace '" + targetNs +"' defined by the class '" + map.TypeFullName + "' is a duplicate.");
234                 }
235                 }
236
237                 void ExportClassSchema (XmlTypeMapping map)
238                 {
239                         if (IsMapExported (map)) return;
240                         SetMapExported (map);
241                         
242                         if (map.TypeData.Type == typeof(object))
243                         {
244                                 foreach (XmlTypeMapping dmap in map.DerivedTypes)
245                                         if (dmap.TypeData.SchemaType == SchemaTypes.Class) ExportClassSchema (dmap);
246                                 return;
247                         }
248
249                         XmlSchema schema = GetSchema (map.XmlTypeNamespace);
250                         XmlSchemaComplexType stype = new XmlSchemaComplexType ();
251                         stype.Name = map.XmlType;
252                         schema.Items.Add (stype);
253
254                         ClassMap cmap = (ClassMap)map.ObjectMap;
255
256                         if (cmap.HasSimpleContent)
257                         {
258                                 XmlSchemaSimpleContent simple = new XmlSchemaSimpleContent ();
259                                 stype.ContentModel = simple;
260                                 XmlSchemaSimpleContentExtension ext = new XmlSchemaSimpleContentExtension ();
261                                 simple.Content = ext;
262                                 XmlSchemaSequence particle;
263                                 XmlSchemaAnyAttribute anyAttribute;
264                                 ExportMembersMapSchema (schema, cmap, map.BaseMap, ext.Attributes, out particle, out anyAttribute);
265                                 ext.AnyAttribute = anyAttribute;
266                                 if (map.BaseMap == null)
267                                         ext.BaseTypeName = cmap.SimpleContentBaseType;
268                                 else {
269                                         ext.BaseTypeName = new XmlQualifiedName (map.BaseMap.XmlType, map.BaseMap.XmlTypeNamespace);
270                                         ImportNamespace (schema, map.BaseMap.XmlTypeNamespace);
271                                         ExportClassSchema (map.BaseMap);
272                                 }
273                         }
274                         else if (map.BaseMap != null && map.BaseMap.IncludeInSchema)
275                         {
276                                 XmlSchemaComplexContent cstype = new XmlSchemaComplexContent ();
277                                 XmlSchemaComplexContentExtension ext = new XmlSchemaComplexContentExtension ();
278                                 ext.BaseTypeName = new XmlQualifiedName (map.BaseMap.XmlType, map.BaseMap.XmlTypeNamespace);
279                                 cstype.Content = ext;
280                                 stype.ContentModel = cstype;
281
282                                 XmlSchemaSequence particle;
283                                 XmlSchemaAnyAttribute anyAttribute;
284                                 ExportMembersMapSchema (schema, cmap, map.BaseMap, ext.Attributes, out particle, out anyAttribute);
285                                 ext.Particle = particle;
286                                 ext.AnyAttribute = anyAttribute;
287                                 stype.IsMixed = HasMixedContent (map);
288                                 cstype.IsMixed = BaseHasMixedContent (map);
289
290                                 ImportNamespace (schema, map.BaseMap.XmlTypeNamespace);
291                                 ExportClassSchema (map.BaseMap);
292                         }
293                         else
294                         {
295                                 XmlSchemaSequence particle;
296                                 XmlSchemaAnyAttribute anyAttribute;
297                                 ExportMembersMapSchema (schema, cmap, map.BaseMap, stype.Attributes, out particle, out anyAttribute);
298                                 stype.Particle = particle;
299                                 stype.AnyAttribute = anyAttribute;
300                                 stype.IsMixed = cmap.XmlTextCollector != null;
301                         }
302                         
303                         foreach (XmlTypeMapping dmap in map.DerivedTypes)
304                                 if (dmap.TypeData.SchemaType == SchemaTypes.Class) ExportClassSchema (dmap);
305                 }
306                 
307                 bool BaseHasMixedContent (XmlTypeMapping map)
308                 {
309                         ClassMap cmap = (ClassMap)map.ObjectMap;
310                         return (cmap.XmlTextCollector != null && (map.BaseMap != null && DefinedInBaseMap (map.BaseMap, cmap.XmlTextCollector)));
311                 }
312
313                 bool HasMixedContent (XmlTypeMapping map)
314                 {
315                         ClassMap cmap = (ClassMap)map.ObjectMap;
316                         return (cmap.XmlTextCollector != null && (map.BaseMap == null || !DefinedInBaseMap (map.BaseMap, cmap.XmlTextCollector)));
317                 }
318
319                 void ExportMembersMapSchema (XmlSchema schema, ClassMap map, XmlTypeMapping baseMap, XmlSchemaObjectCollection outAttributes, out XmlSchemaSequence particle, out XmlSchemaAnyAttribute anyAttribute)
320                 {
321                         particle = null;
322                         XmlSchemaSequence seq = new XmlSchemaSequence ();
323
324                         ICollection members = map.ElementMembers;
325                         if (members != null && !map.HasSimpleContent)
326                         {
327                                 foreach (XmlTypeMapMemberElement member in members)
328                                 {
329                                         if (baseMap != null && DefinedInBaseMap (baseMap, member)) continue;
330
331                                         Type memType = member.GetType();
332                                         if (memType == typeof(XmlTypeMapMemberFlatList))
333                                         {
334                                                 XmlSchemaParticle part = GetSchemaArrayElement (schema, member.ElementInfo);
335                                                 if (part != null) seq.Items.Add (part);
336                                         }
337                                         else if (memType == typeof(XmlTypeMapMemberAnyElement))
338                                         {
339                                                 seq.Items.Add (GetSchemaArrayElement (schema, member.ElementInfo));
340                                         }
341                                         else if (memType == typeof(XmlTypeMapMemberElement))
342                                         {
343                                                 XmlSchemaParticle elem = GetSchemaElement (schema, (XmlTypeMapElementInfo) member.ElementInfo [0], member.DefaultValue, true);
344                                                 if (elem != null)
345                                                         seq.Items.Add (elem);
346                                         }
347                                         else
348                                         {
349                                                 seq.Items.Add (GetSchemaElement (schema, (XmlTypeMapElementInfo) member.ElementInfo [0], true));
350                                         }
351                                 }
352                         }
353
354                         if (seq.Items.Count > 0)
355                                 particle = seq;
356
357                         // Write attributes
358
359                         ICollection attributes = map.AttributeMembers;
360                         if (attributes != null)
361                         {
362                                 foreach (XmlTypeMapMemberAttribute attr in attributes) {
363                                         if (baseMap != null && DefinedInBaseMap (baseMap, attr)) continue;
364                                         outAttributes.Add (GetSchemaAttribute (schema, attr, true));
365                                 }
366                         }
367
368                         XmlTypeMapMember anyAttrMember = map.DefaultAnyAttributeMember;
369                         if (anyAttrMember != null)
370                                 anyAttribute = new XmlSchemaAnyAttribute ();
371                         else
372                                 anyAttribute = null;
373                 }
374                 
375                 XmlSchemaElement FindElement (XmlSchemaObjectCollection col, string name)
376                 {
377                         foreach (XmlSchemaObject ob in col)
378                         {
379                                 XmlSchemaElement elem = ob as XmlSchemaElement;
380                                 if (elem != null && elem.Name == name) return elem;
381                         }
382                         return null;
383                 }
384
385                 XmlSchemaComplexType FindComplexType (XmlSchemaObjectCollection col, string name)
386                 {
387                         foreach (XmlSchemaObject ob in col)
388                         {
389                                 XmlSchemaComplexType ctype = ob as XmlSchemaComplexType;
390                                 if (ctype != null && ctype.Name == name) return ctype;
391                         }
392                         return null;
393                 }
394
395                 XmlSchemaAttribute GetSchemaAttribute (XmlSchema currentSchema, XmlTypeMapMemberAttribute attinfo, bool isTypeMember)
396                 {
397                         XmlSchemaAttribute sat = new XmlSchemaAttribute ();
398                         if (attinfo.DefaultValue != System.DBNull.Value) sat.DefaultValue = XmlCustomFormatter.ToXmlString (attinfo.TypeData, attinfo.DefaultValue);
399
400                         ImportNamespace (currentSchema, attinfo.Namespace);
401
402                         XmlSchema memberSchema;
403                         if (attinfo.Namespace.Length == 0 && attinfo.Form != XmlSchemaForm.Qualified)
404                                 memberSchema = currentSchema;
405                         else
406                                 memberSchema = GetSchema (attinfo.Namespace);
407
408                         if (currentSchema == memberSchema || encodedFormat)
409                         {
410                                 sat.Name = attinfo.AttributeName;
411                                 if (isTypeMember) sat.Form = attinfo.Form;
412                                 if (attinfo.TypeData.SchemaType == SchemaTypes.Enum)
413                                 {
414                                         ImportNamespace (currentSchema, attinfo.DataTypeNamespace);
415                                         ExportEnumSchema (attinfo.MappedType);
416                                         sat.SchemaTypeName = new XmlQualifiedName (attinfo.TypeData.XmlType, attinfo.DataTypeNamespace);;
417                                 }
418                                 else if (attinfo.TypeData.SchemaType == SchemaTypes.Array && TypeTranslator.IsPrimitive (attinfo.TypeData.ListItemType))
419                                 {
420                                         sat.SchemaType = GetSchemaSimpleListType (attinfo.TypeData);
421                                 }
422                                 else
423                                         sat.SchemaTypeName = new XmlQualifiedName (attinfo.TypeData.XmlType, attinfo.DataTypeNamespace);;
424                         }
425                         else
426                         {
427                                 sat.RefName = new XmlQualifiedName (attinfo.AttributeName, attinfo.Namespace);
428                                 foreach (XmlSchemaObject ob in memberSchema.Items)
429                                         if (ob is XmlSchemaAttribute && ((XmlSchemaAttribute)ob).Name == attinfo.AttributeName)
430                                                 return sat;
431                                                 
432                                 memberSchema.Items.Add (GetSchemaAttribute (memberSchema, attinfo, false));
433                         }
434                         return sat;
435                 }
436
437                 XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, bool isTypeMember)
438                 {
439                         return GetSchemaElement (currentSchema, einfo, System.DBNull.Value, isTypeMember);
440                 }
441                 
442                 XmlSchemaParticle GetSchemaElement (XmlSchema currentSchema, XmlTypeMapElementInfo einfo, object defaultValue, bool isTypeMember)
443                 {
444                         if (einfo.IsTextElement) return null;
445
446                         if (einfo.IsUnnamedAnyElement)
447                         {
448                                 XmlSchemaAny any = new XmlSchemaAny ();
449                                 any.MinOccurs = 0;
450                                 any.MaxOccurs = 1;
451                                 return any;
452                         }
453                         
454                         XmlSchemaElement selem = new XmlSchemaElement ();
455
456                         if (isTypeMember)
457                         {
458                                 selem.MaxOccurs = 1;
459                                 selem.MinOccurs = einfo.IsNullable ? 1 : 0;
460                                 
461                                 if ((einfo.TypeData.IsValueType && einfo.Member != null && !einfo.Member.IsOptionalValueType) || encodedFormat) 
462                                         selem.MinOccurs = 1;
463                         }
464
465                         XmlSchema memberSchema = null;
466                         
467                         if (!encodedFormat)
468                         {
469                                 memberSchema = GetSchema (einfo.Namespace);
470                                 ImportNamespace (currentSchema, einfo.Namespace);
471                         }
472                         
473                         if (currentSchema == memberSchema || encodedFormat || !isTypeMember)
474                         {
475                                 if (isTypeMember) selem.IsNillable = einfo.IsNullable;
476                                 selem.Name = einfo.ElementName;
477
478                                 if (defaultValue != System.DBNull.Value)
479                                         selem.DefaultValue = XmlCustomFormatter.ToXmlString (einfo.TypeData, defaultValue);
480                                         
481                                 if (einfo.Form != XmlSchemaForm.Qualified)
482                                         selem.Form = einfo.Form;
483
484                                 switch (einfo.TypeData.SchemaType)
485                                 {
486                                         case SchemaTypes.XmlNode: 
487                                                 selem.SchemaType = GetSchemaXmlNodeType ();
488                                                 break;
489
490                                         case SchemaTypes.XmlSerializable:
491                                                 selem.SchemaType = GetSchemaXmlSerializableType (einfo.MappedType as XmlSerializableMapping);
492                                                 ExportXmlSerializableSchema (currentSchema, einfo.MappedType as XmlSerializableMapping);
493                                                 break;
494
495                                         case SchemaTypes.Enum:
496                                                 selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);
497                                                 ImportNamespace (currentSchema, einfo.MappedType.XmlTypeNamespace);
498                                                 ExportEnumSchema (einfo.MappedType);
499                                                 break;
500
501                                         case SchemaTypes.Array: 
502                                                 XmlQualifiedName atypeName = ExportArraySchema (einfo.MappedType, currentSchema.TargetNamespace); 
503                                                 selem.SchemaTypeName = atypeName;
504                                                 ImportNamespace (currentSchema, atypeName.Namespace);
505                                                 break;
506
507                                         case SchemaTypes.Class:
508                                                 if (einfo.MappedType.TypeData.Type != typeof(object)) {
509                                                         selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);
510                                                         ImportNamespace (currentSchema, einfo.MappedType.XmlTypeNamespace);
511                                                 }
512                                                 else if (encodedFormat)
513                                                         selem.SchemaTypeName = new XmlQualifiedName (einfo.MappedType.XmlType, einfo.MappedType.XmlTypeNamespace);
514                                                         
515                                                 ExportClassSchema (einfo.MappedType);
516                                                 break;
517
518                                         case SchemaTypes.Primitive:
519                                                 selem.SchemaTypeName = new XmlQualifiedName (einfo.TypeData.XmlType, einfo.DataTypeNamespace);;
520                                                 if (!einfo.TypeData.IsXsdType)
521                                                         ExportDerivedSchema (einfo.MappedType);
522                                                 break;
523                                 }
524                         }
525                         else
526                         {
527                                 selem.RefName = new XmlQualifiedName (einfo.ElementName, einfo.Namespace);
528                                 foreach (XmlSchemaObject ob in memberSchema.Items)
529                                         if (ob is XmlSchemaElement && ((XmlSchemaElement)ob).Name == einfo.ElementName)
530                                                 return selem;
531                                                 
532                                 memberSchema.Items.Add (GetSchemaElement (memberSchema, einfo, defaultValue, false));
533                         }
534                         return selem;
535                 }
536
537                 void ImportNamespace (XmlSchema schema, string ns)
538                 {
539                         if (ns == null || ns.Length == 0 ||
540                                 ns == schema.TargetNamespace || ns == XmlSchema.Namespace) return;
541
542                         foreach (XmlSchemaObject sob in schema.Includes)
543                                 if ((sob is XmlSchemaImport) && ((XmlSchemaImport)sob).Namespace == ns) return;
544
545                         XmlSchemaImport imp = new XmlSchemaImport ();
546                         imp.Namespace = ns;
547                         schema.Includes.Add (imp);
548                 }
549
550                 bool DefinedInBaseMap (XmlTypeMapping map, XmlTypeMapMember member)
551                 {
552                         if (((ClassMap)map.ObjectMap).FindMember (member.Name) != null)
553                                 return true;
554                         else if (map.BaseMap != null)
555                                 return DefinedInBaseMap (map.BaseMap, member);
556                         else
557                                 return false;
558                 }
559
560                 XmlSchemaType GetSchemaXmlNodeType ()
561                 {
562                         XmlSchemaComplexType stype = new XmlSchemaComplexType ();
563                         stype.IsMixed = true;
564                         XmlSchemaSequence seq = new XmlSchemaSequence ();
565                         seq.Items.Add (new XmlSchemaAny ());
566                         stype.Particle = seq;
567                         return stype;
568                 }
569
570                 XmlSchemaType GetSchemaXmlSerializableType (XmlSerializableMapping map)
571                 {
572                         XmlSchemaComplexType stype = new XmlSchemaComplexType ();
573                         XmlSchemaSequence seq = new XmlSchemaSequence ();
574                         if (map.Schema == null) {
575                                 XmlSchemaElement selem = new XmlSchemaElement ();
576                                 selem.RefName = new XmlQualifiedName ("schema",XmlSchema.Namespace);
577                                 seq.Items.Add (selem);
578                                 seq.Items.Add (new XmlSchemaAny ());
579                         } else {
580                                 XmlSchemaAny any = new XmlSchemaAny ();
581                                 any.Namespace = map.Schema.TargetNamespace;
582                                 seq.Items.Add (any);
583                         }
584                         stype.Particle = seq;
585                         return stype;
586                 }
587
588                 XmlSchemaSimpleType GetSchemaSimpleListType (TypeData typeData)
589                 {
590                         XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
591                         XmlSchemaSimpleTypeList list = new XmlSchemaSimpleTypeList ();
592                         TypeData itemTypeData = TypeTranslator.GetTypeData (typeData.ListItemType);
593                         list.ItemTypeName = new XmlQualifiedName (itemTypeData.XmlType, XmlSchema.Namespace);
594                         stype.Content = list;
595                         return stype;
596                 }
597
598                 XmlSchemaParticle GetSchemaArrayElement (XmlSchema currentSchema, XmlTypeMapElementInfoList infos)
599                 {
600                         int numInfos = infos.Count;
601                         if (numInfos > 0 && ((XmlTypeMapElementInfo)infos[0]).IsTextElement) numInfos--;
602                         if (numInfos == 0) return null;
603
604                         if (numInfos == 1)
605                         {
606                                 XmlSchemaParticle selem = GetSchemaElement (currentSchema, (XmlTypeMapElementInfo) infos[infos.Count-1], true);
607                                 selem.MinOccursString = "0";
608                                 selem.MaxOccursString = "unbounded";
609                                 return selem;
610                         }
611                         else
612                         {
613                                 XmlSchemaChoice schoice = new XmlSchemaChoice ();
614                                 schoice.MinOccursString = "0";
615                                 schoice.MaxOccursString = "unbounded";
616                                 foreach (XmlTypeMapElementInfo einfo in infos)
617                                 {
618                                         if (einfo.IsTextElement) continue;
619                                         schoice.Items.Add (GetSchemaElement (currentSchema, einfo, true));
620                                 }
621                                 return schoice;
622                         }
623                 }
624
625                 void ExportDerivedSchema(XmlTypeMapping map) {
626                         if (IsMapExported (map)) return;
627                         SetMapExported (map);
628
629                         XmlSchema schema = GetSchema (map.XmlTypeNamespace);
630                         XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
631                         stype.Name = map.ElementName;
632                         schema.Items.Add (stype);
633
634                         XmlSchemaSimpleTypeRestriction rest = new XmlSchemaSimpleTypeRestriction ();
635                         rest.BaseTypeName = new XmlQualifiedName (map.TypeData.MappedType.XmlType, XmlSchema.Namespace);
636                         XmlSchemaPatternFacet facet = map.TypeData.XmlSchemaPatternFacet;
637                         if (facet != null)
638                                 rest.Facets.Add(facet);
639                         stype.Content = rest;
640                 }
641
642                 void ExportEnumSchema (XmlTypeMapping map)
643                 {
644                         if (IsMapExported (map)) return;
645                         SetMapExported (map);
646
647                         XmlSchema schema = GetSchema (map.XmlTypeNamespace);
648                         XmlSchemaSimpleType stype = new XmlSchemaSimpleType ();
649                         stype.Name = map.ElementName;
650                         schema.Items.Add (stype);
651
652                         XmlSchemaSimpleTypeRestriction rest = new XmlSchemaSimpleTypeRestriction ();
653                         rest.BaseTypeName = new XmlQualifiedName ("string",XmlSchema.Namespace);
654                         EnumMap emap = (EnumMap) map.ObjectMap;
655
656                         foreach (EnumMap.EnumMapMember emem in emap.Members)
657                         {
658                                 XmlSchemaEnumerationFacet ef = new XmlSchemaEnumerationFacet ();
659                                 ef.Value = emem.XmlName;
660                                 rest.Facets.Add (ef);
661                         }
662                         stype.Content = rest;
663                 }
664
665                 XmlQualifiedName ExportArraySchema (XmlTypeMapping map, string defaultNamespace)
666                 {
667                         ListMap lmap = (ListMap) map.ObjectMap;
668
669                         if (encodedFormat)
670                         {
671                                 string name, ns, schemaNs;
672                                 lmap.GetArrayType (-1, out name, out ns);                               
673                                 if (ns == XmlSchema.Namespace) schemaNs = defaultNamespace;
674                                 else schemaNs = ns;
675
676                                 if (IsMapExported (map)) return new XmlQualifiedName (lmap.GetSchemaArrayName (), schemaNs);
677                                 SetMapExported (map);
678
679                                 XmlSchema schema = GetSchema (schemaNs);
680                                 XmlSchemaComplexType stype = new XmlSchemaComplexType ();
681                                 stype.Name = lmap.GetSchemaArrayName ();
682                                 schema.Items.Add (stype);
683                                 
684                                 XmlSchemaComplexContent content = new XmlSchemaComplexContent();
685                                 content.IsMixed = false;
686                                 stype.ContentModel = content;
687                                 
688                                 XmlSchemaComplexContentRestriction rest = new XmlSchemaComplexContentRestriction ();
689                                 content.Content = rest;
690                                 rest.BaseTypeName = new XmlQualifiedName ("Array", XmlSerializer.EncodingNamespace);
691                                 XmlSchemaAttribute at = new XmlSchemaAttribute ();
692                                 rest.Attributes.Add (at);
693                                 at.RefName = new XmlQualifiedName ("arrayType", XmlSerializer.EncodingNamespace);
694                                 
695                                 XmlAttribute arrayType = Document.CreateAttribute ("arrayType", XmlSerializer.WsdlNamespace);
696                                 arrayType.Value = ns + (ns != "" ? ":" : "") + name;
697                                 at.UnhandledAttributes = new XmlAttribute [] { arrayType };
698                                 ImportNamespace (schema, XmlSerializer.WsdlNamespace);
699                         
700                                 XmlTypeMapElementInfo einfo = (XmlTypeMapElementInfo) lmap.ItemInfo[0];
701                                 if (einfo.MappedType != null)
702                                 {
703                                         switch (einfo.TypeData.SchemaType)
704                                         {
705                                                 case SchemaTypes.Enum:
706                                                         ExportEnumSchema (einfo.MappedType);
707                                                         break;
708                                                 case SchemaTypes.Array: 
709                                                         ExportArraySchema (einfo.MappedType, schemaNs); 
710                                                         break;
711                                                 case SchemaTypes.Class:
712                                                         ExportClassSchema (einfo.MappedType);
713                                                         break;
714                                         }
715                                 }
716                                 
717                                 return new XmlQualifiedName (lmap.GetSchemaArrayName (), schemaNs);
718                         }
719                         else
720                         {
721                                 if (IsMapExported (map)) return new XmlQualifiedName (map.XmlType, map.XmlTypeNamespace);
722                                 
723                                 SetMapExported (map);
724                                 XmlSchema schema = GetSchema (map.XmlTypeNamespace);
725                                 XmlSchemaComplexType stype = new XmlSchemaComplexType ();
726                                 stype.Name = map.ElementName;
727                                 schema.Items.Add (stype);
728
729                                 XmlSchemaParticle spart = GetSchemaArrayElement (schema, lmap.ItemInfo);
730                                 if (spart is XmlSchemaChoice)
731                                         stype.Particle = spart;
732                                 else
733                                 {
734                                         XmlSchemaSequence seq = new XmlSchemaSequence ();
735                                         seq.Items.Add (spart);
736                                         stype.Particle = seq;
737                                 }
738                                         
739                                 return new XmlQualifiedName (map.XmlType, map.XmlTypeNamespace);
740                         }
741                 }
742                 
743                 XmlDocument Document
744                 {
745                         get
746                         {
747                                 if (xmlDoc == null) xmlDoc = new XmlDocument ();
748                                 return xmlDoc;
749                         }
750                 }
751
752                 bool IsMapExported (XmlTypeMapping map)
753                 {
754                         if (exportedMaps.ContainsKey (GetMapKey(map))) return true;
755                         return false;
756                 }
757
758                 void SetMapExported (XmlTypeMapping map)
759                 {
760                         exportedMaps [GetMapKey(map)] = map;
761                 }
762
763                 bool IsElementExported (XmlTypeMapping map)
764                 {
765                         if (exportedElements.ContainsKey (GetMapKey(map))) return true;
766                         if (map.TypeData.Type == typeof(object)) return true;
767                         return false;
768                 }
769
770                 void SetElementExported (XmlTypeMapping map)
771                 {
772                         exportedElements [GetMapKey(map)] = map;
773                 }
774                 
775                 string GetMapKey (XmlTypeMapping map)
776                 {
777                         // Don't use type name for array types, since we can have different
778                         // classes that represent the same array type (for example
779                         // StringCollection and string[]).
780                         
781                         if (map.TypeData.IsListType)
782                                 return GetArrayKeyName (map.TypeData) + " " + map.XmlType + " " + map.XmlTypeNamespace;
783                         else
784                                 return map.TypeData.FullTypeName + " " + map.XmlType + " " + map.XmlTypeNamespace;
785                 }
786                 
787                 string GetArrayKeyName (TypeData td)
788                 {
789                         TypeData etd = td.ListItemTypeData;
790                         return "*arrayof*" + (etd.IsListType ? GetArrayKeyName (etd) : etd.FullTypeName);
791                 }
792                 
793                 void CompileSchemas ()
794                 {
795 //                      foreach (XmlSchema sc in schemas)
796 //                              sc.Compile (null);
797                 }
798
799                 XmlSchema GetSchema (string ns)
800                 {
801                         XmlSchema schema = schemas [ns];
802                         if (schema == null)
803                         {
804                                 schema = new XmlSchema ();
805                                 schema.TargetNamespace = ns;
806                                 if (!encodedFormat)
807                                         schema.ElementFormDefault = XmlSchemaForm.Qualified;
808                                 schemas.Add (schema);
809                         }
810                         return schema;
811                 }
812
813                 #endregion // Methods
814         }
815 }