Merge pull request #496 from nicolas-raoul/unit-test-for-issue2907
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlReflectionImporter.cs
1 // 
2 // System.Xml.Serialization.XmlReflectionImporter 
3 //
4 // Author:
5 //   Tim Coleman (tim@timcoleman.com)
6 //   Erik LeBel (eriklebel@yahoo.ca)
7 //   Lluis Sanchez Gual (lluis@ximian.com)
8 //
9 // Copyright (C) Tim Coleman, 2002
10 // (C) 2003 Erik LeBel
11 //
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 //
32
33 using System.Collections;
34 using System.Collections.Generic;
35 using System.Globalization;
36 using System.Reflection;
37 using System.Xml.Schema;
38
39 namespace System.Xml.Serialization {
40         public class XmlReflectionImporter {
41
42                 string initialDefaultNamespace;
43                 XmlAttributeOverrides attributeOverrides;
44                 ArrayList includedTypes;
45                 ReflectionHelper helper = new ReflectionHelper();
46                 int arrayChoiceCount = 1;
47                 ArrayList relatedMaps = new ArrayList ();
48                 bool allowPrivateTypes = false;
49
50                 static readonly string errSimple = "Cannot serialize object of type '{0}'. Base " +
51                         "type '{1}' has simpleContent and can be only extended by adding XmlAttribute " +
52                         "elements. Please consider changing XmlText member of the base class to string array";
53
54                 static readonly string errSimple2 = "Cannot serialize object of type '{0}'. " +
55                         "Consider changing type of XmlText member '{1}' from '{2}' to string or string array";
56
57                 #region Constructors
58
59                 public XmlReflectionImporter ()
60                         : this (null, null)
61                 {
62                 }
63
64                 public XmlReflectionImporter (string defaultNamespace)
65                         : this (null, defaultNamespace)
66                 {
67                 }
68
69                 public XmlReflectionImporter (XmlAttributeOverrides attributeOverrides)
70                         : this (attributeOverrides, null)
71                 {
72                 }
73
74                 public XmlReflectionImporter (XmlAttributeOverrides attributeOverrides, string defaultNamespace)
75                 {
76                         if (defaultNamespace == null)
77                                 this.initialDefaultNamespace = String.Empty;
78                         else
79                                 this.initialDefaultNamespace = defaultNamespace;
80
81                         if (attributeOverrides == null)
82                                 this.attributeOverrides = new XmlAttributeOverrides();
83                         else
84                                 this.attributeOverrides = attributeOverrides;
85                 }
86
87 /*              void Reset ()
88                 {
89                         helper = new ReflectionHelper();
90                         arrayChoiceCount = 1;
91                 }
92 */
93                 
94                 internal bool AllowPrivateTypes
95                 {
96                         get { return allowPrivateTypes; }
97                         set { allowPrivateTypes = value; }
98                 }
99
100                 #endregion // Constructors
101
102                 #region Methods
103
104                 public XmlMembersMapping ImportMembersMapping (string elementName,
105                         string ns,
106                         XmlReflectionMember [] members,
107                         bool hasWrapperElement)
108                 {
109                         return ImportMembersMapping (elementName, ns, members, hasWrapperElement, true);
110                 }
111
112 #if NET_2_0
113                 [MonoTODO]
114                 public
115 #endif
116                 XmlMembersMapping ImportMembersMapping (string elementName, 
117                         string ns, 
118                         XmlReflectionMember[] members, 
119                         bool hasWrapperElement, 
120                         bool rpc)
121                 {
122                         return ImportMembersMapping (elementName, ns, members, hasWrapperElement, rpc, true);
123                 }
124
125 #if NET_2_0
126                 [MonoTODO]
127                 public
128 #endif
129                 XmlMembersMapping ImportMembersMapping (string elementName, 
130                         string ns, 
131                         XmlReflectionMember[] members, 
132                         bool hasWrapperElement, 
133                         bool rpc, 
134                         bool openModel)
135                 {
136                         return ImportMembersMapping (elementName, ns, members, hasWrapperElement, rpc, openModel, XmlMappingAccess.Read | XmlMappingAccess.Write);
137                 }
138
139 #if NET_2_0
140                 [MonoTODO] // FIXME: handle writeAccessors, validate, and mapping access
141                 public
142 #endif
143                 XmlMembersMapping ImportMembersMapping (string elementName, 
144                         string ns, 
145                         XmlReflectionMember[] members, 
146                         bool hasWrapperElement, 
147                         bool rpc, 
148                         bool openModel,
149                         XmlMappingAccess access)
150                 {
151 //                      Reset ();       Disabled. See ChangeLog
152
153                         ArrayList mapping = new ArrayList ();
154                         for (int n=0; n<members.Length; n++)
155                         {
156                                 XmlTypeMapMember mapMem = CreateMapMember (null, members[n], ns);
157                                 mapMem.GlobalIndex = n;
158                                 mapMem.CheckOptionalValueType (members);
159                                 mapping.Add (new XmlMemberMapping (members[n].MemberName, ns, mapMem, false));
160                         }
161                         elementName = XmlConvert.EncodeLocalName (elementName);
162                         XmlMembersMapping mps = new XmlMembersMapping (elementName, ns, hasWrapperElement, false, (XmlMemberMapping[])mapping.ToArray (typeof(XmlMemberMapping)));
163                         mps.RelatedMaps = relatedMaps;
164                         mps.Format = SerializationFormat.Literal;
165                         Type[] extraTypes = includedTypes != null ? (Type[])includedTypes.ToArray(typeof(Type)) : null;
166 #if !NET_2_1
167                         mps.Source = new MembersSerializationSource (elementName, hasWrapperElement, members, false, true, ns, extraTypes);
168                         if (allowPrivateTypes) mps.Source.CanBeGenerated = false;
169 #endif
170                         return mps;
171                 }
172
173                 public XmlTypeMapping ImportTypeMapping (Type type)
174                 {
175                         return ImportTypeMapping (type, null, null);
176                 }
177
178                 public XmlTypeMapping ImportTypeMapping (Type type, string defaultNamespace)
179                 {
180                         return ImportTypeMapping (type, null, defaultNamespace);
181                 }
182
183                 public XmlTypeMapping ImportTypeMapping (Type type, XmlRootAttribute root)
184                 {
185                         return ImportTypeMapping (type, root, null);
186                 }
187
188                 public XmlTypeMapping ImportTypeMapping (Type type, XmlRootAttribute root, string defaultNamespace)
189                 {
190                         if (type == null)
191                                 throw new ArgumentNullException ("type");
192
193                         if (type == typeof (void))
194                                 throw new NotSupportedException ("The type " + type.FullName + " may not be serialized.");
195
196                         return ImportTypeMapping (TypeTranslator.GetTypeData (type), root, 
197                                 defaultNamespace);
198                 }
199
200                 internal XmlTypeMapping ImportTypeMapping (TypeData typeData, string defaultNamespace)
201                 {
202                         return ImportTypeMapping (typeData, (XmlRootAttribute) null, 
203                                 defaultNamespace);
204                 }
205
206                 private XmlTypeMapping ImportTypeMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
207                 {
208                         if (typeData == null)
209                                 throw new ArgumentNullException ("typeData");
210
211                         if (typeData.Type == null)
212                                 throw new ArgumentException ("Specified TypeData instance does not have Type set.");
213
214                         if (defaultNamespace == null) defaultNamespace = initialDefaultNamespace;
215                         if (defaultNamespace == null) defaultNamespace = string.Empty;
216
217                         try {
218                                 XmlTypeMapping map;
219
220                                 switch (typeData.SchemaType) {
221                                         case SchemaTypes.Class: map = ImportClassMapping (typeData, root, defaultNamespace); break;
222                                         case SchemaTypes.Array: map = ImportListMapping (typeData, root, defaultNamespace, null, 0); break;
223                                         case SchemaTypes.XmlNode: map = ImportXmlNodeMapping (typeData, root, defaultNamespace); break;
224                                         case SchemaTypes.Primitive: map = ImportPrimitiveMapping (typeData, root, defaultNamespace); break;
225                                         case SchemaTypes.Enum: map = ImportEnumMapping (typeData, root, defaultNamespace); break;
226                                         case SchemaTypes.XmlSerializable: map = ImportXmlSerializableMapping (typeData, root, defaultNamespace); break;
227                                         default: throw new NotSupportedException ("Type " + typeData.Type.FullName + " not supported for XML stialization");
228                                 }
229
230 #if NET_2_0
231                                 // bug #372780
232                                 map.SetKey (typeData.Type.ToString ());
233 #endif
234                                 map.RelatedMaps = relatedMaps;
235                                 map.Format = SerializationFormat.Literal;
236                                 Type[] extraTypes = includedTypes != null ? (Type[]) includedTypes.ToArray (typeof (Type)) : null;
237 #if !NET_2_1
238                                 map.Source = new XmlTypeSerializationSource (typeData.Type, root, attributeOverrides, defaultNamespace, extraTypes);
239                                 if (allowPrivateTypes) map.Source.CanBeGenerated = false;
240 #endif
241                                 return map;
242                         } catch (InvalidOperationException ex) {
243                                 throw new InvalidOperationException (string.Format (CultureInfo.InvariantCulture,
244                                         "There was an error reflecting type '{0}'.", typeData.Type.FullName), ex);
245                         }
246                 }
247
248                 XmlTypeMapping CreateTypeMapping (TypeData typeData, XmlRootAttribute root, string defaultXmlType, string defaultNamespace)
249                 {
250                         bool hasTypeNamespace = !string.IsNullOrEmpty (defaultNamespace);
251                         string rootNamespace = null;
252                         string typeNamespace = null;
253                         string elementName;
254                         bool includeInSchema = true;
255                         XmlAttributes atts = null;
256                         bool nullable = CanBeNull (typeData);
257
258                         if (defaultXmlType == null) defaultXmlType = typeData.XmlType;
259
260                         if (!typeData.IsListType)
261                         {
262                                 if (attributeOverrides != null) 
263                                         atts = attributeOverrides[typeData.Type];
264
265                                 if (atts != null && typeData.SchemaType == SchemaTypes.Primitive)
266                                         throw new InvalidOperationException ("XmlRoot and XmlType attributes may not be specified for the type " + typeData.FullTypeName);
267                         }
268
269                         if (atts == null) 
270                                 atts = new XmlAttributes (typeData.Type);
271
272                         if (atts.XmlRoot != null && root == null)
273                                 root = atts.XmlRoot;
274
275                         if (atts.XmlType != null)
276                         {
277                                 if (atts.XmlType.Namespace != null) {
278                                         typeNamespace = atts.XmlType.Namespace;
279                                         hasTypeNamespace = true;
280                                 }
281
282                                 if (atts.XmlType.TypeName != null && atts.XmlType.TypeName != string.Empty)
283                                         defaultXmlType = XmlConvert.EncodeLocalName (atts.XmlType.TypeName);
284                                         
285                                 includeInSchema = atts.XmlType.IncludeInSchema;
286                         }
287
288                         elementName = defaultXmlType;
289
290                         if (root != null)
291                         {
292                                 if (root.ElementName.Length != 0)
293                                         elementName = XmlConvert.EncodeLocalName(root.ElementName);
294                                 if (root.Namespace != null) {
295                                         rootNamespace = root.Namespace;
296                                         hasTypeNamespace = true;
297                                 }
298                                 nullable = root.IsNullable;
299                         }
300
301                         rootNamespace = rootNamespace ?? defaultNamespace ?? string.Empty;
302                         typeNamespace = typeNamespace ?? rootNamespace;
303                         
304                         XmlTypeMapping map;
305                         switch (typeData.SchemaType) {
306                                 case SchemaTypes.XmlSerializable:
307                                         map = new XmlSerializableMapping (root, elementName, rootNamespace, typeData, defaultXmlType, typeNamespace);
308                                         break;
309                                 case SchemaTypes.Primitive:
310                                         if (!typeData.IsXsdType)
311                                                 map = new XmlTypeMapping (elementName, rootNamespace, 
312                                                         typeData, defaultXmlType, XmlSerializer.WsdlTypesNamespace);
313                                         else
314                                                 map = new XmlTypeMapping (elementName, rootNamespace, 
315                                                         typeData, defaultXmlType, typeNamespace);
316                                         break;
317                                 default:
318                                         map = new XmlTypeMapping (elementName, rootNamespace, typeData, defaultXmlType, hasTypeNamespace ? typeNamespace : null);
319                                         break;
320                         }
321
322                         map.IncludeInSchema = includeInSchema;
323                         map.IsNullable = nullable;
324                         relatedMaps.Add (map);
325                         
326                         return map;
327                 }
328
329                 XmlTypeMapping ImportClassMapping (Type type, XmlRootAttribute root, string defaultNamespace)
330                 {
331                         TypeData typeData = TypeTranslator.GetTypeData (type);
332                         return ImportClassMapping (typeData, root, defaultNamespace);
333                 }
334
335                 XmlTypeMapping ImportClassMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
336                 {
337                         Type type = typeData.Type;
338
339                         XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
340                         if (map != null) return map;
341
342                         if (!allowPrivateTypes)
343                                 ReflectionHelper.CheckSerializableType (type, false);
344                         
345                         map = CreateTypeMapping (typeData, root, null, defaultNamespace);
346                         helper.RegisterClrType (map, type, map.XmlTypeNamespace);
347                         helper.RegisterSchemaType (map, map.XmlType, map.XmlTypeNamespace);
348
349                         // Import members
350
351                         ClassMap classMap = new ClassMap ();
352                         map.ObjectMap = classMap;
353
354                         var members = GetReflectionMembers (type);
355                         bool? isOrderExplicit = null;
356                         foreach (XmlReflectionMember rmember in members)
357                         {
358                                 int? order = rmember.XmlAttributes.Order;
359                                 if (isOrderExplicit == null)
360                                 {
361                                         if (order != null)
362                                                 isOrderExplicit = (int) order >= 0;
363                                 }
364                                 else if (order != null && isOrderExplicit != ((int) order >= 0))
365                                         throw new InvalidOperationException ("Inconsistent XML sequence was detected. If there are XmlElement/XmlArray/XmlAnyElement attributes with explicit Order, then every other member must have an explicit order too.");
366                         }
367                         if (isOrderExplicit == true)
368                                 members.Sort ((m1, m2) => (int) m1.XmlAttributes.SortableOrder - (int) m2.XmlAttributes.SortableOrder);
369
370                         foreach (XmlReflectionMember rmember in members)
371                         {
372                                 string ns = map.XmlTypeNamespace;
373                                 if (rmember.XmlAttributes.XmlIgnore) continue;
374                                 if (rmember.DeclaringType != null && rmember.DeclaringType != type) {
375                                         XmlTypeMapping bmap = ImportClassMapping (rmember.DeclaringType, root, defaultNamespace);
376                                         if (bmap.HasXmlTypeNamespace)
377                                                 ns = bmap.XmlTypeNamespace;
378                                 }
379
380                                 try {
381                                         XmlTypeMapMember mem = CreateMapMember (type, rmember, ns);
382                                         mem.CheckOptionalValueType (type);
383                                         classMap.AddMember (mem);
384                                 } catch (Exception ex) {
385                                         throw new InvalidOperationException (string.Format (
386                                                 CultureInfo.InvariantCulture, "There was an error" +
387                                                 " reflecting field '{0}'.", rmember.MemberName), ex);
388                                 }
389                         }
390
391                         // Import extra classes
392
393                         if (type == typeof (object) && includedTypes != null)
394                         {
395                                 foreach (Type intype in includedTypes)
396                                         map.DerivedTypes.Add (ImportTypeMapping (intype, defaultNamespace));
397                         }
398
399                         // Register inheritance relations
400
401                         if (type.BaseType != null)
402                         {
403                                 XmlTypeMapping bmap = ImportClassMapping (type.BaseType, root, defaultNamespace);
404                                 ClassMap cbmap = bmap.ObjectMap as ClassMap;
405                                 
406                                 if (type.BaseType != typeof (object)) {
407                                         map.BaseMap = bmap;
408                                         if (!cbmap.HasSimpleContent)
409                                                 classMap.SetCanBeSimpleType (false);
410                                 }
411                                 
412                                 // At this point, derived classes of this map must be already registered
413                                 
414                                 RegisterDerivedMap (bmap, map);
415                                 
416                                 if (cbmap.HasSimpleContent && classMap.ElementMembers != null && classMap.ElementMembers.Count != 1)
417                                         throw new InvalidOperationException (String.Format (errSimple, map.TypeData.TypeName, map.BaseMap.TypeData.TypeName));
418                         }
419                         
420                         ImportIncludedTypes (type, defaultNamespace);
421                         
422                         if (classMap.XmlTextCollector != null && !classMap.HasSimpleContent)
423                         {
424                                 XmlTypeMapMember mem = classMap.XmlTextCollector;
425                                 if (mem.TypeData.Type != typeof(string) && 
426                                    mem.TypeData.Type != typeof(string[]) && 
427 #if !MOONLIGHT
428                                    mem.TypeData.Type != typeof(XmlNode[]) && 
429 #endif
430                                    mem.TypeData.Type != typeof(object[]))
431                                    
432                                         throw new InvalidOperationException (String.Format (errSimple2, map.TypeData.TypeName, mem.Name, mem.TypeData.TypeName));
433                         }
434                         
435                         return map;
436                 }
437                 
438                 void RegisterDerivedMap (XmlTypeMapping map, XmlTypeMapping derivedMap)
439                 {
440                         map.DerivedTypes.Add (derivedMap);
441                         map.DerivedTypes.AddRange (derivedMap.DerivedTypes);
442                         
443                         if (map.BaseMap != null)
444                                 RegisterDerivedMap (map.BaseMap, derivedMap);
445                         else {
446                                 XmlTypeMapping obmap = ImportTypeMapping (typeof(object));
447                                 if (obmap != map)
448                                         obmap.DerivedTypes.Add (derivedMap);
449                         }
450                 }
451
452                 string GetTypeNamespace (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
453                 {
454                         string typeNamespace = null;
455                         
456                         XmlAttributes atts = null;
457                         if (!typeData.IsListType)
458                         {
459                                 if (attributeOverrides != null)
460                                         atts = attributeOverrides[typeData.Type];
461                         }
462
463                         if (atts == null)
464                                 atts = new XmlAttributes (typeData.Type);
465
466                         if (atts.XmlType != null)
467                         {
468                                 if (atts.XmlType.Namespace != null && atts.XmlType.Namespace.Length != 0 && typeData.SchemaType != SchemaTypes.Enum)
469                                         typeNamespace = atts.XmlType.Namespace;
470                         }
471
472                         if (typeNamespace != null && typeNamespace.Length != 0) return typeNamespace;
473                         
474                         if (atts.XmlRoot != null && root == null)
475                                 root = atts.XmlRoot;
476
477                         if (root != null)
478                         {
479                                 if (root.Namespace != null && root.Namespace.Length != 0)
480                                         return root.Namespace;
481                         }
482
483                         if (defaultNamespace == null) return "";
484                         else return defaultNamespace;
485                 }
486
487                 XmlTypeMapping ImportListMapping (Type type, XmlRootAttribute root, string defaultNamespace, XmlAttributes atts, int nestingLevel)
488                 {
489                         TypeData typeData = TypeTranslator.GetTypeData (type);
490                         return ImportListMapping (typeData, root, defaultNamespace, atts, nestingLevel);
491                 }
492
493                 XmlTypeMapping ImportListMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace, XmlAttributes atts, int nestingLevel)
494                 {
495                         Type type = typeData.Type;
496                         ListMap obmap = new ListMap ();
497
498                         if (!allowPrivateTypes)
499                                 ReflectionHelper.CheckSerializableType (type, true);
500                         
501                         if (atts == null) atts = new XmlAttributes();
502                         Type itemType = typeData.ListItemType;
503
504                         // warning: byte[][] should not be considered multiarray
505                         bool isMultiArray = (type.IsArray && (TypeTranslator.GetTypeData(itemType).SchemaType == SchemaTypes.Array) && itemType.IsArray);
506
507                         XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
508
509                         foreach (XmlArrayItemAttribute att in atts.XmlArrayItems)
510                         {
511                                 if (att.Namespace != null && att.Form == XmlSchemaForm.Unqualified)
512                                         throw new InvalidOperationException ("XmlArrayItemAttribute.Form must not be Unqualified when it has an explicit Namespace value.");
513                                 if (att.NestingLevel != nestingLevel) continue;
514                                 Type elemType = (att.Type != null) ? att.Type : itemType;
515                                 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, TypeTranslator.GetTypeData(elemType, att.DataType));
516                                 elem.Namespace = att.Namespace != null ? att.Namespace : defaultNamespace;
517                                 if (elem.Namespace == null) elem.Namespace = "";
518                                 elem.Form = att.Form;
519                                 if (att.Form == XmlSchemaForm.Unqualified)
520                                         elem.Namespace = string.Empty;
521                                 elem.IsNullable = att.IsNullable && CanBeNull (elem.TypeData);
522                                 elem.NestingLevel = att.NestingLevel;
523
524                                 if (isMultiArray) {
525                                         elem.MappedType = ImportListMapping (elemType, null, elem.Namespace, atts, nestingLevel + 1);
526                                 } else if (elem.TypeData.IsComplexType) {
527                                         elem.MappedType = ImportTypeMapping (elemType, null, elem.Namespace);
528                                 }
529
530                                 if (att.ElementName.Length != 0) {
531                                         elem.ElementName = XmlConvert.EncodeLocalName (att.ElementName);
532                                 } else if (elem.MappedType != null) {
533                                         elem.ElementName = elem.MappedType.ElementName;
534                                 } else {
535                                         elem.ElementName = TypeTranslator.GetTypeData (elemType).XmlType;
536                                 }
537
538                                 list.Add (elem);
539                         }
540
541                         if (list.Count == 0)
542                         {
543                                 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (null, TypeTranslator.GetTypeData (itemType));
544                                 if (isMultiArray)
545                                         elem.MappedType = ImportListMapping (itemType, null, defaultNamespace, atts, nestingLevel + 1);
546                                 else if (elem.TypeData.IsComplexType)
547                                         elem.MappedType = ImportTypeMapping (itemType, null, defaultNamespace);
548
549                                 if (elem.MappedType != null) {
550                                         elem.ElementName = elem.MappedType.XmlType;
551                                 } else {
552                                         elem.ElementName = TypeTranslator.GetTypeData (itemType).XmlType;
553                                 }
554
555                                 elem.Namespace = (defaultNamespace != null) ? defaultNamespace : "";
556                                 elem.IsNullable = CanBeNull (elem.TypeData);
557                                 list.Add (elem);
558                         }
559
560                         obmap.ItemInfo = list;
561
562                         // If there can be different element names (types) in the array, then its name cannot
563                         // be "ArrayOfXXX" it must be something like ArrayOfChoiceNNN
564
565                         string baseName;
566                         if (list.Count > 1) {
567                                 baseName = "ArrayOfChoice" + (arrayChoiceCount++);
568                         } else {
569                                 XmlTypeMapElementInfo elem = ((XmlTypeMapElementInfo) list[0]);
570                                 if (elem.MappedType != null) {
571                                         baseName = TypeTranslator.GetArrayName (elem.MappedType.XmlType);
572                                 } else {
573                                         baseName = TypeTranslator.GetArrayName (elem.ElementName);
574                                 }
575                         }
576
577                         // Avoid name colisions
578
579                         int nameCount = 1;
580                         string name = baseName;
581
582                         do {
583                                 XmlTypeMapping foundMap = helper.GetRegisteredSchemaType (name, defaultNamespace);
584                                 if (foundMap == null) nameCount = -1;
585                                 else if (obmap.Equals (foundMap.ObjectMap) && typeData.Type == foundMap.TypeData.Type) return foundMap;
586                                 else name = baseName + (nameCount++);
587                         }
588                         while (nameCount != -1);
589
590                         XmlTypeMapping map = CreateTypeMapping (typeData, root, name, defaultNamespace);
591                         map.ObjectMap = obmap;
592                         
593                         // Register any of the including types as a derived class of object
594                         XmlIncludeAttribute[] includes = (XmlIncludeAttribute[])type.GetCustomAttributes (typeof (XmlIncludeAttribute), false);
595                         
596                         XmlTypeMapping objectMapping = ImportTypeMapping (typeof(object));
597                         for (int i = 0; i < includes.Length; i++)
598                         {
599                                 Type includedType = includes[i].Type;
600                                 objectMapping.DerivedTypes.Add(ImportTypeMapping (includedType, null, defaultNamespace));
601                         }
602                         
603                         // Register this map as a derived class of object
604
605                         helper.RegisterSchemaType (map, name, defaultNamespace);
606                         ImportTypeMapping (typeof(object)).DerivedTypes.Add (map);
607
608                         return map;
609                 }
610
611                 XmlTypeMapping ImportXmlNodeMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
612                 {
613                         Type type = typeData.Type;
614                         XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
615                         if (map != null) return map;
616
617                         map = CreateTypeMapping (typeData, root, null, defaultNamespace);
618                         helper.RegisterClrType (map, type, map.XmlTypeNamespace);
619                         
620                         if (type.BaseType != null)
621                         {
622                                 XmlTypeMapping bmap = ImportTypeMapping (type.BaseType, root, defaultNamespace);
623                                 if (type.BaseType != typeof (object))
624                                         map.BaseMap = bmap;
625                                 
626                                 RegisterDerivedMap (bmap, map);
627                         }
628
629                         return map;
630                 }
631
632                 XmlTypeMapping ImportPrimitiveMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
633                 {
634                         Type type = typeData.Type;
635                         XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
636                         if (map != null) return map;
637                         map = CreateTypeMapping (typeData, root, null, defaultNamespace);
638                         helper.RegisterClrType (map, type, map.XmlTypeNamespace);
639                         return map;
640                 }
641 #if MOONLIGHT
642                 // Enum.GetNames is not available in SL API
643                 public static System.Collections.Generic.IEnumerable<string> GetEnumNames (Type type)
644                 {
645                         System.Collections.Generic.List<string> names = new System.Collections.Generic.List<string> ();
646                         foreach (FieldInfo fi in type.GetFields (BindingFlags.Static | BindingFlags.Public))
647                                 names.Add (fi.Name);
648                         return names;
649                 }
650 #endif
651                 XmlTypeMapping ImportEnumMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
652                 {
653                         Type type = typeData.Type;
654                         XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
655                         if (map != null) return map;
656                         
657                         if (!allowPrivateTypes)
658                                 ReflectionHelper.CheckSerializableType (type, false);
659                                 
660                         map = CreateTypeMapping (typeData, root, null, defaultNamespace);
661                         map.IsNullable = false;
662                         helper.RegisterClrType (map, type, map.XmlTypeNamespace);
663
664                         ArrayList members = new ArrayList();
665 #if MOONLIGHT
666                         foreach (string name in GetEnumNames (type)) {
667 #else
668                         string [] names = Enum.GetNames (type);
669                         foreach (string name in names) {
670 #endif
671                                 FieldInfo field = type.GetField (name);
672                                 string xmlName = null;
673                                 if (field.IsDefined(typeof(XmlIgnoreAttribute), false))
674                                         continue;
675                                 object[] atts = field.GetCustomAttributes (typeof(XmlEnumAttribute), false);
676                                 if (atts.Length > 0) xmlName = ((XmlEnumAttribute)atts[0]).Name;
677                                 if (xmlName == null) xmlName = name;
678                                 long value = ((IConvertible) field.GetValue (null)).ToInt64 (CultureInfo.InvariantCulture);
679                                 members.Add (new EnumMap.EnumMapMember (xmlName, name, value));
680                         }
681
682                         bool isFlags = type.IsDefined (typeof (FlagsAttribute), false);
683                         map.ObjectMap = new EnumMap ((EnumMap.EnumMapMember[])members.ToArray (typeof(EnumMap.EnumMapMember)), isFlags);
684                         ImportTypeMapping (typeof(object)).DerivedTypes.Add (map);
685                         return map;
686                 }
687
688                 XmlTypeMapping ImportXmlSerializableMapping (TypeData typeData, XmlRootAttribute root, string defaultNamespace)
689                 {
690                         Type type = typeData.Type;
691                         XmlTypeMapping map = helper.GetRegisteredClrType (type, GetTypeNamespace (typeData, root, defaultNamespace));
692                         if (map != null) return map;
693                         
694                         if (!allowPrivateTypes)
695                                 ReflectionHelper.CheckSerializableType (type, false);
696                                 
697                         map = CreateTypeMapping (typeData, root, null, defaultNamespace);
698                         helper.RegisterClrType (map, type, map.XmlTypeNamespace);
699                         return map;
700                 }
701
702                 void ImportIncludedTypes (Type type, string defaultNamespace)
703                 {
704                         XmlIncludeAttribute[] includes = (XmlIncludeAttribute[])type.GetCustomAttributes (typeof (XmlIncludeAttribute), false);
705                         for (int n=0; n<includes.Length; n++)
706                         {
707                                 Type includedType = includes[n].Type;
708                                 ImportTypeMapping (includedType, null, defaultNamespace);
709                         }
710                 }
711
712                 List<XmlReflectionMember> GetReflectionMembers (Type type)
713                 {
714                         // First we want to find the inheritance hierarchy in reverse order.
715                         Type currentType = type;
716                         ArrayList typeList = new ArrayList();
717                         typeList.Add(currentType);
718                         while (currentType != typeof(object))
719                         {
720                                 currentType = currentType.BaseType; // Read the base type.
721                                 typeList.Insert(0, currentType); // Insert at 0 to reverse the order.
722                         }
723
724                         // Read all Fields via reflection.
725                         ArrayList fieldList = new ArrayList();
726                         FieldInfo[] tfields = type.GetFields (BindingFlags.Instance | BindingFlags.Public);
727 #if TARGET_JVM
728                         // This statement ensures fields are ordered starting from the base type.
729                         for (int ti=0; ti<typeList.Count; ti++) {
730                                 for (int i=0; i<tfields.Length; i++) {
731                                         FieldInfo field = tfields[i];
732                                         if (field.DeclaringType == typeList[ti])
733                                                 fieldList.Add (field);
734                                 }
735                         }
736 #else
737                         currentType = null;
738                         int currentIndex = 0;
739                         foreach (FieldInfo field in tfields)
740                         {
741                                 // This statement ensures fields are ordered starting from the base type.
742                                 if (currentType != field.DeclaringType)
743                                 {
744                                         currentType = field.DeclaringType;
745                                         currentIndex=0;
746                                 }
747                                 fieldList.Insert(currentIndex++, field);
748                         }
749 #endif
750                         // Read all Properties via reflection.
751                         ArrayList propList = new ArrayList();
752                         PropertyInfo[] tprops = type.GetProperties (BindingFlags.Instance | BindingFlags.Public);
753 #if TARGET_JVM
754                         // This statement ensures properties are ordered starting from the base type.
755                         for (int ti=0; ti<typeList.Count; ti++) {
756                                 for (int i=0; i<tprops.Length; i++) {
757                                         PropertyInfo prop = tprops[i];
758                                         if (!prop.CanRead) continue;
759                                         if (prop.GetIndexParameters().Length > 0) continue;
760                                         if (prop.DeclaringType == typeList[ti])
761                                                 propList.Add (prop);
762                                 }
763                         }
764 #else
765                         currentType = null;
766                         currentIndex = 0;
767                         foreach (PropertyInfo prop in tprops)
768                         {
769                                 // This statement ensures properties are ordered starting from the base type.
770                                 if (currentType != prop.DeclaringType)
771                                 {
772                                         currentType = prop.DeclaringType;
773                                         currentIndex = 0;
774                                 }
775                                 if (!prop.CanRead) continue;
776                                 if (prop.GetIndexParameters().Length > 0) continue;
777                                 propList.Insert(currentIndex++, prop);
778                         }
779 #endif
780                         var members = new List<XmlReflectionMember>();
781                         int fieldIndex=0;
782                         int propIndex=0;
783                         // We now step through the type hierarchy from the base (object) through
784                         // to the supplied class, as each step outputting all Fields, and then
785                         // all Properties.  This is the exact same ordering as .NET 1.0/1.1.
786                         foreach (Type t in typeList)
787                         {
788                                 // Add any fields matching the current DeclaringType.
789                                 while (fieldIndex < fieldList.Count)
790                                 {
791                                         FieldInfo field = (FieldInfo)fieldList[fieldIndex];
792                                         if (field.DeclaringType==t)
793                                         {
794                                                 fieldIndex++;
795                                                 XmlAttributes atts = attributeOverrides[type, field.Name];
796                                                 if (atts == null) atts = new XmlAttributes (field);
797                                                 if (atts.XmlIgnore) continue;
798                                                 XmlReflectionMember member = new XmlReflectionMember(field.Name, field.FieldType, atts);
799                                                 member.DeclaringType = field.DeclaringType;
800                                                 members.Add(member);
801                                         }
802                                         else break;
803                                 }
804
805                                 // Add any properties matching the current DeclaringType.
806                                 while (propIndex < propList.Count)
807                                 {
808                                         PropertyInfo prop = (PropertyInfo)propList[propIndex];
809                                         if (prop.DeclaringType==t)
810                                         {
811                                                 propIndex++;
812                                                 XmlAttributes atts = attributeOverrides[type, prop.Name];
813                                                 if (atts == null) atts = new XmlAttributes (prop);
814                                                 if (atts.XmlIgnore) continue;
815                                                 if (!prop.CanWrite) {
816                                                         if (prop.PropertyType.IsGenericType && TypeData.GetGenericListItemType (prop.PropertyType) == null) continue; // check this before calling GetTypeData() which raises error for missing Add(). See bug #704813.
817                                                         if (TypeTranslator.GetTypeData (prop.PropertyType).SchemaType != SchemaTypes.Array || prop.PropertyType.IsArray) continue;
818                                                 }
819                                                 XmlReflectionMember member = new XmlReflectionMember(prop.Name, prop.PropertyType, atts);
820                                                 member.DeclaringType = prop.DeclaringType;
821                                                 members.Add(member);
822                                         }
823                                         else break;
824                                 }
825                         }
826                         
827                         return members;
828                 }
829                 
830                 private XmlTypeMapMember CreateMapMember (Type declaringType, XmlReflectionMember rmember, string defaultNamespace)
831                 {
832                         XmlTypeMapMember mapMember;
833                         XmlAttributes atts = rmember.XmlAttributes;
834                         TypeData typeData = TypeTranslator.GetTypeData (rmember.MemberType);
835
836                         if (atts.XmlArray != null) {
837                                 if (atts.XmlArray.Namespace != null && atts.XmlArray.Form == XmlSchemaForm.Unqualified)
838                                         throw new InvalidOperationException ("XmlArrayAttribute.Form must not be Unqualified when it has an explicit Namespace value.");
839                                 if (typeData.SchemaType != SchemaTypes.Array &&
840                                     !(typeData.SchemaType == SchemaTypes.Primitive && typeData.Type == typeof (byte [])))
841                                         throw new InvalidOperationException ("XmlArrayAttribute can be applied to members of array or collection type.");
842                         }
843
844 #if !MOONLIGHT
845                         if (atts.XmlAnyAttribute != null)
846                         {
847                                 if ( (rmember.MemberType.FullName == "System.Xml.XmlAttribute[]") ||
848                                          (rmember.MemberType.FullName == "System.Xml.XmlNode[]") )
849                                 {
850                                         mapMember = new XmlTypeMapMemberAnyAttribute();
851                                 }
852                                 else
853                                         throw new InvalidOperationException ("XmlAnyAttributeAttribute can only be applied to members of type XmlAttribute[] or XmlNode[]");
854                         }
855                         else
856 #endif
857                         if (atts.XmlAnyElements != null && atts.XmlAnyElements.Count > 0)
858                         {
859                                 // no XmlNode type check is done here (seealso: bug #553032).
860                                 XmlTypeMapMemberAnyElement member = new XmlTypeMapMemberAnyElement();
861                                 member.ElementInfo = ImportAnyElementInfo (defaultNamespace, rmember, member, atts);
862                                 mapMember = member;
863                         }
864                         else if (atts.Xmlns)
865                         {
866                                 XmlTypeMapMemberNamespaces mapNamespaces = new XmlTypeMapMemberNamespaces ();
867                                 mapMember = mapNamespaces;
868                         }
869                         else if (atts.XmlAttribute != null)
870                         {
871                                 // An attribute
872
873                                 if (atts.XmlElements != null && atts.XmlElements.Count > 0)
874                                         throw new Exception ("XmlAttributeAttribute and XmlElementAttribute cannot be applied to the same member");
875
876                                 XmlTypeMapMemberAttribute mapAttribute = new XmlTypeMapMemberAttribute ();
877                                 if (atts.XmlAttribute.AttributeName.Length == 0) 
878                                         mapAttribute.AttributeName = rmember.MemberName;
879                                 else 
880                                         mapAttribute.AttributeName = atts.XmlAttribute.AttributeName;
881
882                                 mapAttribute.AttributeName = XmlConvert.EncodeLocalName (mapAttribute.AttributeName);
883
884                                 if (typeData.IsComplexType)
885                                         mapAttribute.MappedType = ImportTypeMapping (typeData.Type, null, defaultNamespace);
886
887                                 if (atts.XmlAttribute.Namespace != null && atts.XmlAttribute.Namespace != defaultNamespace)
888                                 {
889                                         if (atts.XmlAttribute.Form == XmlSchemaForm.Unqualified)
890                                                 throw new InvalidOperationException ("The Form property may not be 'Unqualified' when an explicit Namespace property is present");
891                                         mapAttribute.Form = XmlSchemaForm.Qualified;
892                                         mapAttribute.Namespace = atts.XmlAttribute.Namespace;
893                                 }
894                                 else
895                                 {
896                                         mapAttribute.Form = atts.XmlAttribute.Form;
897                                         if (atts.XmlAttribute.Form == XmlSchemaForm.Qualified)
898                                                 mapAttribute.Namespace = defaultNamespace;
899                                         else
900                                                 mapAttribute.Namespace = "";
901                                 }
902                                 
903                                 typeData = TypeTranslator.GetTypeData(rmember.MemberType, atts.XmlAttribute.DataType);
904                                 mapMember = mapAttribute;
905                         }
906                         else if (typeData.SchemaType == SchemaTypes.Array)
907                         {
908                                 // If the member has a single XmlElementAttribute and the type is the type of the member,
909                                 // then it is not a flat list
910                                 
911                                 if (atts.XmlElements.Count > 1 ||
912                                    (atts.XmlElements.Count == 1 && atts.XmlElements[0].Type != typeData.Type) ||
913                                    (atts.XmlText != null))
914                                 {
915                                         // A flat list
916
917                                         // check that it does not have XmlArrayAttribute
918                                         if (atts.XmlArray != null)
919                                                 throw new InvalidOperationException ("XmlArrayAttribute cannot be used with members which also attributed with XmlElementAttribute or XmlTextAttribute.");
920
921                                         XmlTypeMapMemberFlatList member = new XmlTypeMapMemberFlatList ();
922                                         member.ListMap = new ListMap ();
923                                         member.ListMap.ItemInfo = ImportElementInfo (declaringType, XmlConvert.EncodeLocalName (rmember.MemberName), defaultNamespace, typeData.ListItemType, member, atts);
924                                         member.ElementInfo = member.ListMap.ItemInfo;
925                                         member.ListMap.ChoiceMember = member.ChoiceMember;
926                                         mapMember = member;
927                                 }
928                                 else
929                                 {
930                                         // A list
931
932                                         XmlTypeMapMemberList member = new XmlTypeMapMemberList ();
933
934                                         // Creates an ElementInfo that identifies the array instance. 
935                                         member.ElementInfo = new XmlTypeMapElementInfoList();
936                                         XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, typeData);
937                                         elem.ElementName = XmlConvert.EncodeLocalName((atts.XmlArray != null && atts.XmlArray.ElementName.Length != 0) ? atts.XmlArray.ElementName : rmember.MemberName);
938                                         // note that it could be changed below (when Form is Unqualified)
939                                         elem.Namespace = (atts.XmlArray != null && atts.XmlArray.Namespace != null) ? atts.XmlArray.Namespace : defaultNamespace;
940                                         elem.MappedType = ImportListMapping (rmember.MemberType, null, elem.Namespace, atts, 0);
941                                         elem.IsNullable = (atts.XmlArray != null) ? atts.XmlArray.IsNullable : false;
942                                         elem.Form = (atts.XmlArray != null) ? atts.XmlArray.Form : XmlSchemaForm.Qualified;
943                                         elem.ExplicitOrder = (atts.XmlArray != null) ? atts.XmlArray.Order : -1;
944                                         // This is a bit tricky, but is done
945                                         // after filling descendant members, so
946                                         // that array items could be serialized
947                                         // with proper namespace.
948                                         if (atts.XmlArray != null && atts.XmlArray.Form == XmlSchemaForm.Unqualified)
949                                                 elem.Namespace = String.Empty;
950
951                                         member.ElementInfo.Add (elem);
952                                         mapMember = member;
953                                 }
954                         }
955                         else
956                         {
957                                 // An element
958
959                                 XmlTypeMapMemberElement member = new XmlTypeMapMemberElement ();
960                                 member.ElementInfo = ImportElementInfo (declaringType, XmlConvert.EncodeLocalName(rmember.MemberName), defaultNamespace, rmember.MemberType, member, atts);
961                                 mapMember = member;
962                         }
963
964                         mapMember.DefaultValue = GetDefaultValue (typeData, atts.XmlDefaultValue);
965                         mapMember.TypeData = typeData;
966                         mapMember.Name = rmember.MemberName;
967                         mapMember.IsReturnValue = rmember.IsReturnValue;
968                         return mapMember;
969                 }
970
971                 XmlTypeMapElementInfoList ImportElementInfo (Type cls, string defaultName, string defaultNamespace, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts)
972                 {
973                         EnumMap choiceEnumMap = null;
974                         Type choiceEnumType = null;
975                         
976                         XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
977                         ImportTextElementInfo (list, defaultType, member, atts, defaultNamespace);
978                         
979                         if (atts.XmlChoiceIdentifier != null) {
980                                 if (cls == null)
981                                         throw new InvalidOperationException ("XmlChoiceIdentifierAttribute not supported in this context.");
982                                         
983                                 member.ChoiceMember = atts.XmlChoiceIdentifier.MemberName;
984                                 MemberInfo[] mems = cls.GetMember (member.ChoiceMember, BindingFlags.Instance|BindingFlags.Public);
985                                 
986                                 if (mems.Length == 0)
987                                         throw new InvalidOperationException ("Choice member '" + member.ChoiceMember + "' not found in class '" + cls);
988                                         
989                                 if (mems[0] is PropertyInfo) {
990                                         PropertyInfo pi = (PropertyInfo)mems[0];
991                                         if (!pi.CanWrite || !pi.CanRead)
992                                                 throw new InvalidOperationException ("Choice property '" + member.ChoiceMember + "' must be read/write.");
993                                         choiceEnumType = pi.PropertyType;
994                                 }
995                                 else choiceEnumType = ((FieldInfo)mems[0]).FieldType;
996                                 
997                                 member.ChoiceTypeData = TypeTranslator.GetTypeData (choiceEnumType);
998                                 
999                                 if (choiceEnumType.IsArray)
1000                                         choiceEnumType = choiceEnumType.GetElementType ();
1001                                 
1002                                 choiceEnumMap = ImportTypeMapping (choiceEnumType).ObjectMap as EnumMap;
1003                                 if (choiceEnumMap == null)
1004                                         throw new InvalidOperationException ("The member '" + mems[0].Name + "' is not a valid target for XmlChoiceIdentifierAttribute.");
1005                         }
1006                         
1007                         if (atts.XmlElements.Count == 0 && list.Count == 0)
1008                         {
1009                                 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(defaultType));
1010                                 elem.ElementName = defaultName;
1011                                 elem.Namespace = defaultNamespace;
1012                                 if (elem.TypeData.IsComplexType)
1013                                         elem.MappedType = ImportTypeMapping (defaultType, null, defaultNamespace);
1014                                 list.Add (elem);
1015                         }
1016
1017                         bool multiType = (atts.XmlElements.Count > 1);
1018                         foreach (XmlElementAttribute att in atts.XmlElements)
1019                         {
1020                                 Type elemType = (att.Type != null) ? att.Type : defaultType;
1021                                 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(elemType, att.DataType));
1022                                 elem.Form = att.Form;
1023                                 if (elem.Form != XmlSchemaForm.Unqualified)
1024                                         elem.Namespace = (att.Namespace != null) ? att.Namespace : defaultNamespace;
1025
1026                                 // elem may already be nullable, and IsNullable property in XmlElement is false by default
1027                                 if (att.IsNullable && !elem.IsNullable)
1028                                         elem.IsNullable = att.IsNullable;
1029
1030                                 elem.ExplicitOrder = att.Order;
1031
1032                                 if (elem.IsNullable && !elem.TypeData.IsNullable)
1033                                         throw new InvalidOperationException ("IsNullable may not be 'true' for value type " + elem.TypeData.FullTypeName + " in member '" + defaultName + "'");
1034                                         
1035                                 if (elem.TypeData.IsComplexType)
1036                                 {
1037                                         if (att.DataType.Length != 0) throw new InvalidOperationException (
1038                                                 string.Format(CultureInfo.InvariantCulture, "'{0}' is "
1039                                                         + "an invalid value for '{1}.{2}' of type '{3}'. "
1040                                                         + "The property may only be specified for primitive types.",
1041                                                         att.DataType, cls.FullName, defaultName, 
1042                                                         elem.TypeData.FullTypeName));
1043                                         elem.MappedType = ImportTypeMapping (elemType, null, elem.Namespace);
1044                                 }
1045
1046                                 if (att.ElementName.Length != 0)  {
1047                                         elem.ElementName = XmlConvert.EncodeLocalName(att.ElementName);
1048                                 } else if (multiType) {
1049                                         if (elem.MappedType != null) {
1050                                                 elem.ElementName = elem.MappedType.ElementName;
1051                                         } else {
1052                                                 elem.ElementName = TypeTranslator.GetTypeData (elemType).XmlType;
1053                                         }
1054                                 } else {
1055                                         elem.ElementName = defaultName;
1056                                 }
1057
1058                                 if (choiceEnumMap != null) {
1059                                         string cname = choiceEnumMap.GetEnumName (choiceEnumType.FullName, elem.ElementName);
1060                                         if (cname == null)
1061                                                 throw new InvalidOperationException (string.Format (
1062                                                         CultureInfo.InvariantCulture, "Type {0} is missing"
1063                                                         + " enumeration value '{1}' for element '{1} from"
1064                                                         + " namespace '{2}'.", choiceEnumType, elem.ElementName,
1065                                                         elem.Namespace));
1066                                         elem.ChoiceValue = Enum.Parse (choiceEnumType, cname, false);
1067                                 }
1068                                         
1069                                 list.Add (elem);
1070                         }
1071                         return list;
1072                 }
1073
1074                 XmlTypeMapElementInfoList ImportAnyElementInfo (string defaultNamespace, XmlReflectionMember rmember, XmlTypeMapMemberElement member, XmlAttributes atts)
1075                 {
1076                         XmlTypeMapElementInfoList list = new XmlTypeMapElementInfoList();
1077
1078                         ImportTextElementInfo (list, rmember.MemberType, member, atts, defaultNamespace);
1079
1080 #if !MOONLIGHT // no practical anyElement support
1081                         foreach (XmlAnyElementAttribute att in atts.XmlAnyElements)
1082                         {
1083                                 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(typeof(XmlElement)));
1084                                 if (att.Name.Length != 0) 
1085                                 {
1086                                         elem.ElementName = XmlConvert.EncodeLocalName(att.Name);
1087                                         elem.Namespace = (att.Namespace != null) ? att.Namespace : "";
1088                                 }
1089                                 else 
1090                                 {
1091                                         elem.IsUnnamedAnyElement = true;
1092                                         elem.Namespace = defaultNamespace;
1093                                         if (att.Namespace != null) 
1094                                                 throw new InvalidOperationException ("The element " + rmember.MemberName + " has been attributed with an XmlAnyElementAttribute and a namespace '" + att.Namespace + "', but no name. When a namespace is supplied, a name is also required. Supply a name or remove the namespace.");
1095                                 }
1096                                 elem.ExplicitOrder = att.Order;
1097                                 list.Add (elem);
1098                         }
1099 #endif
1100                         return list;
1101                 }
1102
1103                 void ImportTextElementInfo (XmlTypeMapElementInfoList list, Type defaultType, XmlTypeMapMemberElement member, XmlAttributes atts, string defaultNamespace)
1104                 {
1105                         if (atts.XmlText != null)
1106                         {
1107                                 member.IsXmlTextCollector = true;
1108                                 if (atts.XmlText.Type != null) {
1109                                         TypeData td = TypeTranslator.GetTypeData (defaultType);
1110                                         if ((td.SchemaType == SchemaTypes.Primitive || td.SchemaType == SchemaTypes.Enum) && atts.XmlText.Type != defaultType) {
1111                                                 throw new InvalidOperationException ("The type for XmlText may not be specified for primitive types.");
1112                                         }
1113                                         defaultType = atts.XmlText.Type;
1114                                 }
1115 #if !MOONLIGHT
1116                                 if (defaultType == typeof(XmlNode)) defaultType = typeof(XmlText);      // Nodes must be text nodes
1117 #endif
1118
1119                                 XmlTypeMapElementInfo elem = new XmlTypeMapElementInfo (member, TypeTranslator.GetTypeData(defaultType, atts.XmlText.DataType));
1120
1121                                 if (elem.TypeData.SchemaType != SchemaTypes.Primitive &&
1122                                         elem.TypeData.SchemaType != SchemaTypes.Enum &&
1123                                     elem.TypeData.SchemaType != SchemaTypes.XmlNode &&
1124                                     !(elem.TypeData.SchemaType == SchemaTypes.Array && elem.TypeData.ListItemTypeData.SchemaType == SchemaTypes.XmlNode)
1125                                  )
1126                                         throw new InvalidOperationException ("XmlText cannot be used to encode complex types");
1127
1128                                 if (elem.TypeData.IsComplexType)
1129                                         elem.MappedType = ImportTypeMapping (defaultType, null, defaultNamespace);
1130                                 elem.IsTextElement = true;
1131                                 elem.WrappedElement = false;
1132                                 list.Add (elem);
1133                         }
1134                 }
1135                 
1136                 bool CanBeNull (TypeData type)
1137                 {
1138 #if !NET_2_0    // idiotic compatibility
1139                         if (type.Type == typeof (XmlQualifiedName))
1140                                 return false;
1141 #endif
1142                         return !type.Type.IsValueType || type.IsNullable;
1143                 }
1144                 
1145                 public void IncludeType (Type type)
1146                 {
1147                         if (type == null)
1148                                 throw new ArgumentNullException ("type");
1149
1150                         if (includedTypes == null) includedTypes = new ArrayList ();
1151                         if (!includedTypes.Contains (type))
1152                                 includedTypes.Add (type);
1153                         
1154                         if (relatedMaps.Count > 0) {
1155                                 foreach (XmlTypeMapping map in (ArrayList) relatedMaps.Clone ()) {
1156                                         if (map.TypeData.Type == typeof(object))
1157                                                 map.DerivedTypes.Add (ImportTypeMapping (type));
1158                                 }
1159                         }
1160                 }
1161
1162                 public void IncludeTypes (ICustomAttributeProvider provider)
1163                 { 
1164                         object[] ats = provider.GetCustomAttributes (typeof(XmlIncludeAttribute), true);
1165                         
1166                         foreach (XmlIncludeAttribute at in ats)
1167                                 IncludeType (at.Type);
1168                 }
1169
1170                 private object GetDefaultValue (TypeData typeData, object defaultValue)
1171                 {
1172                         if (defaultValue == DBNull.Value || typeData.SchemaType != SchemaTypes.Enum)
1173                                 return defaultValue;
1174
1175 #if MOONLIGHT
1176                         string namedValue = (defaultValue as Enum).ToString ("g");
1177                         string decimalValue = (defaultValue as Enum).ToString ("d");
1178 #else
1179                         // get string representation of enum value
1180                         string namedValue = Enum.Format (typeData.Type, defaultValue, "g");
1181                         // get decimal representation of enum value
1182                         string decimalValue = Enum.Format (typeData.Type, defaultValue, "d");
1183 #endif
1184                         // if decimal representation matches string representation, then
1185                         // the value is not defined in the enum type (as the "g" format
1186                         // will return the decimal equivalent of the value if the value
1187                         // is not equal to a combination of named enumerated constants
1188                         if (namedValue == decimalValue) {
1189                                 string msg = string.Format (CultureInfo.InvariantCulture,
1190                                         "Value '{0}' cannot be converted to {1}.", defaultValue,
1191                                         defaultValue.GetType ().FullName);
1192                                 throw new InvalidOperationException (msg);
1193                         }
1194
1195                         // XmlSerializer expects integral enum value
1196                         //return namedValue.Replace (',', ' ');
1197                         return defaultValue;
1198                 }
1199
1200                 #endregion // Methods
1201         }
1202 }