2003-05-10 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSerializer.cs
1 //
2 // Mono Class Libraries
3 // System.Xml.Serialization.XmlSerializer
4 //
5 // Authors:
6 //   John Donagher (john@webmeta.com)
7 //   Ajay kumar Dwivedi (adwiv@yahoo.com)
8 //   Tim Coleman (tim@timcoleman.com)
9 //   Elan Feingold (ef10@cornell.edu)
10 //   Atsushi Enomoto (ginga@kit.hi-ho.ne.jp)
11 //
12 // (C) 2002 John Donagher, Ajay kumar Dwivedi
13 // Copyright (C) Tim Coleman, 2002
14 // (C) 2003 Elan Feingold, Atsushi Enomoto
15 //
16
17 using System;
18 using System.Collections;
19 using System.IO;
20 using System.Reflection;
21 using System.Xml;
22 using System.Xml.Schema;
23 using System.Text;
24
25 namespace System.Xml.Serialization
26 {
27
28         public class XmlSerializer
29         {
30
31 #region Classes
32                 internal class XmlAttributeMapper\r
33                 {\r
34                         XmlAttributeOverrides attributeOverrides;\r
35                         Hashtable cachedTypeAttributes = new Hashtable ();\r
36                         Hashtable cachedMemberAttributes = new Hashtable ();\r
37 \r
38                         public XmlAttributeMapper (XmlAttributeOverrides attributeOverrides)\r
39                         {\r
40                                 this.attributeOverrides = attributeOverrides;\r
41                         }\r
42 \r
43                         //\r
44                         // Get the XmlAttributes object associated with a member\r
45                         // \r
46                         public XmlAttributes GetMemberAttributes (MemberInfo member)\r
47                         {\r
48                                 XmlAttributes cache = cachedMemberAttributes [member] as XmlAttributes;\r
49                                 if (cache != null)\r
50                                         return cache;\r
51 \r
52                                 XmlAttributes attribs = null;\r
53 \r
54                                 try {\r
55                                         if (attributeOverrides != null)\r
56                                         attribs = attributeOverrides [member.ReflectedType, member.Name];\r
57                                         if (attribs == null) {\r
58                                                 attribs = new XmlAttributes ();\r
59                                                 object [] attributes = member.GetCustomAttributes (false);\r
60                                                 attribs.AddMemberAttributes (attributes);\r
61                                         }\r
62 \r
63                                         attribs.MemberInfo = member;\r
64                                         attribs.PropertyInfo = (member as PropertyInfo);\r
65                                         attribs.FieldInfo = (member as FieldInfo);\r
66                                         return attribs;\r
67                                 } finally {\r
68                                         cachedTypeAttributes [member] = attribs;\r
69                                 }\r
70                         }\r
71 \r
72                         //\r
73                         // Get a types XmlAttributes\r
74                         // \r
75                         public XmlAttributes GetTypeAttributes (Type type)\r
76                         {\r
77                                 XmlAttributes cache = cachedTypeAttributes [type] as XmlAttributes;\r
78                                 if (cache != null)\r
79                                         return cache;\r
80 \r
81                                 XmlAttributes attribs = null;\r
82 \r
83                                 try {\r
84                                         if (attributeOverrides != null) {\r
85                                                 attribs = attributeOverrides [type];\r
86                                                 if (attribs != null)\r
87                                                         return attribs;\r
88                                         }\r
89                                         attribs = XmlAttributes.FromClass (type);\r
90                                         if (attribs != null)\r
91                                                 return attribs;\r
92                                         return new XmlAttributes ();\r
93                                 } finally {\r
94                                         cachedTypeAttributes [type] = attribs;\r
95                                 }\r
96                         }\r
97                 }\r
98 #endregion
99
100 #region Fields
101
102                 Type xsertype;
103                 XmlAttributeOverrides overrides;
104                 Type[] extraTypes;
105                 XmlRootAttribute rootAttribute;
106                 string defaultNamespace;
107                 TypeTablePool typeTable;
108                 bool useOrder;
109                 bool isNullable;
110                 Hashtable typeMappings = new Hashtable ();
111                 TypeTranslator typeTranslator = new TypeTranslator ();
112                 XmlAttributeMapper attributeMapper;
113
114 #endregion // Fields
115
116 #region Constructors
117
118                 protected XmlSerializer ()
119                 {
120                 }
121
122                 public XmlSerializer (Type type)
123                         : this (type, null, null, null, null)
124                 {
125                 }
126
127                 public XmlSerializer (XmlTypeMapping xmlTypeMapping)
128                 {
129                         typeMappings.Add (xmlTypeMapping.TypeFullName, xmlTypeMapping);
130                 }
131
132                 public XmlSerializer (Type type, string defaultNamespace)
133                         : this (type, null, null, null, defaultNamespace)
134                 {
135                 }
136
137                 public XmlSerializer (Type type, Type[] extraTypes)
138                         : this (type, null, extraTypes, null, null)
139                 {
140                 }
141
142                 public XmlSerializer (Type type, XmlAttributeOverrides overrides)
143                         : this (type, overrides, null, null, null)
144                 {
145                 }
146
147                 public XmlSerializer (Type type, XmlRootAttribute root)
148                         : this (type, null, null, root, null)
149                 {
150                 }
151
152 //              internal XmlSerializer (Hashtable typeTable)
153 //              {
154 //                        this.typeTable = typeTable;
155 //              }
156
157                 public XmlSerializer (Type type,
158                         XmlAttributeOverrides overrides,
159                         Type [] extraTypes,
160                         XmlRootAttribute root,
161                         string defaultNamespace)
162                 {
163                         if (type == null)
164                                 throw new ArgumentNullException ("type");
165
166                         // TODO: the *REAL* construction steps are:
167                         // (1)create XmlReflectionMember list 
168                         //    for each serializable members.
169                         // (2)use XmlReflectionImporter.ImportMembersMapping()
170                         //    to generate XmlMembersMapping.
171                         attributeMapper = new XmlAttributeMapper (overrides);
172
173                         XmlReflectionImporter ri = new XmlReflectionImporter (overrides, defaultNamespace);
174                         TypeData td = typeTranslator.GetTypeData (type);
175                         typeMappings.Add (td.FullTypeName, ri.ImportTypeMapping (type, root, defaultNamespace));
176                         ri.IncludeTypes (type);
177
178                         if (extraTypes != null) {
179                                 foreach (Type t in extraTypes) {
180                                         td = typeTranslator.GetTypeData (t);
181                                         string n = td.FullTypeName;
182                                         typeMappings.Add (n, ri.ImportTypeMapping (type, root, defaultNamespace));
183                                         ri.IncludeTypes (t);
184                                 }
185                         }
186
187                         this.xsertype = type;
188                         this.overrides = overrides;
189                         this.extraTypes = (extraTypes == null ? new Type[0] : extraTypes);
190
191                         if (root != null)
192                                 this.rootAttribute = root;
193                         else {
194                                 XmlAttributes attributes = new XmlAttributes (type);
195                                 if (attributes.XmlRoot != null)
196                                         this.rootAttribute = attributes.XmlRoot;
197                         }
198
199                         this.defaultNamespace = defaultNamespace;
200
201                         if (typeTable == null)
202                                 typeTable = new TypeTablePool ();
203
204                         FillTypeTable (type);
205                 }
206
207 #endregion // Constructors
208
209 #region Events
210
211                 public event XmlAttributeEventHandler UnknownAttribute;
212                 public event XmlElementEventHandler UnknownElement;
213                 public event XmlNodeEventHandler UnknownNode;
214                 public event UnreferencedObjectEventHandler UnreferencedObject;
215
216 #endregion // Events
217
218 #region Properties
219
220                 internal bool UseOrder {
221                         get { return useOrder; }
222                         set { useOrder = value; }
223                 }
224
225 #endregion // Properties
226
227 #region Methods
228
229                 [MonoTODO ("Implement.")]
230                 public virtual bool CanDeserialize (XmlReader xmlReader)
231                 {
232                         string localName = (rootAttribute != null ? rootAttribute.ElementName : xsertype.Name);
233 //                      throw new NotImplementedException ();
234                         xmlReader.MoveToContent ();
235                         return localName == xmlReader.LocalName;
236                 }
237
238                 protected virtual XmlSerializationReader CreateReader ()
239                 {
240                         // This is what MS does.
241                         // Its body is defined only in extended classes.
242                         throw new NotImplementedException ();
243                 }
244
245                 protected virtual XmlSerializationWriter CreateWriter ()
246                 {
247                         // This is what MS does.
248                         // Its body is defined only in extended classes.
249                         throw new NotImplementedException ();
250                 }
251
252                 public object Deserialize (Stream stream)
253                 {
254                         XmlTextReader xmlReader = new XmlTextReader(stream);
255                         return Deserialize(xmlReader);
256                 }
257
258                 public object Deserialize (TextReader textReader)
259                 {
260                         XmlTextReader xmlReader = new XmlTextReader(textReader);
261                         return Deserialize(xmlReader);
262                 }
263
264                 public bool DeserializeComposite(XmlReader xmlReader, ref Object theObject)
265                 {
266                         Type objType = theObject.GetType();
267                         bool retVal  = true;
268
269                         // Are we at an empty element?
270                         if (xmlReader.IsEmptyElement == true)
271                                 return retVal;
272
273                         int startDepth = xmlReader.Depth;
274                         xmlReader.Read ();
275                         if (xmlReader.NodeType == XmlNodeType.EndElement)
276                                 return retVal;
277
278                         // Read each field, counting how many we find.
279                         for (int numFields=0; xmlReader.Depth > startDepth; xmlReader.Read()) {
280                                 switch (xmlReader.NodeType) {
281                                 case XmlNodeType.Element:
282                                         // Read the field.
283                                         DeserializeField(xmlReader, ref theObject, xmlReader.Name);
284                                         numFields++;
285                                         break;
286                                 case XmlNodeType.EndElement:
287                                         if (numFields == 0)
288                                                 retVal = false;
289                                         return retVal;
290                                 }
291                         }
292                         return retVal;
293                 }
294
295                 private void DeserializeField (XmlReader xmlReader, ref Object theObject, String fieldName)
296                 {
297                         //Console.WriteLine("DeserializeField({0})", fieldName);
298
299                         BindingFlags bindingFlags = 0;
300                         Type fieldType = null;
301
302                         // Get the type, first try a field.
303                         FieldInfo fieldInfo = theObject.GetType().GetField(fieldName);
304
305                         if (fieldInfo != null) {
306                                 fieldType = fieldInfo.FieldType;
307                                 bindingFlags = BindingFlags.SetField;
308                         } else {
309                                 // Is it a property?
310                                 PropertyInfo propInfo = theObject.GetType().GetProperty(fieldName);
311                                 if (propInfo != null)
312                                 {
313                                         fieldType = propInfo.PropertyType;
314                                         bindingFlags = BindingFlags.SetProperty;
315                                 }
316                         }
317
318                         if (fieldType == null)
319                                 throw new Exception (String.Format ("On type {0} can not identify {1}", theObject.GetType (), fieldName));
320
321                         Object    value            = null;
322                         bool      isEmptyField = xmlReader.IsEmptyElement;
323  
324                         //Console.WriteLine("DeserializeField({0} of type {1})", fieldName, fieldType);
325
326                         if (fieldType.IsArray && fieldType != typeof(System.Byte[]))
327                         {
328                                 // Create an empty array list.
329                                 ArrayList list = new ArrayList();
330
331                                 // Call out to deserialize it.
332                                 DeserializeArray(xmlReader, list, fieldType.GetElementType());
333                                 value = list.ToArray(fieldType.GetElementType());
334                         }
335                         else if (isEmptyField == false && (IsInbuiltType(fieldType) || fieldType.IsEnum || fieldType.IsArray))
336                         {
337                                 // Built in, set it.
338                                 while (xmlReader.Read())
339                                 {
340                                         if (xmlReader.NodeType == XmlNodeType.Text)
341                                         {
342                                                 //Console.WriteLine(" -> value is '{0}'", xmlReader.Value);
343
344                                                 if (fieldType == typeof(Guid))
345                                                         value = XmlConvert.ToGuid(xmlReader.Value);
346                                                 else if (fieldType == typeof(Boolean))
347                                                         value = XmlConvert.ToBoolean(xmlReader.Value);
348                                                 else if (fieldType == typeof(String))
349                                                         value = xmlReader.Value;
350                                                 else if (fieldType == typeof(Int64))
351                                                         value = XmlConvert.ToInt64(xmlReader.Value);
352                                                 else if (fieldType == typeof(DateTime))
353                                                         value = XmlConvert.ToDateTime(xmlReader.Value);
354                                                 else if (fieldType.IsEnum)
355                                                         value = Enum.Parse(fieldType, xmlReader.Value);
356                                                 else if (fieldType == typeof(System.Byte[]))
357                                                         value = XmlCustomFormatter.ToByteArrayBase64(xmlReader.Value);
358                                                 else if (fieldType == typeof (Int32))
359                                                         value = XmlConvert.ToInt32 (xmlReader.Value);
360                                                 else
361                                                         throw new NotImplementedException (String.Format ("XmlSerializer.DeserializeField, improve routine: Error (type is '{0}')", fieldType));
362
363                                                 break;
364                                         }
365                                 }
366                         }
367                         else if (isEmptyField == true)
368                         {
369                                 if  (fieldType.IsArray)
370                                 {
371                                         // Must be a byte array, just create an empty one.
372                                         value = new byte[0];
373                                 }
374                                 else if (fieldType == typeof(string))
375                                 {
376                                         // Create a new empty string.
377                                         value = "";
378                                 }
379                         }
380                         else
381                         {
382                                 //Console.WriteLine("Creating new {0}", fieldType);
383
384                                 // Create the new complex object.
385                                 value = System.Activator.CreateInstance(fieldType);
386
387                                 // Recurse, allowing the method to whack the object if it's empty.
388                                 DeserializeComposite(xmlReader, ref value);
389                         }
390
391                         //Console.WriteLine(" Setting {0} to '{1}'", fieldName, value);
392
393                         // Set the field value.
394                         theObject.GetType().InvokeMember(fieldName,
395                                                          bindingFlags,
396                                                          null,
397                                                          theObject,
398                                                          new Object[] { value },
399                                                          null, null, null);
400
401                         // We need to munch the end.
402                         if (IsInbuiltType(fieldType) ||
403                             fieldType.IsEnum                 ||
404                             fieldType == typeof(System.Byte[]))
405                         {
406                                 if (isEmptyField == false)
407                                         while (xmlReader.Read() && xmlReader.NodeType != XmlNodeType.EndElement)
408                                                 ;
409                         }
410
411                 }
412
413                 public void DeserializeArray(XmlReader xmlReader, ArrayList theList, Type theType)
414                 {
415                         //Console.WriteLine(" DeserializeArray({0})", theType);
416
417                         if (xmlReader.IsEmptyElement)
418                         {
419                                 //Console.WriteLine("  DeserializeArray -> empty, nothing to do here");
420                                 return;
421                         }
422
423                         while (xmlReader.Read())
424                         {
425                                 XmlNodeType xmlNodeType = xmlReader.NodeType;
426                                 bool        isEmpty     = xmlReader.IsEmptyElement;
427
428                                 if (xmlNodeType == XmlNodeType.Element)
429                                 {
430                                         // Must be an element of the array, create it.
431                                         Object obj = System.Activator.CreateInstance(theType);
432
433                                         //Console.WriteLine("  created obj of type '{0}'", obj.GetType());
434
435                                         // Deserialize and add.
436                                         if (DeserializeComposite(xmlReader, ref obj))
437                                         {
438                                                 theList.Add(obj);
439                                         }
440                                 }
441
442                                 if ((xmlNodeType == XmlNodeType.Element && isEmpty) ||
443                                     (xmlNodeType == XmlNodeType.EndElement))
444                                 {
445                                         return;
446                                 }
447                         }
448                 }
449
450                 [MonoTODO ("Use XmlSerializationReader and extended XmlSerializer.")]
451                 public object Deserialize (XmlReader xmlReader)
452                 {
453                         if (!CanDeserialize (xmlReader))
454                                 throw new InvalidOperationException ("Cannot deserialize specified Xml.");
455
456                         Object obj = null;
457
458                         TypeData td = typeTranslator.GetTypeData (xsertype);
459                         if (td.Type.IsArray) {
460                                 ArrayList list = new ArrayList ();
461                                 // Call out to deserialize it.
462                                 DeserializeArray (xmlReader, list, xsertype.GetElementType ());
463                                 obj = list.ToArray (xsertype.GetElementType ());
464                         } else {
465                                 // Create the top level object.
466                                 obj = System.Activator.CreateInstance(xsertype);
467                                 if (!xmlReader.IsEmptyElement)
468                                         DeserializeComposite (xmlReader, ref obj);
469                         }
470                         return obj;
471                 }
472
473                 protected virtual object Deserialize (XmlSerializationReader reader)
474                 {
475                         // This is what MS does.
476                         // Because it is defined only in extended classes.
477                         throw new NotImplementedException ();
478                 }
479
480                 [MonoTODO]
481                 public static XmlSerializer [] FromMappings (XmlMapping [] mappings)
482                 {
483                         throw new NotImplementedException ();
484                 }
485
486                 [MonoTODO]
487                 public static XmlSerializer [] FromTypes (Type [] mappings)
488                 {
489                         throw new NotImplementedException ();
490                 }
491
492                 protected virtual void Serialize (object o, XmlSerializationWriter writer)
493                 {
494                         // Because it is defined only in extended classes.
495                         throw new NotImplementedException ();
496                 }
497
498                 public void Serialize (Stream stream, object o)
499                 {
500                         XmlTextWriter xmlWriter = new XmlTextWriter (stream, System.Text.Encoding.Default);
501                         xmlWriter.Formatting = Formatting.Indented;
502                         xmlWriter.WriteStartDocument ();
503                         Serialize (xmlWriter, o, null);
504                         xmlWriter.WriteEndDocument();
505                         xmlWriter.Flush();
506                 }
507
508                 public void Serialize (TextWriter textWriter, object o)
509                 {
510                         XmlTextWriter xmlWriter = new XmlTextWriter (textWriter);
511                         xmlWriter.Formatting = Formatting.Indented;
512                         xmlWriter.WriteStartDocument ();
513                         Serialize (xmlWriter, o, null);
514                         xmlWriter.WriteEndDocument();
515                         xmlWriter.Flush();
516                 }
517
518                 public void Serialize (XmlWriter xmlWriter, object o)
519                 {
520                         Serialize (xmlWriter, o, null);
521                 }
522
523                 public void Serialize (Stream stream, object o, XmlSerializerNamespaces namespaces)
524                 {
525                         XmlTextWriter xmlWriter = new XmlTextWriter (stream, System.Text.Encoding.Default);
526                         xmlWriter.Formatting = Formatting.Indented;
527                         xmlWriter.WriteStartDocument ();
528                         Serialize (xmlWriter, o, namespaces);
529                         xmlWriter.WriteEndDocument();
530                         xmlWriter.Flush();
531                 }
532
533                 public void Serialize (TextWriter textWriter, object o, XmlSerializerNamespaces namespaces)
534                 {
535                         XmlTextWriter xmlWriter = new XmlTextWriter (textWriter);
536                         xmlWriter.Formatting = Formatting.Indented;
537                         xmlWriter.WriteStartDocument ();
538                         Serialize (xmlWriter, o, namespaces);
539                         xmlWriter.WriteEndDocument();
540                         xmlWriter.Flush();
541                 }
542
543                 [MonoTODO ("Use XmlSerializationWriter")]
544                 public void Serialize (XmlWriter writer, object o, XmlSerializerNamespaces namespaces)
545                 {
546                         if (IsInbuiltType(xsertype)) {
547                                 SerializeBuiltIn (writer, o, xsertype);
548                                 return;
549                         }
550
551                         // FIXME: If XmlRoot specifies IsNullable=true,
552                         // then it must emit xsi:nil instance.
553                         if (o == null)
554                                 throw new ArgumentNullException ("object o");
555
556                         // First, get root type mapping.
557                         TypeTableEntry entry = typeTable [xsertype];
558                         Hashtable memberTable = entry.MemberTable;
559                         XmlAttributes xmlAttributes = (XmlAttributes) memberTable [""];
560                         bool isNullable = false;
561                         XmlRootAttribute root = xmlAttributes.XmlRoot;
562                         if (root != null)
563                                 isNullable = root.IsNullable;
564
565                         if (o == null) {
566                                 if (!isNullable)
567                                         throw new ArgumentNullException ("target object is null.");
568                                 else {
569                                         this.WriteElement (writer, xmlAttributes, root.ElementName, root.Namespace, xsertype, null, namespaces);
570                                 }
571                                 return;
572                         }
573
574                         // We don't use actual (derived)Type, which may have
575                         // its own, different XmlAttributes.
576                         if (!xsertype.IsInstanceOfType (o))
577                                 throw new InvalidOperationException ("Specified object is not of the target Type.");
578
579                         if (namespaces == null)
580                                 namespaces = new XmlSerializerNamespaces ();
581                         namespaces.Add ("xsd", XmlSchema.Namespace);
582                         namespaces.Add ("xsi", XmlSchema.InstanceNamespace);
583
584                         if (writer.WriteState == WriteState.Start)
585                                 writer.WriteStartDocument ();
586                         SerializeType (writer, o, namespaces, xsertype);
587                         // Keep WriteState.Content state. 
588                         // Don't WriteEndDocument().
589                         writer.Flush ();
590                 }
591
592                 private void SerializeType (XmlWriter writer, object o, XmlSerializerNamespaces namespaces, Type objType)
593                 {
594                         if (IsInbuiltType(objType))
595                         {
596                                 SerializeBuiltIn (writer, o, objType);
597                                 return;
598                         }
599
600                         XmlSerializerNamespaces nss = 
601                                 new XmlSerializerNamespaces ();
602
603                         XmlQualifiedName[] qnames;
604
605                         TypeTableEntry entry = (TypeTableEntry) typeTable [objType];
606                         if (entry == null)
607                                 throw new Exception ("Unknown Type " + objType +
608                                                      " encountered during Serialization");
609
610                         Hashtable memberTable = entry.MemberTable;
611                         XmlAttributes xmlAttributes = (XmlAttributes) memberTable [""];
612
613                         string rootName = objType.Name;
614                         string rootNs = String.Empty;
615                         string rootPrefix = String.Empty;
616
617                         //If we have been passed an XmlRoot, set it on the base class
618                         if (rootAttribute != null)
619                                 xmlAttributes.XmlRoot = rootAttribute;
620
621                         if (xmlAttributes.XmlRoot != null) {
622                                 isNullable = xmlAttributes.XmlRoot.IsNullable;
623                                 if (xmlAttributes.XmlRoot.ElementName != null)
624                                         rootName = xmlAttributes.XmlRoot.ElementName;
625                                 rootNs  = xmlAttributes.XmlRoot.Namespace;
626                         }
627
628                         if (namespaces != null && namespaces.GetPrefix (rootNs) != null)
629                                 rootPrefix = namespaces.GetPrefix (rootNs);
630
631                         //XMLNS attributes in the Root
632                         XmlAttributes XnsAttrs = ((TypeTableEntry) typeTable [objType]).XmlAttributes;
633
634                         if (XnsAttrs != null) {
635                                 MemberInfo member = XnsAttrs.MemberInfo;
636                                 FieldInfo fieldInfo = member as FieldInfo;
637                                 PropertyInfo propertyInfo = member as PropertyInfo;
638                                 XmlSerializerNamespaces xns;
639
640                                 if (fieldInfo != null)
641                                         xns = (XmlSerializerNamespaces) fieldInfo.GetValue (o);
642                                 else
643                                         xns = (XmlSerializerNamespaces) propertyInfo.GetValue (o, null);
644
645                                 qnames = xns.ToArray ();
646
647                                 foreach (XmlQualifiedName qname in qnames)
648                                         nss.Add (qname.Name, qname.Namespace);
649                         }
650
651                         //XmlNs from the namespaces passed
652                         qnames = namespaces.ToArray ();
653                         foreach (XmlQualifiedName qname in qnames) {
654                                 if (writer.LookupPrefix (qname.Namespace) != qname.Name)
655                                         nss.Add (qname.Name, qname.Namespace);
656                         }
657
658                         writer.WriteStartElement (rootPrefix, rootName, rootNs);
659
660                         qnames = nss.ToArray();
661                         foreach (XmlQualifiedName qname in qnames) {
662                                 if (writer.LookupPrefix (qname.Namespace) != qname.Name)
663                                         writer.WriteAttributeString ("xmlns", qname.Name, null, qname.Namespace);
664                         }
665
666                         if (rootPrefix == String.Empty && rootNs != String.Empty && rootNs != null)
667                                 writer.WriteAttributeString (String.Empty, "xmlns", null, rootNs);
668
669                         SerializeMembers (writer, o, true, namespaces);
670                 }
671
672                 // TODO: Resolve custom XmlAttributes
673                 private void SerializeBuiltIn (XmlWriter writer, object o, Type type)
674                 {
675                         if (o is XmlQualifiedName) {
676                                 XmlQualifiedName qn = o as XmlQualifiedName;
677                                 if (writer.WriteState != WriteState.Attribute) {
678                                         writer.WriteStartElement ("QName");
679                                         writer.WriteStartAttribute ("xmlns", "q1", "http://www.w3.org/2000/xmlns");
680                                         writer.WriteString (qn.Namespace);
681                                         writer.WriteEndAttribute ();
682                                         writer.WriteQualifiedName (qn.Name, qn.Namespace);
683                                         writer.WriteEndElement ();
684                                 } else
685                                         writer.WriteQualifiedName (qn.Name, qn.Namespace);
686                         } else if (o is XmlNode) {
687                                 XmlNode n = (XmlNode) o;
688                                 XmlNodeReader nrdr = new XmlNodeReader (n);
689                                 nrdr.MoveToContent ();
690                                 writer.WriteNode (nrdr, false);
691                         } else {
692                                 TypeData td = typeTranslator.GetTypeData (type);
693                                 writer.WriteStartElement (td.ElementName);
694                                 if (o == null)
695                                         WriteNilAttribute (writer);
696                                 else
697                                         WriteBuiltinValue (writer,o);
698                                 writer.WriteEndElement();
699                         }
700                 }
701
702                 private void WriteNilAttribute(XmlWriter writer)
703                 {
704                         writer.WriteAttributeString("nil",XmlSchema.InstanceNamespace, "true");
705                 }
706
707                 private void WriteBuiltinValue (XmlWriter writer, object o)
708                 {
709                         if (o == null)
710                                 WriteNilAttribute (writer);
711                         else
712                                 writer.WriteString (GetXmlValue(o));
713                 }
714
715                 private void SerializeMembers (XmlWriter writer, object o, bool isRoot, XmlSerializerNamespaces namespaces)
716                 {
717                         if(o == null)
718                         {
719                                 WriteNilAttribute (writer);
720                                 return;
721                         }
722
723                         Type objType = o.GetType ();
724
725                         if (IsInbuiltType(objType))
726                         {
727                                 SerializeBuiltIn (writer, o, objType);
728                                 return;
729                         }
730
731                         TypeTableEntry entry = (TypeTableEntry) typeTable [objType];
732                         XmlAttributes nsAttributes = entry.XmlAttributes;
733                         ArrayList attributes = entry.AttributeMembers;
734                         ArrayList elements = entry.ElementMembers;
735
736                         if (!isRoot && nsAttributes != null) {
737                                 MemberInfo member = nsAttributes.MemberInfo;
738                                 FieldInfo fieldInfo = member as FieldInfo;
739                                 PropertyInfo propertyInfo = member as PropertyInfo;
740
741                                 XmlSerializerNamespaces xns;
742
743                                 if (fieldInfo != null)
744                                         xns = (XmlSerializerNamespaces) fieldInfo.GetValue (o);
745                                 else
746                                         xns = (XmlSerializerNamespaces) propertyInfo.GetValue (o, null);
747
748                                 XmlQualifiedName[] qnames = xns.ToArray ();
749                                 foreach (XmlQualifiedName qname in qnames)
750                                         if (writer.LookupPrefix (qname.Namespace) != qname.Name)
751                                                 writer.WriteAttributeString ("xmlns", qname.Name, null, qname.Namespace);
752                         }
753
754                         //Serialize the Attributes.
755                         foreach (XmlAttributes xmlAttributes in attributes) {
756                                 MemberInfo member = xmlAttributes.MemberInfo;
757                                 FieldInfo fieldInfo = member as FieldInfo;
758                                 PropertyInfo propertyInfo = member as PropertyInfo;
759
760                                 Type attributeType;
761                                 object attributeValue;
762                                 string attributeValueString;
763                                 string attributeName;
764                                 string attributeNs;
765
766                                 if (fieldInfo != null) {
767                                         attributeValue = fieldInfo.GetValue (o);
768                                         attributeType = (attributeValue == null) ? fieldInfo.FieldType : attributeValue.GetType ();
769                                 }
770                                 else {
771                                         attributeValue = propertyInfo.GetValue (o, null);
772                                         attributeType = (attributeValue == null) ? propertyInfo.PropertyType : attributeValue.GetType ();
773                                 }
774
775                                 attributeName = xmlAttributes.GetAttributeName (attributeType, member.Name);
776                                 attributeNs = xmlAttributes.GetAttributeNamespace (attributeType);
777
778                                 if (attributeValue is XmlQualifiedName) {
779                                         XmlQualifiedName qname = (XmlQualifiedName) attributeValue;
780
781                                         if (qname.IsEmpty)
782                                                 continue;
783
784                                         writer.WriteStartAttribute (attributeName, attributeNs);
785                                         writer.WriteQualifiedName (qname.Name, qname.Namespace);
786                                         writer.WriteEndAttribute ();
787                                         continue;
788                                 }
789                                 else if (attributeValue is XmlQualifiedName[]) {
790                                         XmlQualifiedName[] qnames = (XmlQualifiedName[]) attributeValue;
791                                         writer.WriteStartAttribute (attributeName, attributeNs);
792                                         int count = 0;
793                                         foreach (XmlQualifiedName qname in qnames) {
794                                                 if (qname.IsEmpty)
795                                                         continue;
796                                                 if (count++ > 0)
797                                                         writer.WriteWhitespace (" ");
798                                                 writer.WriteQualifiedName (qname.Name, qname.Namespace);
799                                         }
800                                         writer.WriteEndAttribute ();
801                                         continue;
802                                 }
803                                 else if (attributeValue is XmlAttribute[]) {
804                                         XmlAttribute[] xmlattrs = (XmlAttribute[]) attributeValue;
805                                         foreach (XmlAttribute xmlattr in xmlattrs) {
806                                                 xmlattr.WriteTo(writer);
807                                         }
808                                         continue;
809                                 }
810
811                                 attributeValueString = GetXmlValue (attributeValue);
812                                 if (attributeValueString != GetXmlValue (xmlAttributes.XmlDefaultValue))
813                                         writer.WriteAttributeString (attributeName, attributeNs, attributeValueString);
814                         }
815
816                         // Serialize Elements
817                         foreach (XmlAttributes xmlElements in elements) {
818                                 MemberInfo member = xmlElements.MemberInfo;
819                                 FieldInfo fieldInfo = member as FieldInfo;
820                                 PropertyInfo propertyInfo = member as PropertyInfo;
821
822                                 Type elementType;
823                                 object elementValue;
824                                 string elementName;
825                                 string elementNs;
826
827                                 if (fieldInfo != null) {
828                                         elementValue = fieldInfo.GetValue (o);
829                                         elementType = (elementValue == null) ? fieldInfo.FieldType : elementValue.GetType ();
830                                 }
831                                 else {
832                                         elementValue = propertyInfo.GetValue (o, null);
833                                         elementType = (elementValue == null) ? propertyInfo.PropertyType : elementValue.GetType ();
834                                 }
835
836                                 if (elementType.GetInterface (typeof (ICollection).FullName) != null)
837                                         this.WriteCollectionElementMember (writer, member.Name, xmlElements, elementType, elementValue, namespaces);
838                                 else {
839                                         elementName = xmlElements.GetElementName (elementType, member.Name);
840                                         elementNs = xmlElements.GetElementNamespace (elementType);
841
842                                         if (elementValue == null &&
843                                                 !xmlElements.GetElementIsNullable (elementType))
844                                                 continue; // do not serialize
845                                         else
846                                                 WriteElement (writer, xmlElements, elementName, elementNs, elementType, elementValue, namespaces);
847                                 }
848                         }
849                 }
850
851                 private void WriteCollectionElementMember (XmlWriter writer, string elementDefaultName, XmlAttributes attrs, Type type, Object value, XmlSerializerNamespaces namespaces)
852                 {
853                         if (attrs.XmlElements != null && attrs.XmlElements.Count > 0)
854                                 SerializeCollectionContent (writer, attrs, type, value, namespaces);
855                         else {
856                                 string elementName;
857                                 string elementNs;
858                                 if (attrs.XmlArray != null) {
859                                         elementName = attrs.XmlArray.ElementName;
860                                         elementNs = attrs.XmlArray.Namespace;
861                                 } else {
862                                         elementName = attrs.GetElementName (type,elementDefaultName);
863                                         elementNs = attrs.GetElementNamespace (type);
864                                 }
865                                 WriteElement (writer, attrs, elementName, elementNs, type, value, namespaces);
866                         }
867                 }
868
869                 [MonoTODO ("Remove FIXMEs")]
870                 private void WriteElement (XmlWriter writer, XmlAttributes attrs, string name, string ns, Type type, Object value, XmlSerializerNamespaces namespaces)
871                 {
872                         //IF the element has XmlText Attribute, the name of the member is not serialized;
873                         if (attrs.XmlText != null && value != null)
874                         {
875                                 if (type == typeof (object[]))
876                                 {
877                                         foreach(object obj in (object[]) value)
878                                                 writer.WriteRaw(""+obj);
879                                 }
880                                 else if (type == typeof (string[]))
881                                 {
882                                         foreach(string str in (string[]) value)
883                                                 writer.WriteRaw(str);
884                                 }
885                                 else if (type == typeof (XmlNode))
886                                 {
887                                         ((XmlNode) value).WriteTo (writer);
888                                 }
889                                 else if (type == typeof (XmlNode[]))
890                                 {
891                                         XmlNode[] nodes = (XmlNode[]) value;
892                                         foreach (XmlNode node in nodes)
893                                                 node.WriteTo (writer);
894                                 }
895                                 return;
896                         }
897
898                         //If not text, serialize as an element
899
900                         //Start the element tag
901                         writer.WriteStartElement  (name, ns);
902
903                         if (IsInbuiltType (type))
904                         {
905                                 WriteBuiltinValue(writer,value);
906                         }
907                         else if (type.IsArray && value != null)
908                         {
909                                 SerializeArrayContent (writer, value, namespaces);
910                         }
911                         else if (value is ICollection)
912                         {
913                                 SerializeCollectionContent (writer, attrs, type, value, namespaces);
914                         }
915                         else if (value is IEnumerable)
916                         {
917                                 // FIXME
918                                 throw new NotImplementedException ();
919                         }
920                         else if (type.IsEnum)
921                         {
922                                 writer.WriteString(GetXmlValue(value));
923                         }
924                         else
925                         { //Complex Type
926                                 SerializeMembers (writer, value, false, namespaces);
927                         }
928
929                         // Close the Element
930                         writer.WriteEndElement();
931                 }
932
933                 private void SerializeCollectionContent (XmlWriter writer, XmlAttributes attrs, Type type, object value, XmlSerializerNamespaces namespaces)
934                 {
935                         BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
936
937                         //Find a non indexer Count Property with return type of int
938                         PropertyInfo countInfo = type.GetProperty ("Count", flags, null, typeof (int), new Type[0], null);
939                         PropertyInfo itemInfo = type.GetProperty ("Item", flags, null, null, new Type[1] {typeof (int)}, null);
940                         int count = (int) countInfo.GetValue (value, null);
941
942                         if (count > 0) {
943                                 for (int i = 0; i < count; i++) {
944                                         object itemValue = itemInfo.GetValue (value, new object[1] {i});
945                                         Type   itemType  = itemInfo.PropertyType;
946
947                                         string itemName = attrs.GetElementName (itemValue != null ? itemValue.GetType () : itemType, typeTranslator.GetTypeData(itemType).ElementName);
948                                         string itemNs = attrs.GetElementNamespace (itemValue != null ? itemValue.GetType () : itemType);
949                                         if (itemValue != null) {
950                                                 writer.WriteStartElement (itemName, itemNs);
951                                                 SerializeMembers (writer, itemValue, false, namespaces);
952                                                 writer.WriteEndElement ();
953                                         } else {
954                                                 foreach (XmlElementAttribute elem in attrs.XmlElements) {
955                                                         if (elem.IsNullable) {
956                                                                 writer.WriteStartElement (itemName, itemNs);
957                                                                 WriteNilAttribute (writer);
958                                                                 writer.WriteEndElement ();
959                                                         }
960                                                 }
961                                         }
962                                 }
963                         }
964                 }
965
966                 //Does not take care of any array specific Xml Attributes
967                 [MonoTODO]
968                 private void SerializeArrayContent (XmlWriter writer, object o, XmlSerializerNamespaces namespaces)
969                 {
970                         Array arr = (o as Array);
971                         if(arr == null || arr.Rank != 1)
972                                 throw new ApplicationException("Expected a single dimension Array, Got "+ o);
973
974                         Type arrayType = arr.GetType().GetElementType();
975                         string arrayTypeName = typeTranslator.GetTypeData(arrayType).ElementName;
976
977                         TypeData td = typeTranslator.GetTypeData (arrayType);
978
979                         // Special Treatment for Byte array
980                         if(arrayType.Equals(typeof(byte)))
981                         {
982                                 WriteBuiltinValue(writer,o);
983                         }
984                         else
985                         {
986                                 for(int i=0; i< arr.Length; i++)
987                                 {
988                                         writer.WriteStartElement (td.ElementName);
989                                         object value = arr.GetValue(i);
990                                         if (IsInbuiltType (arrayType))
991                                         {
992                                                 WriteBuiltinValue(writer, value);
993                                         }
994                                         else
995                                         {
996                                                 SerializeMembers(writer, value, false, namespaces);
997                                         }
998
999                                         writer.WriteEndElement();
1000                                 }
1001                         }
1002                 }
1003
1004                 private bool IsFieldTypeSerializable (FieldInfo fieldInfo)
1005                 {
1006                         //If field is readOnly or const, do not serialize it.
1007                         if (fieldInfo.IsLiteral || fieldInfo.IsInitOnly)
1008                                 return false;
1009                         // If no default constructor, do not serialize it.
1010                         if (!HasDefaultConstructor (fieldInfo.FieldType))
1011                                 return false;
1012                         return true;
1013                 }
1014
1015                 private bool IsTypeArrayOrSpecial (Type type)
1016                 {
1017                         return type.IsArray || 
1018                         Implements (type, typeof (ICollection)) ||
1019                         (type != typeof (string) && Implements (type, typeof (IEnumerable)));
1020                 }
1021
1022                 private bool IsPropertyTypeSerializable (PropertyInfo propertyInfo)
1023                 {
1024                         //If property is readonly or writeonly, do not serialize.
1025                         //Exceptions are properties whose return type is array,
1026                         //ICollection or IEnumerable.
1027                         //Indexers are not serialized unless the class 
1028                         //Implements ICollection.
1029                         if (!IsTypeArrayOrSpecial (propertyInfo.PropertyType)) {
1030                                 if(!(propertyInfo.CanRead && propertyInfo.CanWrite) ||
1031                                         propertyInfo.GetIndexParameters ().Length != 0)
1032                                         return false;
1033                         }
1034
1035                         return true;
1036                 }
1037
1038                 /// <summary>
1039                 /// If the type is a string, valuetype or primitive type we do not populate the TypeTable.
1040                 /// If the type is an array, we populate the TypeTable with Element type of the array.
1041                 /// If the type implements ICollection, it is handled differently. We do not care for its members.
1042                 /// If the type implements IEnumberable, we check that it implements Add(). Don't care for members.
1043                 /// </summary>
1044                 [MonoTODO ("Remove FIXMEs")]
1045                 private void FillTypeTable (Type type)
1046                 {
1047                         // If it's already in the table, don't add it again.
1048                         if (typeTable.Contains (type))
1049                                 return;
1050
1051                         //For value types and strings we don't need the members.
1052                         //FIXME: We will need the enum types probably.
1053                         if (IsInbuiltType (type))
1054                                 return;
1055
1056                         //Array, ICollection and IEnumberable are treated differenty
1057                         if (type.IsArray) {
1058                                 FillArrayType (type);
1059                                 return;
1060                         }
1061                         else if (type.IsEnum) {
1062                                 FillEnum (type);
1063                                 return;
1064                         }
1065                         else {
1066                                 //There must be a public constructor
1067                                 if (!HasDefaultConstructor (type) && !IsTypeArrayOrSpecial (type))
1068                                 throw new Exception ("Can't Serialize Type " + type.Name + " since it does not have default Constructor");
1069
1070                                 if (type.GetInterface ("ICollection") == typeof (System.Collections.ICollection)) {
1071                                         FillICollectionType (type);
1072                                         return;
1073                                 }
1074 //                              if (type.GetInterface ("IDictionary") == typeof (System.Collections.IDictionary)) {
1075 //                                      throw new Exception ("Can't Serialize Type " + type.Name + " since it implements IDictionary");
1076 //                              }
1077                                 if (type.GetInterface ("IEnumerable") == typeof (System.Collections.IEnumerable)) {
1078                                         //FillIEnumerableType(type);
1079                                         //return;
1080                                 }
1081                         }
1082
1083
1084                         //Add the Class to the hashtable.
1085                         //Each value of the hashtable has two objects, one is the hashtable with key of membername (for deserialization)
1086                         //Other is an Array of XmlSerializernames, Array of XmlAttributes & Array of XmlElements.
1087                         Hashtable memberTable = new Hashtable ();
1088                         ArrayList attributes = new ArrayList ();
1089                         ArrayList elements = new ArrayList ();
1090
1091                         TypeTableEntry entry = new TypeTableEntry (memberTable, null, elements, attributes);
1092                         typeTable.Add (type, entry);
1093
1094                         XmlAttributes resolvedAttributes = 
1095                                 attributeMapper.GetTypeAttributes (type);
1096                         memberTable.Add ("", resolvedAttributes);
1097
1098                         //Get the graph of the members. Graph is nothing but the order
1099                         //in which MS implementation serializes the members.
1100                         MemberInfo[] minfo = GetGraph (type);
1101
1102                         foreach (MemberInfo member in minfo) {
1103                                 FieldInfo fieldInfo = (member as FieldInfo);
1104                                 PropertyInfo propertyInfo = (member as PropertyInfo);
1105
1106                                 if (memberTable [member.Name] != null)
1107                                         continue;
1108
1109                                 if (fieldInfo != null) {
1110                                         if (!IsFieldTypeSerializable (fieldInfo))
1111                                                 continue;
1112
1113                                         XmlAttributes xmlAttributes = XmlAttributes.FromField (member, fieldInfo);
1114
1115                                         //If XmlAttributes have XmlIgnore, ignore this member
1116
1117                                         if (xmlAttributes.XmlIgnore)
1118                                                 continue;
1119
1120                                         //If this member is a XmlNs type, set the XmlNs object.
1121                                         if (xmlAttributes.Xmlns) {
1122                                                 entry.XmlAttributes = xmlAttributes;
1123                                                 continue;
1124                                         }
1125
1126                                         //If the member is a attribute Type, Add to attribute list
1127                                         if (xmlAttributes.isAttribute)
1128                                                 attributes.Add (xmlAttributes);
1129                                         else //Add to elements
1130                                                 elements.Add (xmlAttributes);
1131
1132                                         //Add in the Hashtable.
1133                                         memberTable.Add (member.Name, xmlAttributes);
1134
1135                                         if (xmlAttributes.XmlAnyAttribute != null  || xmlAttributes.XmlText != null)
1136                                                 continue;
1137
1138                                         if (xmlAttributes.XmlElements.Count > 0) {
1139                                                 foreach (XmlElementAttribute elem in xmlAttributes.XmlElements) {
1140                                                         if (elem.Type != null)
1141                                                                 FillTypeTable (elem.Type);
1142                                                         else
1143                                                                 FillTypeTable (fieldInfo.FieldType);
1144                                                 }
1145                                                 continue;
1146                                         }
1147
1148                                         if (!IsInbuiltType (fieldInfo.FieldType))
1149                                                 FillTypeTable (fieldInfo.FieldType);
1150                                 }
1151                                 else if (propertyInfo != null) {
1152
1153                                         XmlAttributes xmlAttributes = XmlAttributes.FromProperty (member, propertyInfo);
1154
1155                                         // If XmlAttributes have XmlIgnore, ignore this member
1156                                         if (xmlAttributes.XmlIgnore)
1157                                                 continue;
1158
1159                                         bool anySerializable = false;
1160                                         if (xmlAttributes.XmlIncludes != null) {
1161                                                 foreach (XmlIncludeAttribute inc in xmlAttributes.XmlIncludes) {
1162                                                         if (HasDefaultConstructor (inc.Type)) {
1163                                                                 anySerializable = true;
1164                                                                 FillTypeTable (inc.Type);
1165                                                         }
1166                                                 }
1167                                         }
1168                                         // If property's Types (containing any
1169                                         // included types) have no default 
1170                                         // constructor, do not serialize it.
1171                                         if (!IsPropertyTypeSerializable (propertyInfo) && !HasDefaultConstructor (propertyInfo.PropertyType) && !anySerializable)
1172                                                         continue;
1173
1174                                         // If this member is a XmlNs type, set the XmlNs object.
1175                                         if (xmlAttributes.Xmlns) {
1176                                                 entry.XmlAttributes = xmlAttributes;
1177                                                 continue;
1178                                         }
1179                                         // If the member is a attribute Type, Add to attribute list
1180                                         if (xmlAttributes.isAttribute)
1181                                                 attributes.Add (xmlAttributes);
1182                                         else  //Add to elements
1183                                                 elements.Add (xmlAttributes);
1184
1185                                         // OtherWise add in the Hashtable.
1186                                         memberTable.Add (member.Name, xmlAttributes);
1187
1188                                         if (xmlAttributes.XmlAnyAttribute != null || xmlAttributes.XmlText != null)
1189                                                 continue;
1190
1191                                         if (xmlAttributes.XmlElements.Count > 0) {
1192                                                 foreach (XmlElementAttribute elem in xmlAttributes.XmlElements) {
1193                                                         if (elem.Type != null)
1194                                                                 FillTypeTable (elem.Type);
1195                                                         else
1196                                                                 FillTypeTable (propertyInfo.PropertyType);
1197                                                 }
1198                                                 continue;
1199                                         }
1200
1201                                         if (!IsInbuiltType (propertyInfo.PropertyType))
1202                                                 FillTypeTable (propertyInfo.PropertyType);
1203                                 }
1204                         }
1205
1206                         // Sort the attributes for the members according to their Order
1207                         // This is an extension to MS's Implementation and will be useful
1208                         // if our reflection does not return the same order of elements
1209                         // as MS .NET impl
1210                         if (useOrder)
1211                                 BubbleSort (elements, XmlAttributes.attrComparer);
1212                 }
1213
1214                 private void FillArrayType (Type type)
1215                 {
1216                         if (type.GetArrayRank () != 1)
1217                                 throw new Exception ("MultiDimensional Arrays are not Supported");
1218
1219                         Type arrayType = type.GetElementType ();
1220
1221                         if (arrayType.IsArray)
1222                                 FillArrayType (arrayType);
1223                         else if (!IsInbuiltType (arrayType))
1224                                 FillTypeTable (arrayType);
1225                 }
1226
1227                 private void FillICollectionType (Type type)
1228                 {
1229                         //Must have an public Indexer that takes an integer and
1230                         //a public Count Property which returns an int.
1231
1232                         BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
1233
1234                         //Find a non indexer Count Property with return type of int
1235                         PropertyInfo countProp = type.GetProperty ("Count", flags, null, typeof (int), new Type[0], null);
1236                         if (countProp == null || !countProp.CanRead)
1237                                 throw new Exception ("Cannot Serialize " + type + " because it implements ICollectoion, but does not implement public Count property");
1238                         //Find a indexer Item Property which takes an int
1239                         PropertyInfo itemProp = type.GetProperty ("Item", flags, null, null, new Type[1] {typeof (int)}, null);
1240                         if (itemProp == null || !itemProp.CanRead || !itemProp.CanWrite)
1241                                 throw new Exception ("Cannot Serialize " + type + " because it does not have a read/write indexer property that takes an int as argument");
1242                         if (HasDefaultConstructor (itemProp.PropertyType))
1243                                 FillTypeTable (itemProp.PropertyType);
1244
1245                         XmlAttributes typeAtts = new XmlAttributes (type);
1246                         ArrayList includes = typeAtts.XmlIncludes;
1247                         if (includes != null) {
1248                                 foreach (XmlIncludeAttribute i in includes)
1249                                         FillTypeTable (i.Type);
1250                         }
1251                 }
1252
1253                 [MonoTODO]
1254                 private void FillIEnumerableType (Type type)
1255                 {
1256                         //Must implement a public Add method that takes a single parameter.
1257                         //The Add method's parameter must be of the same type as is returned from
1258                         //the Current property on the value returned from GetEnumerator, or one of that type's bases.
1259
1260                         // We currently ignore enumerable types anyway, so this method was junked.
1261                         // The code did not do what the documentation above says (if that is even possible!)
1262                         return;
1263                 }
1264
1265                 private void FillEnum (Type type)
1266                 {
1267                         Hashtable memberTable = new Hashtable ();
1268                         TypeTableEntry entry = new TypeTableEntry (memberTable, null, null, null);
1269                         BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
1270                         if (typeTable [type] == null)
1271                                 typeTable.Add (type, entry);
1272                         string[] names = Enum.GetNames (type);
1273
1274                         foreach (string name in names) {
1275                                 MemberInfo[] members = type.GetMember (name);
1276                                 if (members.Length != 1)
1277                                         throw new Exception("Should never happen. Enum member not present or more than one. " + name);
1278                                 XmlAttributes xmlAttributes = new XmlAttributes (members[0]);
1279
1280                                 if (xmlAttributes.XmlIgnore)
1281                                         continue;
1282
1283                                 if (xmlAttributes.XmlEnum != null)
1284                                         memberTable.Add (members[0].Name, xmlAttributes.XmlEnum.Name);
1285                                 else
1286                                         memberTable.Add (members[0].Name, members[0].Name);
1287                         }
1288                 }
1289
1290                 private bool HasDefaultConstructor (Type type)
1291                 {
1292                         ConstructorInfo defaultConstructor = type.GetConstructor (new Type[0]);
1293                         if (defaultConstructor == null || defaultConstructor.IsAbstract || defaultConstructor.IsStatic || !defaultConstructor.IsPublic)
1294                                 return false;
1295
1296                         return true;
1297                 }
1298
1299                 private bool IsInbuiltType (Type type)
1300                 {
1301                         if (type.IsEnum)
1302                                 return false;
1303                         if (/* type.IsValueType || */type == typeof (string) || type.IsPrimitive)
1304                                 return true;
1305                         if (type == typeof (DateTime) ||
1306                             type == typeof (Guid)     ||
1307                             type == typeof (XmlQualifiedName) ||
1308                             type == typeof (XmlNode)  ||
1309                             type.IsSubclassOf (typeof (XmlNode)))
1310                                 return true;
1311
1312                         return false;
1313                 }
1314
1315                 private static MemberInfo[] GetGraph(Type type)
1316                 {
1317                         ArrayList typeGraph = new ArrayList ();
1318                         GetGraph (type, typeGraph);
1319                         return (MemberInfo[]) typeGraph.ToArray (typeof (MemberInfo));
1320                 }
1321
1322                 private static void GetGraph (Type type, ArrayList typeGraph)
1323                 {
1324                         BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
1325                         if (type.BaseType == null)
1326                                 return;
1327                         GetGraph (type.BaseType, typeGraph);
1328
1329                         typeGraph.AddRange (type.GetFields (flags));
1330                         typeGraph.AddRange (type.GetProperties (flags));
1331                 }
1332
1333                 private string GetXmlValue (object value)
1334                 {
1335                         if (value == null)
1336                                 return null;
1337 #region enum type
1338                         if (value is Enum)
1339                         {
1340                                 Type type = value.GetType ();
1341
1342                                 TypeTableEntry entry = typeTable [type];
1343                                 if (entry != null) {
1344                                         Hashtable memberTable = entry.MemberTable;
1345                                         if (type.IsDefined (typeof (FlagsAttribute), false)) {
1346                                                 //If value is exactly a single enum member
1347                                                 if (memberTable.Contains (value.ToString ()))
1348                                                         return (string) memberTable[value.ToString ()];
1349
1350                                                 string retval = "";
1351                                                 int enumval = (int) value;
1352                                                 string[] names = Enum.GetNames (type);
1353
1354                                                 foreach (string key in names) {
1355                                                         if (!memberTable.ContainsKey (key))
1356                                                                 continue;
1357
1358                                                         //Otherwise multiple values.
1359                                                         int val = (int) Enum.Parse (type, key);
1360                                                         if (val != 0 && (enumval & val) == val)
1361                                                                 retval += " " + (string) memberTable[Enum.GetName (type, val)];
1362                                                 }
1363
1364                                                 retval = retval.Trim ();
1365
1366                                                 if (retval.Length == 0)
1367                                                         return null;
1368
1369                                                 return retval;
1370                                         }
1371                                         else if (memberTable.ContainsKey (value.ToString ()))
1372                                                 return (string) memberTable[value.ToString()];
1373                                         else
1374                                                 return null;
1375                                 }
1376                                 else
1377                                         throw new Exception ("Unknown Enumeration");
1378                         }
1379 #endregion
1380                         if (value is byte[])
1381                                 return XmlCustomFormatter.FromByteArrayBase64((byte[])value);
1382                         if (value is Guid)
1383                                 return XmlConvert.ToString((Guid)value);
1384                         if(value is DateTime)
1385                                 return XmlConvert.ToString((DateTime)value);
1386                         if(value is TimeSpan)
1387                                 return XmlConvert.ToString((TimeSpan)value);
1388                         if(value is bool)
1389                                 return XmlConvert.ToString((bool)value);
1390                         if(value is byte)
1391                                 return XmlConvert.ToString((byte)value);
1392                         if(value is char)
1393                                 return XmlCustomFormatter.FromChar((char)value);
1394                         if(value is decimal)
1395                                 return XmlConvert.ToString((decimal)value);
1396                         if(value is double)
1397                                 return XmlConvert.ToString((double)value);
1398                         if(value is short)
1399                                 return XmlConvert.ToString((short)value);
1400                         if(value is int)
1401                                 return XmlConvert.ToString((int)value);
1402                         if(value is long)
1403                                 return XmlConvert.ToString((long)value);
1404                         if(value is sbyte)
1405                                 return XmlConvert.ToString((sbyte)value);
1406                         if(value is float)
1407                                 return XmlConvert.ToString((float)value);
1408                         if(value is ushort)
1409                                 return XmlConvert.ToString((ushort)value);
1410                         if(value is uint)
1411                                 return XmlConvert.ToString((uint)value);
1412                         if(value is ulong)
1413                                 return XmlConvert.ToString((ulong)value);
1414                         if (value is XmlQualifiedName) {
1415                                 if (((XmlQualifiedName) value).IsEmpty)
1416                                         return null;
1417                         }
1418                         return (value == null) ? null : value.ToString ();
1419                 }
1420
1421                 [MonoTODO ("Remove FIXMEs")]
1422                 private static void ProcessAttributes (XmlAttributes attrs, Hashtable memberTable)
1423                 {
1424                         if (attrs.XmlAnyAttribute != null) {
1425                                 // FIXME
1426                         }
1427                         foreach (XmlAnyElementAttribute anyelem in attrs.XmlAnyElements)
1428                         memberTable.Add (new XmlQualifiedName (anyelem.Name, anyelem.Namespace), attrs);
1429
1430                         if (attrs.XmlArray != null) {
1431                                 // FIXME
1432                         }
1433
1434                         foreach (XmlArrayItemAttribute item in attrs.XmlArrayItems)
1435                         memberTable.Add (new XmlQualifiedName (item.ElementName, item.Namespace), attrs);
1436
1437                         if (attrs.XmlAttribute != null)
1438                                 memberTable.Add (new XmlQualifiedName (attrs.XmlAttribute.AttributeName,attrs.XmlAttribute.Namespace), attrs);
1439
1440                         if (attrs.XmlChoiceIdentifier != null) {
1441                                 // FIXME
1442                         }
1443
1444                         foreach (XmlElementAttribute elem in attrs.XmlElements)
1445                         memberTable.Add (new XmlQualifiedName (elem.ElementName, elem.Namespace), attrs);
1446
1447                         if (attrs.XmlEnum != null) {
1448                                 // FIXME
1449                         }
1450
1451                         if (attrs.XmlType != null)
1452                                 memberTable.Add (new XmlQualifiedName (attrs.XmlType.TypeName, attrs.XmlType.Namespace), attrs);
1453                 }
1454
1455                 private bool Implements (Type type, Type interfaceType)
1456                 {
1457                         return (type.GetInterface (interfaceType.Name) == interfaceType);
1458                 }
1459
1460                 private static void BubbleSort (ArrayList array, IComparer comparer)
1461                 {
1462                         array.Sort (comparer);
1463 /*
1464                         int len = array.Count;
1465                         object obj1, obj2;
1466                         for (int i=0; i < len; i++) {
1467                                 for (int j=0; j < len -i -1; j++) {
1468                                         obj1 = array[j];
1469                                         obj2 = array[j+1];
1470                                         if (comparer.Compare (obj2 , obj1 ) < 0) {
1471                                                 array[j] = obj2;
1472                                                 array[j+1] = obj1;
1473                                         }
1474                                 }
1475                         }
1476 */
1477                 }
1478 #endregion // Methods
1479         }
1480 }