XmlSerializer.cs 25 KB

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