2
0

XmlSerializer.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903
  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 type;
  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.type = 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 = o.GetType ();
  197. string rootName = objType.Name;
  198. string rootNs = String.Empty;
  199. string rootPrefix = String.Empty;
  200. bool isBuiltIn = IsInbuiltType (objType);
  201. if (namespaces == null)
  202. namespaces = new XmlSerializerNamespaces ();
  203. if (namespaces.Count == 0) {
  204. namespaces.Add ("xsd", XmlSchema.Namespace);
  205. namespaces.Add ("xsi", XmlSchema.InstanceNamespace);
  206. }
  207. XmlSerializerNamespaces nss = new XmlSerializerNamespaces ();
  208. XmlQualifiedName[] qnames;
  209. if (isBuiltIn) {
  210. writer.WriteStartDocument ();
  211. SerializeBuiltIn (writer, o);
  212. writer.WriteEndDocument ();
  213. return;
  214. }
  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. TypeData td = TypeTranslator.GetTypeData (o.GetType ());
  266. writer.WriteElementString (td.ElementName, o.ToString ());
  267. }
  268. private void SerializeMembers (XmlWriter writer, object o, bool isRoot)
  269. {
  270. Type objType = o.GetType ();
  271. XmlAttributes nsAttributes = (XmlAttributes) ((object[]) typeTable [objType])[1];
  272. ArrayList attributes = (ArrayList) ((object[]) typeTable [objType])[2];
  273. ArrayList elements = (ArrayList) ((object[]) typeTable [objType])[3];
  274. if (!isRoot && nsAttributes != null) {
  275. MemberInfo member = nsAttributes.MemberInfo;
  276. FieldInfo fieldInfo = member as FieldInfo;
  277. PropertyInfo propertyInfo = member as PropertyInfo;
  278. XmlSerializerNamespaces xns;
  279. if (fieldInfo != null)
  280. xns = (XmlSerializerNamespaces) fieldInfo.GetValue (o);
  281. else
  282. xns = (XmlSerializerNamespaces) propertyInfo.GetValue (o, null);
  283. XmlQualifiedName[] qnames = xns.ToArray ();
  284. foreach (XmlQualifiedName qname in qnames)
  285. if (writer.LookupPrefix (qname.Namespace) != qname.Name)
  286. writer.WriteAttributeString ("xmlns", qname.Name, null, qname.Namespace);
  287. }
  288. //Serialize the Attributes.
  289. foreach (XmlAttributes xmlAttributes in attributes) {
  290. MemberInfo member = xmlAttributes.MemberInfo;
  291. FieldInfo fieldInfo = member as FieldInfo;
  292. PropertyInfo propertyInfo = member as PropertyInfo;
  293. Type attributeType;
  294. object attributeValue;
  295. string attributeValueString;
  296. string attributeName;
  297. string attributeNs;
  298. if (fieldInfo != null) {
  299. attributeType = fieldInfo.FieldType;
  300. attributeValue = fieldInfo.GetValue (o);
  301. }
  302. else {
  303. attributeType = propertyInfo.PropertyType;
  304. attributeValue = propertyInfo.GetValue (o, null);
  305. }
  306. attributeName = xmlAttributes.GetAttributeName (attributeType, member.Name);
  307. attributeNs = xmlAttributes.GetAttributeNamespace (attributeType);
  308. if (attributeValue is XmlQualifiedName) {
  309. XmlQualifiedName qname = (XmlQualifiedName) attributeValue;
  310. if (qname.IsEmpty)
  311. continue;
  312. writer.WriteStartAttribute (attributeName, attributeNs);
  313. writer.WriteQualifiedName (qname.Name, qname.Namespace);
  314. writer.WriteEndAttribute ();
  315. continue;
  316. }
  317. else if (attributeValue is XmlQualifiedName[]) {
  318. XmlQualifiedName[] qnames = (XmlQualifiedName[]) attributeValue;
  319. writer.WriteStartAttribute (attributeName, attributeNs);
  320. int count = 0;
  321. foreach (XmlQualifiedName qname in qnames) {
  322. if (qname.IsEmpty)
  323. continue;
  324. if (count++ > 0)
  325. writer.WriteWhitespace (" ");
  326. writer.WriteQualifiedName (qname.Name, qname.Namespace);
  327. }
  328. writer.WriteEndAttribute ();
  329. continue;
  330. }
  331. else if (attributeValue is XmlAttribute[]) {
  332. XmlAttribute[] xmlattrs = (XmlAttribute[]) attributeValue;
  333. foreach (XmlAttribute xmlattr in xmlattrs)
  334. xmlattr.WriteTo(writer);
  335. continue;
  336. }
  337. attributeValueString = GetXmlValue (attributeValue);
  338. if (attributeValueString != GetXmlValue (xmlAttributes.XmlDefaultValue))
  339. writer.WriteAttributeString (attributeName, attributeNs, attributeValueString);
  340. }
  341. // Serialize Elements
  342. foreach (XmlAttributes xmlElements in elements) {
  343. MemberInfo member = xmlElements.MemberInfo;
  344. FieldInfo fieldInfo = member as FieldInfo;
  345. PropertyInfo propertyInfo = member as PropertyInfo;
  346. Type elementType;
  347. object elementValue;
  348. string elementName;
  349. string elementNs;
  350. if (fieldInfo != null) {
  351. elementType = fieldInfo.FieldType;
  352. elementValue = fieldInfo.GetValue (o);
  353. }
  354. else {
  355. elementType = propertyInfo.PropertyType;
  356. elementValue = propertyInfo.GetValue (o, null);
  357. }
  358. elementName = xmlElements.GetElementName (elementType, member.Name);
  359. elementNs = xmlElements.GetElementNamespace (elementType);
  360. WriteElement (writer, xmlElements, elementName, elementNs, elementType, elementValue);
  361. }
  362. }
  363. [MonoTODO ("Remove FIXMEs")]
  364. private void WriteElement (XmlWriter writer, XmlAttributes attrs, string name, string ns, Type type, Object value)
  365. {
  366. if (IsInbuiltType (type)) {
  367. string xmlValue = GetXmlValue (value);
  368. if (xmlValue != String.Empty && xmlValue != null)
  369. writer.WriteElementString (name, ns, xmlValue);
  370. }
  371. else if (attrs.XmlText != null && value != null) {
  372. if (type == typeof (object[])) {
  373. // FIXME
  374. }
  375. else if (type == typeof (string[])) {
  376. // FIXME
  377. }
  378. else if (type == typeof (XmlNode)) {
  379. ((XmlNode) value).WriteTo (writer);
  380. }
  381. else if (type == typeof (XmlNode[])) {
  382. XmlNode[] nodes = (XmlNode[]) value;
  383. foreach (XmlNode node in nodes)
  384. node.WriteTo (writer);
  385. }
  386. }
  387. else if (type.IsArray && value != null) {
  388. writer.WriteStartElement (name, ns);
  389. SerializeArray (writer, value);
  390. writer.WriteEndElement ();
  391. }
  392. else if (value is ICollection) {
  393. BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
  394. //Find a non indexer Count Property with return type of int
  395. PropertyInfo countInfo = type.GetProperty ("Count", flags, null, typeof (int), new Type[0], null);
  396. PropertyInfo itemInfo = type.GetProperty ("Item", flags, null, null, new Type[1] {typeof (int)}, null);
  397. int count = (int) countInfo.GetValue (value, null);
  398. if (count > 0)
  399. for (int i = 0; i < count; i++) {
  400. object itemValue = itemInfo.GetValue (value, new object[1] {i});
  401. if (itemValue != null) {
  402. string itemName = attrs.GetElementName (itemValue.GetType (), name);
  403. string itemNs = attrs.GetElementNamespace (itemValue.GetType ());
  404. writer.WriteStartElement (itemName, itemNs);
  405. SerializeMembers (writer, itemValue, false);
  406. writer.WriteEndElement ();
  407. }
  408. }
  409. }
  410. else if (value is IEnumerable) {
  411. // FIXME
  412. }
  413. else if (type.IsEnum) {
  414. // FIXME
  415. }
  416. else if (value != null) { //Complex Type?
  417. string itemName = attrs.GetElementName (value.GetType (), name);
  418. string itemNs = attrs.GetElementNamespace (value.GetType ());
  419. writer.WriteStartElement (itemName, itemNs);
  420. SerializeMembers (writer, value, false);
  421. writer.WriteEndElement ();
  422. }
  423. else {
  424. // FIXME
  425. }
  426. }
  427. [MonoTODO]
  428. private void SerializeArray (XmlWriter writer, object o)
  429. {
  430. throw new NotImplementedException ();
  431. }
  432. /// <summary>
  433. /// If the type is a string, valuetype or primitive type we do not populate the TypeTable.
  434. /// If the type is an array, we populate the TypeTable with Element type of the array.
  435. /// If the type implements ICollection, it is handled differently. We do not care for its members.
  436. /// If the type implements IEnumberable, we check that it implements Add(). Don't care for members.
  437. /// </summary>
  438. [MonoTODO ("Remove FIXMEs")]
  439. private void FillTypeTable (Type type)
  440. {
  441. if (typeTable.Contains (type))
  442. return;
  443. //For value types and strings we don't need the members.
  444. //FIXME: We will need the enum types probably.
  445. if (IsInbuiltType (type))
  446. return;
  447. //Array, ICollection and IEnumberable are treated differenty
  448. if (type.IsArray) {
  449. FillArrayType (type);
  450. return;
  451. }
  452. else if (type.IsEnum) {
  453. FillEnum (type);
  454. return;
  455. }
  456. else {
  457. //There must be a public constructor
  458. if (!HasDefaultConstructor (type))
  459. throw new Exception ("Can't Serialize Type " + type.Name + " since it does not have default Constructor");
  460. if (type.GetInterface ("ICollection") == typeof (System.Collections.ICollection)) {
  461. FillICollectionType (type);
  462. return;
  463. }
  464. if (type.GetInterface ("IEnumerable") == typeof (System.Collections.IEnumerable)) {
  465. //FillIEnumerableType(type);
  466. //return;
  467. }
  468. }
  469. //Add the Class to the hashtable.
  470. //Each value of the hashtable has two objects, one is the hashtable with key of membername (for deserialization)
  471. //Other is an Array of XmlSerializernames, Array of XmlAttributes & Array of XmlElements.
  472. Object[] memberObj = new Object[4];
  473. typeTable.Add (type,memberObj);
  474. Hashtable memberTable = new Hashtable ();
  475. memberObj[0] = memberTable;
  476. memberTable.Add ("", XmlAttributes.FromClass (type));
  477. memberObj[1] = null;
  478. ArrayList attributes = new ArrayList ();
  479. memberObj[2] = attributes;
  480. ArrayList elements = new ArrayList ();
  481. memberObj[3] = elements;
  482. //Get the graph of the members. Graph is nothing but the order
  483. //in which MS implementation serializes the members.
  484. MemberInfo[] minfo = GetGraph (type);
  485. foreach (MemberInfo member in minfo) {
  486. FieldInfo fieldInfo = (member as FieldInfo);
  487. PropertyInfo propertyInfo = (member as PropertyInfo);
  488. if (fieldInfo != null) {
  489. //If field is readOnly or const, do not serialize it.
  490. if (fieldInfo.IsLiteral || fieldInfo.IsInitOnly)
  491. continue;
  492. XmlAttributes xmlAttributes = XmlAttributes.FromField (member, fieldInfo);
  493. //If XmlAttributes have XmlIgnore, ignore this member
  494. if (xmlAttributes.XmlIgnore)
  495. continue;
  496. //If this member is a XmlNs type, set the XmlNs object.
  497. if (xmlAttributes.Xmlns) {
  498. memberObj[1] = xmlAttributes;
  499. continue;
  500. }
  501. //If the member is a attribute Type, Add to attribute list
  502. if (xmlAttributes.isAttribute)
  503. attributes.Add (xmlAttributes);
  504. else //Add to elements
  505. elements.Add (xmlAttributes);
  506. //Add in the Hashtable.
  507. memberTable.Add (member.Name, xmlAttributes);
  508. if (xmlAttributes.XmlAnyAttribute != null || xmlAttributes.XmlText != null)
  509. continue;
  510. if (xmlAttributes.XmlElements.Count > 0) {
  511. foreach (XmlElementAttribute elem in xmlAttributes.XmlElements) {
  512. if (elem.Type != null)
  513. FillTypeTable (elem.Type);
  514. else
  515. FillTypeTable (fieldInfo.FieldType);
  516. }
  517. continue;
  518. }
  519. if (!IsInbuiltType (fieldInfo.FieldType))
  520. FillTypeTable (fieldInfo.FieldType);
  521. }
  522. else if (propertyInfo != null) {
  523. //If property is readonly or writeonly, do not serialize it.
  524. //Exceptions are properties whose return type is array, ICollection or IEnumerable
  525. //Indexers are not serialized unless the class Implements ICollection.
  526. if (!(propertyInfo.PropertyType.IsArray || Implements (propertyInfo.PropertyType, typeof (ICollection)) ||
  527. (propertyInfo.PropertyType != typeof (string) && Implements (propertyInfo.PropertyType, typeof (IEnumerable))))) {
  528. if(!(propertyInfo.CanRead && propertyInfo.CanWrite) || propertyInfo.GetIndexParameters ().Length != 0)
  529. continue;
  530. }
  531. XmlAttributes xmlAttributes = XmlAttributes.FromProperty (member, propertyInfo);
  532. // If XmlAttributes have XmlIgnore, ignore this member
  533. if (xmlAttributes.XmlIgnore)
  534. continue;
  535. // If this member is a XmlNs type, set the XmlNs object.
  536. if (xmlAttributes.Xmlns) {
  537. memberObj[1] = xmlAttributes;
  538. continue;
  539. }
  540. // If the member is a attribute Type, Add to attribute list
  541. if (xmlAttributes.isAttribute)
  542. attributes.Add (xmlAttributes);
  543. else //Add to elements
  544. elements.Add (xmlAttributes);
  545. // OtherWise add in the Hashtable.
  546. memberTable.Add (member.Name, xmlAttributes);
  547. if (xmlAttributes.XmlAnyAttribute != null || xmlAttributes.XmlText != null)
  548. continue;
  549. if (xmlAttributes.XmlElements.Count > 0) {
  550. foreach (XmlElementAttribute elem in xmlAttributes.XmlElements) {
  551. if (elem.Type != null)
  552. FillTypeTable (elem.Type);
  553. else
  554. FillTypeTable (propertyInfo.PropertyType);
  555. }
  556. continue;
  557. }
  558. if (!IsInbuiltType (propertyInfo.PropertyType))
  559. FillTypeTable (propertyInfo.PropertyType);
  560. }
  561. }
  562. // Sort the attributes for the members according to their Order
  563. // This is an extension to MS's Implementation and will be useful
  564. // if our reflection does not return the same order of elements
  565. // as MS .NET impl
  566. if (useOrder)
  567. BubbleSort (elements, XmlAttributes.attrComparer);
  568. }
  569. private void FillArrayType (Type type)
  570. {
  571. if (type.GetArrayRank () != 1)
  572. throw new Exception ("MultiDimensional Arrays are not Supported");
  573. Type arrayType = type.GetElementType ();
  574. if (arrayType.IsArray)
  575. FillArrayType (arrayType);
  576. else if (!IsInbuiltType (arrayType))
  577. FillTypeTable (arrayType);
  578. }
  579. private void FillICollectionType (Type type)
  580. {
  581. //Must have an public Indexer that takes an integer and
  582. //a public Count Property which returns an int.
  583. BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
  584. //Find a non indexer Count Property with return type of int
  585. PropertyInfo countProp = type.GetProperty ("Count", flags, null, typeof (int), new Type[0], null);
  586. if (countProp == null || !countProp.CanRead)
  587. throw new Exception ("Cannot Serialize " + type + " because it implements ICollectoion, but does not implement public Count property");
  588. //Find a indexer Item Property which takes an int
  589. PropertyInfo itemProp = type.GetProperty ("Item", flags, null, null, new Type[1] {typeof (int)}, null);
  590. if (itemProp == null || !itemProp.CanRead || !itemProp.CanWrite)
  591. throw new Exception ("Cannot Serialize " + type + " because it does not have a read/write indexer property that takes an int as argument");
  592. FillTypeTable (itemProp.PropertyType);
  593. }
  594. [MonoTODO]
  595. private void FillIEnumerableType (Type type)
  596. {
  597. //Must implement a public Add method that takes a single parameter.
  598. //The Add method's parameter must be of the same type as is returned from
  599. //the Current property on the value returned from GetEnumerator, or one of that type's bases.
  600. // We currently ignore enumerable types anyway, so this method was junked.
  601. // The code did not do what the documentation above says (if that is even possible!)
  602. return;
  603. }
  604. private void FillEnum (Type type)
  605. {
  606. Hashtable memberTable = new Hashtable ();
  607. BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
  608. typeTable.Add (type, memberTable);
  609. string[] names = Enum.GetNames (type);
  610. foreach (string name in names) {
  611. MemberInfo[] members = type.GetMember (name);
  612. if (members.Length != 1)
  613. throw new Exception("Should never happen. Enum member not present or more than one. " + name);
  614. XmlAttributes xmlAttributes = new XmlAttributes (members[0]);
  615. if (xmlAttributes.XmlIgnore)
  616. continue;
  617. if (xmlAttributes.XmlEnum != null)
  618. memberTable.Add (members[0].Name, xmlAttributes.XmlEnum.Name);
  619. else
  620. memberTable.Add (members[0].Name, members[0].Name);
  621. }
  622. }
  623. private bool HasDefaultConstructor (Type type)
  624. {
  625. ConstructorInfo defaultConstructor = type.GetConstructor (new Type[0]);
  626. if (defaultConstructor == null || defaultConstructor.IsAbstract || defaultConstructor.IsStatic || !defaultConstructor.IsPublic)
  627. return false;
  628. return true;
  629. }
  630. private bool IsInbuiltType (Type type)
  631. {
  632. if (type.IsEnum)
  633. return false;
  634. if (type.IsValueType || type == typeof (string) || type.IsPrimitive)
  635. return true;
  636. if (type == typeof (DateTime) || type == typeof (XmlNode))
  637. return true;
  638. return false;
  639. }
  640. private static MemberInfo[] GetGraph(Type type)
  641. {
  642. ArrayList typeGraph = new ArrayList ();
  643. GetGraph (type, typeGraph);
  644. return (MemberInfo[]) typeGraph.ToArray (typeof (MemberInfo));
  645. }
  646. private static void GetGraph (Type type, ArrayList typeGraph)
  647. {
  648. BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
  649. if (type.BaseType == null)
  650. return;
  651. GetGraph (type.BaseType, typeGraph);
  652. typeGraph.AddRange (type.GetFields (flags));
  653. typeGraph.AddRange (type.GetProperties (flags));
  654. }
  655. private string GetXmlValue (object value)
  656. {
  657. if (value == null)
  658. return null;
  659. if (value is Enum) {
  660. Type type = value.GetType ();
  661. if (typeTable.ContainsKey (type)) {
  662. Hashtable memberTable = (Hashtable) (typeTable[type]);
  663. if (type.IsDefined (typeof (FlagsAttribute), false)) {
  664. //If value is exactly a single enum member
  665. if (memberTable.Contains (value.ToString ()))
  666. return (string) memberTable[value.ToString ()];
  667. string retval = "";
  668. int enumval = (int) value;
  669. string[] names = Enum.GetNames (type);
  670. foreach (string key in names) {
  671. if (!memberTable.ContainsKey (key))
  672. continue;
  673. //Otherwise multiple values.
  674. int val = (int) Enum.Parse (type, key);
  675. if (val != 0 && (enumval & val) == val)
  676. retval += " " + (string) memberTable[Enum.GetName (type, val)];
  677. }
  678. retval = retval.Trim ();
  679. if (retval.Length == 0)
  680. return null;
  681. return retval;
  682. }
  683. else if (memberTable.ContainsKey (value.ToString ()))
  684. return (string) memberTable[value.ToString()];
  685. else
  686. return null;
  687. }
  688. else
  689. throw new Exception ("Unknown Enumeration");
  690. }
  691. if (value is bool)
  692. return (bool) value ? "true" : "false";
  693. if (value is XmlQualifiedName) {
  694. if (((XmlQualifiedName) value).IsEmpty)
  695. return null;
  696. }
  697. return (value == null) ? null : value.ToString ();
  698. }
  699. [MonoTODO ("Remove FIXMEs")]
  700. private static void ProcessAttributes (XmlAttributes attrs, Hashtable memberTable)
  701. {
  702. if (attrs.XmlAnyAttribute != null) {
  703. // FIXME
  704. }
  705. foreach (XmlAnyElementAttribute anyelem in attrs.XmlAnyElements)
  706. memberTable.Add (new XmlQualifiedName (anyelem.Name, anyelem.Namespace), attrs);
  707. if (attrs.XmlArray != null) {
  708. // FIXME
  709. }
  710. foreach (XmlArrayItemAttribute item in attrs.XmlArrayItems)
  711. memberTable.Add (new XmlQualifiedName (item.ElementName, item.Namespace), attrs);
  712. if (attrs.XmlAttribute != null)
  713. memberTable.Add (new XmlQualifiedName (attrs.XmlAttribute.AttributeName,attrs.XmlAttribute.Namespace), attrs);
  714. if (attrs.XmlChoiceIdentifier != null) {
  715. // FIXME
  716. }
  717. foreach (XmlElementAttribute elem in attrs.XmlElements)
  718. memberTable.Add (new XmlQualifiedName (elem.ElementName, elem.Namespace), attrs);
  719. if (attrs.XmlEnum != null) {
  720. // FIXME
  721. }
  722. if (attrs.XmlType != null)
  723. memberTable.Add (new XmlQualifiedName (attrs.XmlType.TypeName, attrs.XmlType.Namespace), attrs);
  724. }
  725. private bool Implements (Type type, Type interfaceType)
  726. {
  727. return (type.GetInterface (interfaceType.Name) == interfaceType);
  728. }
  729. private static void BubbleSort (ArrayList array, IComparer comparer)
  730. {
  731. int len = array.Count;
  732. object obj1, obj2;
  733. for (int i=0; i < len; i++) {
  734. for (int j=0; j < len -i -1; j++) {
  735. obj1 = array[j];
  736. obj2 = array[j+1];
  737. if (comparer.Compare (obj2 , obj1 ) < 0) {
  738. array[j] = obj2;
  739. array[j+1] = obj1;
  740. }
  741. }
  742. }
  743. }
  744. #endregion // Methods
  745. }
  746. }