XmlSerializer.cs 26 KB

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