2002-07-05 Ajay kumar Dwivedi <adwiv@yahoo.com>
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSerializer.cs
1 //
2 // XmlSerializer.cs: 
3 //
4 // Author:
5 //   John Donagher (john@webmeta.com)
6 //       Ajay kumar Dwivedi (adwiv@yahoo.com)
7 // (C) 2002 John Donagher, Ajay kumar Dwivedi
8 // 
9
10 using System.Xml.Serialization;\r
11 using System.Xml;\r
12 using System.IO;\r
13 using System;\r
14 using System.Collections;\r
15 using System.Reflection;\r
16 \r
17 namespace System.Xml.Serialization\r
18 {       \r
19         /// <summary>\r
20         /// Summary description for XmlSerializer.\r
21         /// </summary>
22         public class XmlSerializer\r
23         {\r
24                 private Type type;\r
25                 private XmlAttributeOverrides overrides;\r
26                 private Type[] extraTypes;\r
27                 private XmlRootAttribute rootAttribute;\r
28                 private string defaultNamespace;\r
29                 private static Hashtable typeTable;\r
30                 private bool useOrder;\r
31                 \r
32                 private bool isNullable;\r
33 \r
34                 public bool UseOrder\r
35                 {\r
36                         get{ return  useOrder; }\r
37                         set{ useOrder = value; }\r
38                 }\r
39 \r
40                 #region constructors\r
41                 protected XmlSerializer ()\r
42                 {\r
43                 }\r
44 \r
45                 public XmlSerializer (Type type)\r
46                         : this(type, null, null, null, null)\r
47                 {}\r
48 \r
49                 [MonoTODO]\r
50                 public XmlSerializer (XmlTypeMapping xmltypemapping)\r
51                 {}\r
52 \r
53                 public XmlSerializer (Type type, string defaultNamespace)\r
54                         : this(type, null, null, null, defaultNamespace)\r
55                 {}\r
56 \r
57                 public XmlSerializer (Type type, Type[] extraTypes)\r
58                         : this(type, null, extraTypes, null, null)\r
59                 {}\r
60 \r
61                 public XmlSerializer (Type type, XmlAttributeOverrides overrides)\r
62                         : this(type, overrides, null, null, null)\r
63                 {}\r
64 \r
65                 public XmlSerializer (Type type, XmlRootAttribute root)\r
66                         : this(type, null, null, root, null)\r
67                 {}\r
68 \r
69                 internal XmlSerializer(Hashtable typeTable)\r
70                 {\r
71                         typeTable = typeTable;\r
72                 }\r
73 \r
74                 public XmlSerializer (Type type, XmlAttributeOverrides overrides, Type[] extraTypes, XmlRootAttribute root, string defaultNamespace)\r
75                 {\r
76                         if(type == null)\r
77                                 throw new ArgumentNullException("type", "XmlSerializer can't be consturcted with a null type");\r
78                         this.type = type;\r
79 \r
80                         this.overrides = overrides;\r
81 \r
82                         this.extraTypes = (extraTypes == null ? new Type[0] : extraTypes);\r
83                         \r
84                         this.rootAttribute      = root;\r
85                         \r
86                         this.defaultNamespace = defaultNamespace;\r
87 \r
88                         if(typeTable == null)\r
89                                 typeTable = new Hashtable();\r
90 \r
91                         FillTypeTable(type);\r
92                 }\r
93                 #endregion\r
94                 #region Events\r
95                 [MonoTODO]
96                 public event XmlAttributeEventHandler UnknownAttribute;\r
97                 [MonoTODO]
98                 public event XmlElementEventHandler UnknownElement;\r
99                 [MonoTODO]
100                 public event XmlNodeEventHandler UnknownNode;\r
101                 [MonoTODO]
102                 public event UnreferencedObjectEventHandler UnreferencedObject;\r
103                 #endregion              \r
104                 #region Deserialize\r
105                 [MonoTODO]
106                 public virtual bool CanDeserialize (XmlReader xmlReader)\r
107                 {\r
108                         throw new NotImplementedException ();\r
109                 }\r
110                 [MonoTODO]
111                 public object Deserialize (Stream stream)\r
112                 {\r
113                         throw new NotImplementedException ();\r
114                 }\r
115                 [MonoTODO]
116                 public object Deserialize (TextReader textReader)\r
117                 {\r
118                         throw new NotImplementedException ();\r
119                 }\r
120                 [MonoTODO]
121                 public object Deserialize (XmlReader xmlReader)\r
122                 {\r
123                         throw new NotImplementedException ();\r
124                 }\r
125                 #endregion\r
126                 #region Serialize Delegates\r
127                 public void Serialize (Stream stream, object o)\r
128                 {\r
129                         XmlTextWriter xmlWriter = new XmlTextWriter(stream, System.Text.Encoding.Default);\r
130                         xmlWriter.Formatting = Formatting.Indented;\r
131                         Serialize(xmlWriter, o, null);\r
132                 }\r
133                 
134                 public void Serialize (TextWriter textWriter, object o)\r
135                 {\r
136                         XmlTextWriter xmlWriter = new XmlTextWriter(textWriter);\r
137                         xmlWriter.Formatting = Formatting.Indented;\r
138                         Serialize(xmlWriter, o, null);\r
139                 }\r
140                 
141                 public void Serialize (XmlWriter xmlWriter, object o)\r
142                 {\r
143                         Serialize(xmlWriter, o);\r
144                 }\r
145                 
146                 public void Serialize (Stream stream, object o, XmlSerializerNamespaces namespaces)\r
147                 {\r
148                         XmlTextWriter xmlWriter = new XmlTextWriter(stream, System.Text.Encoding.Default);\r
149                         xmlWriter.Formatting = Formatting.Indented;\r
150                         Serialize(xmlWriter, o, namespaces);\r
151                 }\r
152                 
153                 public void Serialize (TextWriter textWriter, object o, XmlSerializerNamespaces namespaces)\r
154                 {\r
155                         XmlTextWriter xmlWriter = new XmlTextWriter(textWriter);\r
156                         xmlWriter.Formatting = Formatting.Indented;\r
157                         Serialize(xmlWriter, o, namespaces);\r
158                 }\r
159                 #endregion 
160
161                 public void Serialize (XmlWriter writer, object o, XmlSerializerNamespaces namespaces)\r
162                 {       \r
163                         if(namespaces == null)\r
164                         {\r
165                                 namespaces = new XmlSerializerNamespaces();\r
166                         }\r
167                         if(namespaces.Count == 0)\r
168                         {\r
169                                 namespaces.Add("xsd", System.Xml.Schema.XmlSchema.Namespace);\r
170                                 namespaces.Add("xsi", System.Xml.Schema.XmlSchema.InstanceNamespace);\r
171                         }\r
172 \r
173                         Type objType = o.GetType();\r
174                         string rootName = objType.Name;\r
175                         string rootNs   = null;\r
176                         XmlSerializerNamespaces nss = new XmlSerializerNamespaces();\r
177                         XmlQualifiedName[] qnames;\r
178 \r
179                         writer.WriteStartDocument();\r
180                         \r
181                         object[] memberObj = (object[])typeTable[objType];\r
182                         if(memberObj == null)\r
183                                 throw new Exception("Unknown Type "+objType+" encounterd during Serialization");\r
184                         Hashtable memberTable = (Hashtable)memberObj[0];\r
185 \r
186                         XmlAttributes attrs = (XmlAttributes)memberTable[""];\r
187                         //If we have been passed an XmlRoot, set it on the base class\r
188                         if(rootAttribute != null)\r
189                                 attrs.XmlRoot = rootAttribute;\r
190                         \r
191                         if(attrs.XmlRoot != null)\r
192                         {\r
193                                 isNullable = attrs.XmlRoot.IsNullable;\r
194                                 if(attrs.XmlRoot.ElementName != null)\r
195                                         rootName = attrs.XmlRoot.ElementName;\r
196                                 rootNs  = attrs.XmlRoot.Namespace;\r
197                         }\r
198 \r
199                         //XMLNS attributes in the Root\r
200                         XmlAttributes XnsAttrs = (XmlAttributes)((object[])typeTable[objType])[1];\r
201                         if(XnsAttrs != null)\r
202                         {\r
203                                 MemberInfo member = XnsAttrs.MemberInfo;\r
204                                 FieldInfo fInfo = member as FieldInfo;\r
205                                 PropertyInfo propInfo = member as PropertyInfo;\r
206                                 XmlSerializerNamespaces xns;\r
207                                 if(fInfo != null)\r
208                                         xns = (XmlSerializerNamespaces) fInfo.GetValue(o);\r
209                                 else\r
210                                         xns = (XmlSerializerNamespaces) propInfo.GetValue(o,null);\r
211                                 \r
212                                 qnames = xns.ToArray();\r
213                                 foreach(XmlQualifiedName qname in qnames)\r
214                                 {\r
215                                         nss.Add(qname.Name, qname.Namespace);\r
216                                 }                               \r
217                         }\r
218                         //XmlNs from the namespaces passed\r
219                         qnames = namespaces.ToArray();\r
220                         foreach(XmlQualifiedName qname in qnames)\r
221                         {\r
222                                 if(writer.LookupPrefix(qname.Namespace) != qname.Name)\r
223                                 {\r
224                                         nss.Add(qname.Name, qname.Namespace);\r
225                                 }\r
226                         }\r
227 \r
228                         if(namespaces.GetPrefix(rootNs) != null)\r
229                                 writer.WriteStartElement(namespaces.GetPrefix(rootNs),rootName, rootNs);\r
230 \r
231                         qnames = nss.ToArray();\r
232                         foreach(XmlQualifiedName qname in qnames)\r
233                         {\r
234                                 if(writer.LookupPrefix(qname.Namespace) != qname.Name)\r
235                                 {\r
236                                         writer.WriteAttributeString("xmlns", qname.Name, null, qname.Namespace);\r
237                                 }\r
238                         }\r
239 \r
240                         SerializeMembers(writer, o, true);//, namespaces);\r
241                         writer.WriteEndElement();\r
242                 }\r
243 \r
244                 private void SerializeMembers ( XmlWriter writer, object o, bool isRoot)\r
245                 {\r
246                         Type objType = o.GetType();\r
247                         XmlAttributes XnsAttrs = (XmlAttributes)((object[])typeTable[objType])[1];\r
248                         ArrayList attrList = (ArrayList)((object[])typeTable[objType])[2];\r
249                         ArrayList elemList = (ArrayList)((object[])typeTable[objType])[3];\r
250 \r
251                         if(!isRoot && XnsAttrs != null)\r
252                         {\r
253                                 MemberInfo member = XnsAttrs.MemberInfo;\r
254                                 FieldInfo fInfo = member as FieldInfo;\r
255                                 PropertyInfo propInfo = member as PropertyInfo;\r
256                                 XmlSerializerNamespaces xns;\r
257                                 if(fInfo != null)\r
258                                         xns = (XmlSerializerNamespaces) fInfo.GetValue(o);\r
259                                 else\r
260                                         xns = (XmlSerializerNamespaces) propInfo.GetValue(o,null);\r
261                                 \r
262                                 XmlQualifiedName[] qnames = xns.ToArray();\r
263                                 foreach(XmlQualifiedName qname in qnames)\r
264                                 {\r
265                                         if(writer.LookupPrefix(qname.Namespace) != qname.Name)\r
266                                                 writer.WriteAttributeString("xmlns", qname.Name, null, qname.Namespace);\r
267                                 }\r
268                         }\r
269 \r
270                         //Serialize the Attributes.\r
271                         foreach(XmlAttributes attrs in attrList)\r
272                         {\r
273                                 MemberInfo member = attrs.MemberInfo;\r
274                                 FieldInfo fInfo = member as FieldInfo;\r
275                                 PropertyInfo propInfo = member as PropertyInfo;\r
276                                 Type attributeType;\r
277                                 object attributeValue;\r
278                                 string attributeValString;\r
279                                 string attributeName;\r
280                                 string attributeNs;\r
281 \r
282                                 if(fInfo != null)\r
283                                 {\r
284                                         attributeType  = fInfo.FieldType;\r
285                                         attributeValue = fInfo.GetValue(o);\r
286                                 } \r
287                                 else if(propInfo != null)\r
288                                 {\r
289                                         attributeType  = propInfo.PropertyType;\r
290                                         attributeValue = propInfo.GetValue(o,null);\r
291                                 }\r
292                                 else\r
293                                         throw new Exception("Should never Happen. Neither field or property");\r
294 \r
295                                 attributeName = attrs.GetAttributeName(attributeType, member.Name);\r
296                                 attributeNs       = attrs.GetAttributeNamespace(attributeType);\r
297                         \r
298                                 if(attributeValue is XmlQualifiedName)\r
299                                 {\r
300                                         XmlQualifiedName qname = (XmlQualifiedName) attributeValue;\r
301                                         if(qname.IsEmpty)\r
302                                                 continue;\r
303                                         writer.WriteStartAttribute(attributeName, attributeNs);\r
304                                         writer.WriteQualifiedName(qname.Name, qname.Namespace);\r
305                                         writer.WriteEndAttribute();\r
306                                         continue;\r
307                                 }\r
308 \r
309                                 else if(attributeValue is XmlQualifiedName[])\r
310                                 {\r
311                                         XmlQualifiedName[] qnames = (XmlQualifiedName[]) attributeValue;\r
312                                         writer.WriteStartAttribute(attributeName, attributeNs);\r
313                                         int count = 0;\r
314                                         foreach(XmlQualifiedName qname in qnames)\r
315                                         {\r
316                                                 if(qname.IsEmpty)\r
317                                                         continue;\r
318                                                 if(count++ > 0)\r
319                                                         writer.WriteWhitespace(" ");\r
320                                                 writer.WriteQualifiedName(qname.Name, qname.Namespace);\r
321                                         }\r
322                                         writer.WriteEndAttribute();\r
323                                         continue;\r
324                                 }\r
325                                 else if(attributeValue is XmlAttribute[])\r
326                                 {\r
327                                         XmlAttribute[] xmlattrs = (XmlAttribute[]) attributeValue;\r
328                                         foreach(XmlAttribute xmlattr in xmlattrs)\r
329                                                 xmlattr.WriteTo(writer);\r
330                                         continue;\r
331                                 }\r
332                                 attributeValString = GetXmlValue(attributeValue);\r
333 \r
334                                 if(attributeValString != GetXmlValue(attrs.XmlDefaultValue))\r
335                                 {\r
336                                                 writer.WriteAttributeString(attributeName, attributeNs, attributeValString);\r
337                                 }\r
338                         }\r
339 \r
340                         //Serialize Elements\r
341                         foreach(XmlAttributes attrs in elemList)\r
342                         {\r
343                                 MemberInfo member       = attrs.MemberInfo;\r
344                                 FieldInfo fInfo         = member as FieldInfo;\r
345                                 PropertyInfo propInfo = member as PropertyInfo;\r
346                                 Type    elementType;\r
347                                 object  elementValue;\r
348                                 string  elementName;\r
349                                 string  elementNs;\r
350 \r
351                                 if(fInfo != null)\r
352                                 {\r
353                                         elementType = fInfo.FieldType;\r
354                                         elementValue = fInfo.GetValue(o);\r
355                                 }\r
356                                 else if(propInfo != null)\r
357                                 {\r
358                                         elementType  = propInfo.PropertyType;\r
359                                         elementValue = propInfo.GetValue(o,null);\r
360                                 }\r
361                                 else throw new Exception("should never happpen. Element is neither field nor property");\r
362 \r
363                                 elementName = attrs.GetElementName(elementType, member.Name);\r
364                                 elementNs       = attrs.GetElementNamespace(elementType);\r
365 \r
366                                 WriteElement(writer, attrs, elementName, elementNs, elementType, elementValue);\r
367                         }\r
368                 }\r
369 \r
370                 private void WriteElement(XmlWriter writer, XmlAttributes attrs, \r
371                         string name, string ns, Type type, Object value)\r
372                 {\r
373                         if(IsInbuiltType(type))\r
374                         {\r
375                                 writer.WriteElementString(name, ns,  "" + GetXmlValue(value));\r
376                         }\r
377                         else if(attrs.XmlText != null && value != null)\r
378                         {\r
379                                 if(type == typeof(object[]))\r
380                                 {\r
381                                 }\r
382                                 else if(type == typeof(string[]))\r
383                                 {\r
384                                 }\r
385                                 else if(type == typeof(XmlNode))\r
386                                 {\r
387                                         ((XmlNode)value).WriteTo(writer);\r
388                                 }\r
389                                 else if(type == typeof(XmlNode[]))\r
390                                 {\r
391                                         XmlNode[] nodes = (XmlNode[])value;\r
392                                         foreach(XmlNode node in nodes)\r
393                                                 node.WriteTo(writer);\r
394                                 }\r
395                         }\r
396                         else if(type.IsArray && value != null)\r
397                         {\r
398                                 writer.WriteStartElement(name, ns);\r
399                                 SerializeArray(writer, value);\r
400                                 writer.WriteEndElement();\r
401                         }\r
402                         else if(value is ICollection)\r
403                         {\r
404                                 BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;\r
405                                 //Find a non indexer Count Property with return type of int\r
406                                 PropertyInfo countProp = type.GetProperty("Count", flags, null, typeof(int),new Type[0], null);\r
407                                 PropertyInfo itemProp = type.GetProperty("Item", flags, null, null, new Type[1]{typeof(int)}, null);\r
408                                 int count = (int)countProp.GetValue(value,null);\r
409                                 object[] items = new object[1];\r
410 \r
411                                 if(count > 0)\r
412                                 {\r
413                                         for(int i=0;i<count;i++)\r
414                                         {\r
415                                                 items[0] = i;\r
416                                                 object itemval = itemProp.GetValue(value, items);\r
417                                                 string itemName;\r
418                                                 string itemNs; \r
419                                                 if(itemval != null)\r
420                                                 {\r
421                                                         itemName = attrs.GetElementName(itemval.GetType(), name);\r
422                                                         itemNs  = attrs.GetElementNamespace(itemval.GetType());\r
423                                                         writer.WriteStartElement(itemName, itemNs);\r
424                                                         SerializeMembers(writer, itemval, false);\r
425                                                         writer.WriteEndElement();\r
426                                                 }\r
427                                         }\r
428                                 }\r
429                         }\r
430                         else if(value is IEnumerable)\r
431                         {\r
432 \r
433                         }\r
434                         else if(type.IsEnum)\r
435                         {\r
436 \r
437                         }\r
438                         else if(value != null) //Complex Type?\r
439                         {\r
440                                 string itemName = attrs.GetElementName(value.GetType(), name);\r
441                                 string itemNs   = attrs.GetElementNamespace(value.GetType());\r
442                                 writer.WriteStartElement(itemName, itemNs);\r
443                                 SerializeMembers(writer, value, false);\r
444                                 writer.WriteEndElement();\r
445                         }\r
446                         else\r
447                         {\r
448                         }\r
449                 }\r
450 \r
451                 private void SerializeArray( XmlWriter writer, object o)\r
452                 {\r
453 \r
454                 }\r
455 \r
456                 /// <summary>\r
457                 /// If the type is a string, valuetype or primitive type we do not populate the TypeTable.\r
458                 /// If the type is an array, we populate the TypeTable with Element type of the array.\r
459                 /// If the type implements ICollection, it is handled differently. We do not care for its members.\r
460                 /// If the type implements IEnumberable, we check that it implements Add(). Don't care for members.\r
461                 /// </summary>\r
462                 private void FillTypeTable(Type type)\r
463                 {\r
464                         if(typeTable.Contains(type))\r
465                                 return;\r
466 \r
467                         //For value types and strings we don't need the members.\r
468                         //FIXME: We will need the enum types probably.\r
469                         if(IsInbuiltType(type))\r
470                                 return;\r
471 \r
472                         //Array, ICollection and IEnumberable are treated differenty\r
473                         if(type.IsArray)\r
474                         {\r
475                                 FillArrayType(type);\r
476                                 return;\r
477                         }\r
478                         else if(type.IsEnum)\r
479                         {\r
480                                 FillEnum(type);\r
481                                 return;\r
482                         }\r
483                         else\r
484                         {\r
485                                 //There must be a public constructor\r
486                                 if(!HasDefaultConstructor(type))\r
487                                 {\r
488                                         throw new Exception("Can't Serialize Type " + type.Name + " since it does not have default Constructor");\r
489                                 }\r
490 \r
491                                 if(type.GetInterface("ICollection") == typeof(System.Collections.ICollection))\r
492                                 {\r
493                                         FillICollectionType(type);\r
494                                         return;\r
495                                 }\r
496                                 \r
497                                 if(type.GetInterface("IEnumerable") == typeof(System.Collections.IEnumerable))\r
498                                 {\r
499                                         FillIEnumerableType(type);\r
500                                         return;\r
501                                 }\r
502                         }\r
503                         \r
504                         //Add the Class to the hashtable.\r
505                         //Each value of the hashtable has two objects, one is the hashtable with key of membername (for deserialization)\r
506                         //Other is an Array of XmlSerializernames, Array of XmlAttributes & Array of XmlElements.\r
507                         Object[] memberObj = new Object[4];\r
508                         typeTable.Add(type,memberObj);\r
509 \r
510                         Hashtable memberTable = new Hashtable();\r
511                         memberObj[0] = memberTable;\r
512                         memberTable.Add("", XmlAttributes.FromClass(type));\r
513 \r
514                         memberObj[1] = null;\r
515 \r
516                         ArrayList attrList = new ArrayList();\r
517                         memberObj[2] = attrList;\r
518 \r
519                         ArrayList elemList = new ArrayList();\r
520                         memberObj[3] = elemList;\r
521 \r
522                         //Get the graph of the members. Graph is nothing but the order\r
523                         //in which MS implementation serializes the members.\r
524                         MemberInfo[] minfo = GetGraph(type);\r
525 \r
526                         foreach(MemberInfo member in minfo)\r
527                         {\r
528                                 FieldInfo fInfo = (member as FieldInfo);\r
529                                 PropertyInfo propInfo = (member as PropertyInfo);\r
530 \r
531                                 if(fInfo != null)\r
532                                 {\r
533                                         //If field is readOnly or const, do not serialize it.\r
534                                         if(fInfo.IsLiteral || fInfo.IsInitOnly)\r
535                                                 continue;\r
536 \r
537                                         XmlAttributes attrs  = XmlAttributes.FromField(member,fInfo);\r
538 \r
539                                         //If XmlAttributes have XmlIgnore, ignore this member\r
540                                         if(attrs.XmlIgnore)\r
541                                                 continue;\r
542                                         //If this member is a XmlNs type, set the XmlNs object.\r
543                                         if(attrs.Xmlns)\r
544                                         {\r
545                                                 memberObj[1] = attrs;\r
546                                                 continue;\r
547                                         }\r
548                                         //If the member is a attribute Type, Add to attribute list\r
549                                         if(attrs.isAttribute)\r
550                                                 attrList.Add(attrs);\r
551                                         else //Add to elements\r
552                                         {\r
553                                                 elemList.Add(attrs);\r
554                                         }\r
555                                         //Add in the Hashtable.\r
556                                         memberTable.Add(member.Name, attrs);\r
557                                         \r
558                                         Type fieldType = fInfo.FieldType;\r
559                                         \r
560                                         if(attrs.XmlAnyAttribute != null  || attrs.XmlText != null)\r
561                                                 continue;\r
562 \r
563                                         if(attrs.XmlElements.Count > 0)\r
564                                         {\r
565                                                 foreach(XmlElementAttribute elem in attrs.XmlElements)\r
566                                                 {\r
567                                                         if(elem.Type != null)\r
568                                                                 FillTypeTable(elem.Type);\r
569                                                         else\r
570                                                                 FillTypeTable(fieldType);\r
571                                                 }\r
572                                                 continue;\r
573                                         }\r
574 \r
575                                         if(!IsInbuiltType(fieldType))\r
576                                                 FillTypeTable(fieldType);\r
577                                 } \r
578                                 else if(propInfo != null)\r
579                                 {\r
580                                         //If property is readonly or writeonly, do not serialize it.\r
581                                         //Exceptions are properties whose return type is array, ICollection or IEnumerable\r
582                                         //Indexers are not serialized unless the class Implements ICollection.\r
583                                         if(!(propInfo.PropertyType.IsArray || Implements(propInfo.PropertyType,typeof(ICollection)) || \r
584                                                 (propInfo.PropertyType != typeof(string) && Implements(propInfo.PropertyType,typeof(IEnumerable)))))\r
585                                         {\r
586                                                 if(!(propInfo.CanRead && propInfo.CanWrite) || propInfo.GetIndexParameters().Length != 0)\r
587                                                         continue;\r
588                                         }\r
589                                         XmlAttributes attrs  = XmlAttributes.FromProperty(member,propInfo);\r
590                                         //If XmlAttributes have XmlIgnore, ignore this member\r
591                                         if(attrs.XmlIgnore)\r
592                                                 continue;\r
593 \r
594                                         //If this member is a XmlNs type, set the XmlNs object.\r
595                                         if(attrs.Xmlns)\r
596                                         {\r
597                                                 memberObj[1] = attrs;\r
598                                                 continue;\r
599                                         }\r
600                                         //If the member is a attribute Type, Add to attribute list\r
601                                         if(attrs.isAttribute)\r
602                                                 attrList.Add(attrs);\r
603                                         else  //Add to elements\r
604                                         {\r
605                                                 elemList.Add(attrs);\r
606                                         }\r
607 \r
608                                         //OtherWise add in the Hashtable.\r
609                                         memberTable.Add(member.Name, attrs);\r
610 \r
611                                         Type propType = propInfo.PropertyType;\r
612                                         \r
613                                         if(attrs.XmlAnyAttribute != null || attrs.XmlText != null)\r
614                                                 continue;\r
615 \r
616                                         if(attrs.XmlElements.Count > 0)\r
617                                         {\r
618                                                 foreach(XmlElementAttribute elem in attrs.XmlElements)\r
619                                                 {\r
620                                                         if(elem.Type != null)\r
621                                                                 FillTypeTable(elem.Type);\r
622                                                         else\r
623                                                                 FillTypeTable(propType);\r
624                                                 }\r
625                                                 continue;\r
626                                         }\r
627 \r
628                                         if(!IsInbuiltType(propType))\r
629                                                 FillTypeTable(propType);\r
630                                 }\r
631                         }\r
632                         //Sort the attributes for the members according to their Order\r
633                         //This is an extension to MS's Implementation and will be useful\r
634                         //if our reflection does not return the same order of elements\r
635                         //as MS .NET impl\r
636                         if(useOrder)\r
637                                 BubbleSort(elemList,XmlAttributes.attrComparer);\r
638                 }\r
639 \r
640                 private void FillArrayType(Type type)\r
641                 {\r
642                         if(!type.IsArray)\r
643                                 throw new Exception("Should never happen. Type is not an array");\r
644 \r
645                         if(type.GetArrayRank() != 1)\r
646                                 throw new Exception("MultiDimensional Arrays are not Supported");\r
647 \r
648                         Type arrayType = type.GetElementType();\r
649 \r
650                         if(arrayType.IsArray)\r
651                         {\r
652                                 FillArrayType(arrayType);\r
653                         }\r
654                         else if(!IsInbuiltType(arrayType))\r
655                         {\r
656                                 FillTypeTable(arrayType);\r
657                         }\r
658                 }\r
659 \r
660                 private void FillICollectionType(Type type)\r
661                 {\r
662                         //Must have an public Indexer that takes an integer and\r
663                         //a public Count Property which returns an int.\r
664 \r
665                         BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;\r
666                         \r
667                         //Find a non indexer Count Property with return type of int\r
668                         PropertyInfo countProp = type.GetProperty("Count", flags, null, typeof(int),new Type[0], null);\r
669                         if(countProp == null || !countProp.CanRead)\r
670                                 throw new Exception("Cannot Serialize "+type+" because it implements ICollectoion, but does not implement public Count property");\r
671                         //Find a indexer Item Property which takes an int\r
672                         PropertyInfo itemProp = type.GetProperty("Item", flags, null, null, new Type[1]{typeof(int)}, null);\r
673                         if(itemProp == null || !itemProp.CanRead || !itemProp.CanWrite)\r
674                                 throw new Exception("Cannot Serialize "+type+" because it does not have a read/write indexer property that takes an int as argument");\r
675                 }\r
676 \r
677                 private void FillIEnumerableType(Type type)\r
678                 {\r
679                         //Must implement a public Add method that takes a single parameter.\r
680                         //The Add method's parameter must be of the same type as is returned from \r
681                         // the Current property on the value returned from GetEnumerator, or one of that type's bases.\r
682                         BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;\r
683                         MethodInfo enumMethod = type.GetMethod("GetEnumerator", flags, null, new Type[0], null);\r
684                         if(enumMethod == null)\r
685                                 throw new Exception("Cannot serialize "+type+" because it does not implement GetEnumerator");\r
686 \r
687                         Type returnType = enumMethod.ReturnType;\r
688 \r
689                         while(returnType != null)\r
690                         {\r
691                                 MethodInfo addMethod = type.GetMethod("Add", flags, null, new Type[1]{returnType},null);\r
692                                 if(addMethod != null)\r
693                                         return;\r
694                                 returnType = returnType.BaseType;\r
695                         }\r
696                         \r
697                         throw new Exception("Cannot serialize "+type+" because it does not have a Add method which takes "\r
698                                         +enumMethod.ReturnType+" or one of its base types.");\r
699                 }\r
700 \r
701                 private void FillEnum(Type type)\r
702                 {\r
703                         Hashtable memberTable = new Hashtable();\r
704                         BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;\r
705                         typeTable.Add(type,memberTable);\r
706                         string[] names = Enum.GetNames(type);\r
707                         foreach(string name in names)\r
708                         {\r
709                                 MemberInfo[] members = type.GetMember(name);\r
710                                 if(members.Length != 1)\r
711                                         throw new Exception("Should never happen. Enum member not present or more than one. "+name);\r
712                                 XmlAttributes attrs = new XmlAttributes(members[0]);\r
713                                 if(attrs.XmlIgnore)\r
714                                         continue;\r
715                                 if(attrs.XmlEnum != null)\r
716                                 {\r
717                                         memberTable.Add(members[0].Name, attrs.XmlEnum.Name);\r
718                                 }\r
719                                 else\r
720                                 {\r
721                                         memberTable.Add(members[0].Name, members[0].Name);\r
722                                 }\r
723                         }\r
724                 }\r
725 \r
726                 private bool HasDefaultConstructor(Type type)\r
727                 {\r
728                         ConstructorInfo defaultConstructor = type.GetConstructor(new Type[0]);\r
729                         if(defaultConstructor == null || defaultConstructor.IsAbstract || defaultConstructor.IsStatic \r
730                                 || !defaultConstructor.IsPublic)\r
731                                 return false;\r
732                         \r
733                         return true;\r
734                 }\r
735 \r
736                 private bool IsInbuiltType(Type type)\r
737                 {\r
738                         if(type.IsEnum)\r
739                                 return false;\r
740                         if(type.IsValueType || type == typeof(string) || type.IsPrimitive)\r
741                                 return true;\r
742                         return false;\r
743                 }\r
744 \r
745                 private static MemberInfo[] GetGraph(Type type)\r
746                 {\r
747                         ArrayList typeGraph = new ArrayList();\r
748                         GetGraph(type, typeGraph);\r
749                         return (MemberInfo[]) typeGraph.ToArray(typeof(MemberInfo));\r
750                 }\r
751 \r
752                 private static void GetGraph(Type type, ArrayList typeGraph)\r
753                 {\r
754                         BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;\r
755                         if(type.BaseType == null)\r
756                                 return;\r
757                         GetGraph(type.BaseType,typeGraph);\r
758 \r
759                         typeGraph.AddRange(type.GetFields(flags));\r
760                         typeGraph.AddRange(type.GetProperties(flags));\r
761                 }\r
762 \r
763                 private string GetXmlValue(object value)\r
764                 {\r
765                         if(value == null)\r
766                                 return null;\r
767                         if(value is Enum)\r
768                         {\r
769                                 Type type = value.GetType();\r
770                                 \r
771                                 if(typeTable.ContainsKey(type))\r
772                                 {\r
773                                         Hashtable memberTable = (Hashtable)(typeTable[type]);\r
774                                         if(type.IsDefined(typeof(FlagsAttribute),false))\r
775                                         {\r
776                                                 //If value is exactly a single enum member\r
777                                                 if(memberTable.Contains(value.ToString()))\r
778                                                         return (string)memberTable[value.ToString()];\r
779 \r
780                                                 string retval = "";\r
781                                                 int count=0;\r
782                                                 int enumval = (int) value;\r
783                                                 string[] names = Enum.GetNames(type);\r
784                                                 foreach(string key in names)\r
785                                                 {\r
786                                                         if(!memberTable.ContainsKey(key))\r
787                                                                 continue;\r
788                                                         //Otherwise multiple values.\r
789                                                         int val = (int)Enum.Parse(type, key);\r
790                                                         if(val != 0 && (enumval & val) == val)\r
791                                                         {\r
792                                                                 retval += " " + (string)memberTable[Enum.GetName(type,val)];\r
793                                                         }\r
794                                                 }\r
795                                                 retval = retval.Trim();\r
796                                                 if(retval.Length == 0)\r
797                                                         return null;\r
798                                                 return retval;\r
799                                         }\r
800                                         else\r
801                                         {\r
802                                                 if(memberTable.ContainsKey(value.ToString()))\r
803                                                         return (string)memberTable[value.ToString()];\r
804                                                 else\r
805                                                         return null;\r
806                                         }\r
807                                 }\r
808                                 else\r
809                                 {\r
810                                         throw new Exception("Unknown Enumeration");\r
811                                 }\r
812                         }\r
813                         if(value is bool)\r
814                         {\r
815                                 return (bool)value ? "true" : "false";\r
816                         }\r
817                         if(value is XmlQualifiedName)\r
818                         {\r
819                                 if(((XmlQualifiedName)value).IsEmpty)\r
820                                         return null;\r
821                         }\r
822                         return (value==null) ? null : value.ToString();\r
823                 }\r
824 \r
825                 private static void ProcessAttributes(XmlAttributes attrs, Hashtable memberTable)\r
826                 {\r
827                         if(attrs.XmlAnyAttribute != null)\r
828                         {\r
829                         }\r
830                         foreach(XmlAnyElementAttribute anyelem in attrs.XmlAnyElements) \r
831                         {\r
832                                 memberTable.Add(new XmlQualifiedName(anyelem.Name, anyelem.Namespace), attrs);\r
833                         }\r
834                         if(attrs.XmlArray != null)\r
835                         {\r
836                         }\r
837                         foreach(XmlArrayItemAttribute item in attrs.XmlArrayItems)\r
838                         {\r
839                                 memberTable.Add(new XmlQualifiedName(item.ElementName, item.Namespace), attrs);\r
840                         }\r
841                         if(attrs.XmlAttribute != null)\r
842                         {\r
843                                 memberTable.Add(new XmlQualifiedName(attrs.XmlAttribute.AttributeName,attrs.XmlAttribute.Namespace), attrs);\r
844                         }\r
845                         if(attrs.XmlChoiceIdentifier != null)\r
846                         {\r
847                         }\r
848                         foreach(XmlElementAttribute elem in attrs.XmlElements)\r
849                         {\r
850                                 memberTable.Add(new XmlQualifiedName(elem.ElementName, elem.Namespace), attrs);\r
851                         }\r
852                         if(attrs.XmlEnum != null)\r
853                         {\r
854                         }\r
855                         if(attrs.XmlType != null)\r
856                         {\r
857                                 memberTable.Add(new XmlQualifiedName(attrs.XmlType.TypeName, attrs.XmlType.Namespace), attrs);\r
858                         }\r
859                 }\r
860 \r
861                 private bool Implements(Type type, Type interfaceType)\r
862                 {\r
863                         if(type.GetInterface(interfaceType.FullName) == interfaceType)\r
864                                 return true;\r
865                         return false;\r
866                 }\r
867                 private static void BubbleSort(ArrayList array, IComparer comparer)\r
868                 {\r
869                         int len = array.Count;\r
870                         object obj1, obj2;\r
871                         for (int i=0; i < len; i++) \r
872                         {\r
873                                 for (int j=0; j < len -i -1; j++)\r
874                                 {\r
875                                         obj1 = array[j];\r
876                                         obj2 = array[j+1];\r
877                                         if (comparer.Compare( obj2 , obj1 ) < 0) \r
878                                         {\r
879                                                 array[j] = obj2;\r
880                                                 array[j+1] = obj1;\r
881                                         }\r
882                                 }\r
883                         }\r
884                 }\r
885         }\r
886 }