XmlSerializer.cs 30 KB

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