| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274 |
- //
- // Mono Class Libraries
- // System.Xml.Serialization.XmlSerializer
- //
- // Authors:
- // John Donagher ([email protected])
- // Ajay kumar Dwivedi ([email protected])
- // Tim Coleman ([email protected])
- // Elan Feingold ([email protected])
- //
- // (C) 2002 John Donagher, Ajay kumar Dwivedi
- // Copyright (C) Tim Coleman, 2002
- // (C) 2003 Elan Feingold
- //
- using System;
- using System.Collections;
- using System.IO;
- using System.Reflection;
- using System.Xml;
- using System.Xml.Schema;
- using System.Text;
- namespace System.Xml.Serialization {
- /// <summary>
- /// Summary description for XmlSerializer.
- /// </summary>
- public class XmlSerializer {
- #region Fields
- Type xsertype;
- XmlAttributeOverrides overrides;
- Type[] extraTypes;
- XmlRootAttribute rootAttribute;
- string defaultNamespace;
- Hashtable typeTable;
- bool useOrder;
- bool isNullable;
- Hashtable typeMappings = new Hashtable ();
- #endregion // Fields
- #region Constructors
- protected XmlSerializer ()
- {
- }
- public XmlSerializer (Type type)
- : this (type, null, null, null, null)
- {
- }
- public XmlSerializer (XmlTypeMapping xmlTypeMapping)
- {
- typeMappings.Add (xmlTypeMapping.TypeFullName, xmlTypeMapping);
- }
- public XmlSerializer (Type type, string defaultNamespace)
- : this (type, null, null, null, defaultNamespace)
- {
- }
- public XmlSerializer (Type type, Type[] extraTypes)
- : this (type, null, extraTypes, null, null)
- {
- }
- public XmlSerializer (Type type, XmlAttributeOverrides overrides)
- : this (type, overrides, null, null, null)
- {
- }
- public XmlSerializer (Type type, XmlRootAttribute root)
- : this (type, null, null, root, null)
- {
- }
- internal XmlSerializer (Hashtable typeTable)
- {
- this.typeTable = typeTable;
- }
- public XmlSerializer (Type type,
- XmlAttributeOverrides overrides,
- Type [] extraTypes,
- XmlRootAttribute root,
- string defaultNamespace)
- {
- if (type == null)
- throw new ArgumentNullException ("type");
- XmlReflectionImporter ri = new XmlReflectionImporter (overrides, defaultNamespace);
- TypeData td = TypeTranslator.GetTypeData (type);
- typeMappings.Add (td.FullTypeName, ri.ImportTypeMapping (type, root, defaultNamespace));
- ri.IncludeTypes (type);
- if (extraTypes != null) {
- foreach (Type t in extraTypes) {
- td = TypeTranslator.GetTypeData (t);
- string n = td.FullTypeName;
- typeMappings.Add (n, ri.ImportTypeMapping (type, root, defaultNamespace));
- ri.IncludeTypes (t);
- }
- }
- this.xsertype = type;
- this.overrides = overrides;
- this.extraTypes = (extraTypes == null ? new Type[0] : extraTypes);
- if (root != null)
- this.rootAttribute = root;
- else {
- object[] attributes = type.GetCustomAttributes (typeof (XmlRootAttribute), false);
- if (attributes.Length > 0)
- this.rootAttribute = (XmlRootAttribute) attributes[0];
- }
- this.defaultNamespace = defaultNamespace;
- if (typeTable == null)
- typeTable = new Hashtable ();
- FillTypeTable (type);
- }
- #endregion // Constructors
- #region Events
- public event XmlAttributeEventHandler UnknownAttribute;
- public event XmlElementEventHandler UnknownElement;
- public event XmlNodeEventHandler UnknownNode;
- public event UnreferencedObjectEventHandler UnreferencedObject;
- #endregion // Events
- #region Properties
- internal bool UseOrder {
- get { return useOrder; }
- set { useOrder = value; }
- }
- #endregion // Properties
- #region Methods
- [MonoTODO]
- public virtual bool CanDeserialize (XmlReader xmlReader)
- {
- throw new NotImplementedException ();
- }
- protected virtual XmlSerializationReader CreateReader ()
- {
- // This is what MS does!!!
- throw new NotImplementedException ();
- }
- protected virtual XmlSerializationWriter CreateWriter ()
- {
- // This is what MS does!!!
- throw new NotImplementedException ();
- }
- public object Deserialize (Stream stream)
- {
- XmlTextReader xmlReader = new XmlTextReader(stream);
- return Deserialize(xmlReader);
- }
- public object Deserialize (TextReader textReader)
- {
- XmlTextReader xmlReader = new XmlTextReader(textReader);
- return Deserialize(xmlReader);
- }
- public bool DeserializeComposite(XmlReader xmlReader, ref Object theObject)
- {
- Type objType = theObject.GetType();
- bool retVal = true;
- //Console.WriteLine("DeserializeComposite({0})", objType);
- // Are we at an empty element?
- if (xmlReader.IsEmptyElement == true)
- return retVal;
- // Read each field, counting how many we find.
- for (int numFields=0; xmlReader.Read(); )
- {
- XmlNodeType xmlNodeType = xmlReader.NodeType;
- bool isEmpty = xmlReader.IsEmptyElement;
- if (xmlNodeType == XmlNodeType.Element)
- {
- // Read the field.
- DeserializeField(xmlReader, ref theObject, xmlReader.Name);
- numFields++;
- }
- else if (xmlNodeType == XmlNodeType.EndElement)
- {
- if (numFields == 0)
- {
- //Console.WriteLine("Empty object deserialized, ignoring.");
- retVal = false;
- }
- return retVal;
- }
- }
- return retVal;
- }
- public void DeserializeField (XmlReader xmlReader, ref Object theObject, String fieldName)
- {
- //Console.WriteLine("DeserializeField({0})", fieldName);
- BindingFlags bindingFlags = 0;
- Type fieldType = null;
- // Get the type, first try a field.
- FieldInfo fieldInfo = theObject.GetType().GetField(fieldName);
- if (fieldInfo != null) {
- fieldType = fieldInfo.FieldType;
- bindingFlags = BindingFlags.SetField;
- } else {
- // Is it a property?
- PropertyInfo propInfo = theObject.GetType().GetProperty(fieldName);
- if (propInfo != null)
- {
- fieldType = propInfo.PropertyType;
- bindingFlags = BindingFlags.SetProperty;
- }
- }
- if (fieldType == null)
- throw new Exception (String.Format ("On type {0} can not identify {1}", theObject.GetType (), fieldName));
- Object value = null;
- bool isEmptyField = xmlReader.IsEmptyElement;
- //Console.WriteLine("DeserializeField({0} of type {1})", fieldName, fieldType);
- if (fieldType.IsArray && fieldType != typeof(System.Byte[]))
- {
- // Create an empty array list.
- ArrayList list = new ArrayList();
- // Call out to deserialize it.
- DeserializeArray(xmlReader, list, fieldType.GetElementType());
- value = list.ToArray(fieldType.GetElementType());
- }
- else if (isEmptyField == false && (IsInbuiltType(fieldType) || fieldType.IsEnum || fieldType.IsArray))
- {
- // Built in, set it.
- while (xmlReader.Read())
- {
- if (xmlReader.NodeType == XmlNodeType.Text)
- {
- //Console.WriteLine(" -> value is '{0}'", xmlReader.Value);
- if (fieldType == typeof(Guid))
- value = XmlConvert.ToGuid(xmlReader.Value);
- else if (fieldType == typeof(Boolean))
- value = XmlConvert.ToBoolean(xmlReader.Value);
- else if (fieldType == typeof(String))
- value = xmlReader.Value;
- else if (fieldType == typeof(Int64))
- value = XmlConvert.ToInt64(xmlReader.Value);
- else if (fieldType == typeof(DateTime))
- value = XmlConvert.ToDateTime(xmlReader.Value);
- else if (fieldType.IsEnum)
- value = Enum.Parse(fieldType, xmlReader.Value);
- else if (fieldType == typeof(System.Byte[]))
- value = XmlCustomFormatter.ToByteArrayBase64(xmlReader.Value);
- else if (fieldType == typeof (Int32))
- value = XmlConvert.ToInt32 (xmlReader.Value);
- else
- Console.WriteLine("XmlSerializer.DeserializeField, improve routine: Error (type is '{0}')", fieldType);
- break;
- }
- }
- }
- else if (isEmptyField == true)
- {
- if (fieldType.IsArray)
- {
- // Must be a byte array, just create an empty one.
- value = new byte[0];
- }
- else if (fieldType == typeof(string))
- {
- // Create a new empty string.
- value = "";
- }
- }
- else
- {
- //Console.WriteLine("Creating new {0}", fieldType);
- // Create the new complex object.
- value = System.Activator.CreateInstance(fieldType);
- // Recurse, allowing the method to whack the object if it's empty.
- DeserializeComposite(xmlReader, ref value);
- }
- //Console.WriteLine(" Setting {0} to '{1}'", fieldName, value);
- // Set the field value.
- theObject.GetType().InvokeMember(fieldName,
- bindingFlags,
- null,
- theObject,
- new Object[] { value },
- null, null, null);
- // We need to munch the end.
- if (IsInbuiltType(fieldType) ||
- fieldType.IsEnum ||
- fieldType == typeof(System.Byte[]))
- {
- if (isEmptyField == false)
- while (xmlReader.Read() && xmlReader.NodeType != XmlNodeType.EndElement)
- ;
- }
- }
- public void DeserializeArray(XmlReader xmlReader, ArrayList theList, Type theType)
- {
- //Console.WriteLine(" DeserializeArray({0})", theType);
- if (xmlReader.IsEmptyElement)
- {
- //Console.WriteLine(" DeserializeArray -> empty, nothing to do here");
- return;
- }
- while (xmlReader.Read())
- {
- XmlNodeType xmlNodeType = xmlReader.NodeType;
- bool isEmpty = xmlReader.IsEmptyElement;
- if (xmlNodeType == XmlNodeType.Element)
- {
- // Must be an element of the array, create it.
- Object obj = System.Activator.CreateInstance(theType);
- //Console.WriteLine(" created obj of type '{0}'", obj.GetType());
- // Deserialize and add.
- if (DeserializeComposite(xmlReader, ref obj))
- {
- theList.Add(obj);
- }
- }
- if ((xmlNodeType == XmlNodeType.Element && isEmpty) ||
- (xmlNodeType == XmlNodeType.EndElement))
- {
- return;
- }
- }
- }
- public object Deserialize(XmlReader xmlReader)
- {
- Object obj = null;
- // Read each node in the tree.
- while (xmlReader.Read())
- {
- if (xmlReader.NodeType == XmlNodeType.Element)
- {
- // Create the top level object.
- //Console.WriteLine("Creating '{0}'", xsertype.FullName);
- obj = System.Activator.CreateInstance(xsertype);
- // Deserialize it.
- DeserializeComposite(xmlReader, ref obj);
- }
- else if (xmlReader.NodeType == XmlNodeType.EndElement)
- {
- return obj;
- }
- }
- return obj;
- }
- protected virtual object Deserialize (XmlSerializationReader reader)
- {
- // This is what MS does!!!
- throw new NotImplementedException ();
- }
- [MonoTODO]
- public static XmlSerializer [] FromMappings (XmlMapping [] mappings)
- {
- throw new NotImplementedException ();
- }
- [MonoTODO]
- public static XmlSerializer [] FromTypes (Type [] mappings)
- {
- throw new NotImplementedException ();
- }
- [MonoTODO]
- protected virtual void Serialize (object o, XmlSerializationWriter writer)
- {
- throw new NotImplementedException ();
- }
- public void Serialize (Stream stream, object o)
- {
- XmlTextWriter xmlWriter = new XmlTextWriter (stream, System.Text.Encoding.Default);
- xmlWriter.Formatting = Formatting.Indented;
- Serialize (xmlWriter, o, null);
- xmlWriter.WriteEndDocument();
- xmlWriter.Flush();
- }
- public void Serialize (TextWriter textWriter, object o)
- {
- XmlTextWriter xmlWriter = new XmlTextWriter (textWriter);
- xmlWriter.Formatting = Formatting.Indented;
- Serialize (xmlWriter, o, null);
- xmlWriter.WriteEndDocument();
- xmlWriter.Flush();
- }
- public void Serialize (XmlWriter xmlWriter, object o)
- {
- Serialize (xmlWriter, o, null);
- }
- public void Serialize (Stream stream, object o, XmlSerializerNamespaces namespaces)
- {
- XmlTextWriter xmlWriter = new XmlTextWriter (stream, System.Text.Encoding.Default);
- xmlWriter.Formatting = Formatting.Indented;
- Serialize (xmlWriter, o, namespaces);
- xmlWriter.WriteEndDocument();
- xmlWriter.Flush();
- }
- public void Serialize (TextWriter textWriter, object o, XmlSerializerNamespaces namespaces)
- {
- XmlTextWriter xmlWriter = new XmlTextWriter (textWriter);
- xmlWriter.Formatting = Formatting.Indented;
- Serialize (xmlWriter, o, namespaces);
- xmlWriter.WriteEndDocument();
- xmlWriter.Flush();
- }
- public void Serialize (XmlWriter writer, object o, XmlSerializerNamespaces namespaces)
- {
- Type objType = xsertype;//o.GetType ();
- if (IsInbuiltType(objType))
- {
- if (writer.WriteState == WriteState.Start)
- writer.WriteStartDocument ();
- SerializeBuiltIn (writer, o);
- // Keep WriteState.Content state.
- // writer.WriteEndDocument();
- writer.Flush ();
- return;
- }
- string rootName = objType.Name;
- string rootNs = String.Empty;
- string rootPrefix = String.Empty;
- if (namespaces == null)
- namespaces = new XmlSerializerNamespaces ();
- if (namespaces.Count == 0) {
- namespaces.Add ("xsd", XmlSchema.Namespace);
- namespaces.Add ("xsi", XmlSchema.InstanceNamespace);
- }
- XmlSerializerNamespaces nss = new XmlSerializerNamespaces ();
- XmlQualifiedName[] qnames;
- if (writer.WriteState == WriteState.Start)
- writer.WriteStartDocument ();
- object [] memberObj = (object []) typeTable [objType];
- if (memberObj == null)
- throw new Exception ("Unknown Type " + objType +
- " encountered during Serialization");
- Hashtable memberTable = (Hashtable) memberObj [0];
- XmlAttributes xmlAttributes = (XmlAttributes) memberTable [""];
- //If we have been passed an XmlRoot, set it on the base class
- if (rootAttribute != null)
- xmlAttributes.XmlRoot = rootAttribute;
- if (xmlAttributes.XmlRoot != null) {
- isNullable = xmlAttributes.XmlRoot.IsNullable;
- if (xmlAttributes.XmlRoot.ElementName != null)
- rootName = xmlAttributes.XmlRoot.ElementName;
- rootNs = xmlAttributes.XmlRoot.Namespace;
- }
- if (namespaces != null && namespaces.GetPrefix (rootNs) != null)
- rootPrefix = namespaces.GetPrefix (rootNs);
- //XMLNS attributes in the Root
- XmlAttributes XnsAttrs = (XmlAttributes) ((object[]) typeTable[objType])[1];
- if (XnsAttrs != null) {
- MemberInfo member = XnsAttrs.MemberInfo;
- FieldInfo fieldInfo = member as FieldInfo;
- PropertyInfo propertyInfo = member as PropertyInfo;
- XmlSerializerNamespaces xns;
- if (fieldInfo != null)
- xns = (XmlSerializerNamespaces) fieldInfo.GetValue (o);
- else
- xns = (XmlSerializerNamespaces) propertyInfo.GetValue (o, null);
- qnames = xns.ToArray ();
- foreach (XmlQualifiedName qname in qnames)
- nss.Add (qname.Name, qname.Namespace);
- }
- //XmlNs from the namespaces passed
- qnames = namespaces.ToArray ();
- foreach (XmlQualifiedName qname in qnames) {
- if (writer.LookupPrefix (qname.Namespace) != qname.Name)
- nss.Add (qname.Name, qname.Namespace);
- }
- writer.WriteStartElement (rootPrefix, rootName, rootNs);
- qnames = nss.ToArray();
- foreach (XmlQualifiedName qname in qnames) {
- if (writer.LookupPrefix (qname.Namespace) != qname.Name)
- writer.WriteAttributeString ("xmlns", qname.Name, null, qname.Namespace);
- }
- if (rootPrefix == String.Empty && rootNs != String.Empty && rootNs != null)
- writer.WriteAttributeString (String.Empty, "xmlns", null, rootNs);
- SerializeMembers (writer, o, true);//, namespaces);
- // Keep WriteState.Content state.
- // writer.WriteEndDocument ();
- writer.Flush ();
- }
- private void SerializeBuiltIn (XmlWriter writer, object o)
- {
- if (o is XmlNode) {
- XmlNode n = (XmlNode) o;
- XmlNodeReader nrdr = new XmlNodeReader (n);
- nrdr.Read ();
- if (nrdr.NodeType == XmlNodeType.XmlDeclaration)
- nrdr.Read ();
- do {
- writer.WriteNode (nrdr, false);
- } while (nrdr.Read ());
- }
- else {
- TypeData td = TypeTranslator.GetTypeData (o.GetType ());
- writer.WriteStartElement (td.ElementName);
- WriteBuiltinValue(writer,o);
- writer.WriteEndElement();
- }
- }
- private void WriteNilAttribute(XmlWriter writer)
- {
- writer.WriteAttributeString("nil",XmlSchema.InstanceNamespace, "true");
- }
- private void WriteBuiltinValue(XmlWriter writer, object o)
- {
- if(o == null)
- WriteNilAttribute(writer);
- else
- writer.WriteString (GetXmlValue(o));
- }
- private void SerializeMembers (XmlWriter writer, object o, bool isRoot)
- {
- if(o == null)
- {
- WriteNilAttribute(writer);
- return;
- }
- Type objType = o.GetType ();
- if (IsInbuiltType(objType))
- {
- SerializeBuiltIn (writer, o);
- return;
- }
- XmlAttributes nsAttributes = (XmlAttributes) ((object[]) typeTable [objType])[1];
- ArrayList attributes = (ArrayList) ((object[]) typeTable [objType])[2];
- ArrayList elements = (ArrayList) ((object[]) typeTable [objType])[3];
- if (!isRoot && nsAttributes != null) {
- MemberInfo member = nsAttributes.MemberInfo;
- FieldInfo fieldInfo = member as FieldInfo;
- PropertyInfo propertyInfo = member as PropertyInfo;
- XmlSerializerNamespaces xns;
- if (fieldInfo != null)
- xns = (XmlSerializerNamespaces) fieldInfo.GetValue (o);
- else
- xns = (XmlSerializerNamespaces) propertyInfo.GetValue (o, null);
- XmlQualifiedName[] qnames = xns.ToArray ();
- foreach (XmlQualifiedName qname in qnames)
- if (writer.LookupPrefix (qname.Namespace) != qname.Name)
- writer.WriteAttributeString ("xmlns", qname.Name, null, qname.Namespace);
- }
- //Serialize the Attributes.
- foreach (XmlAttributes xmlAttributes in attributes) {
- MemberInfo member = xmlAttributes.MemberInfo;
- FieldInfo fieldInfo = member as FieldInfo;
- PropertyInfo propertyInfo = member as PropertyInfo;
- Type attributeType;
- object attributeValue;
- string attributeValueString;
- string attributeName;
- string attributeNs;
- if (fieldInfo != null) {
- attributeType = fieldInfo.FieldType;
- attributeValue = fieldInfo.GetValue (o);
- }
- else {
- attributeType = propertyInfo.PropertyType;
- attributeValue = propertyInfo.GetValue (o, null);
- }
- attributeName = xmlAttributes.GetAttributeName (attributeType, member.Name);
- attributeNs = xmlAttributes.GetAttributeNamespace (attributeType);
- if (attributeValue is XmlQualifiedName) {
- XmlQualifiedName qname = (XmlQualifiedName) attributeValue;
- if (qname.IsEmpty)
- continue;
- writer.WriteStartAttribute (attributeName, attributeNs);
- writer.WriteQualifiedName (qname.Name, qname.Namespace);
- writer.WriteEndAttribute ();
- continue;
- }
- else if (attributeValue is XmlQualifiedName[]) {
- XmlQualifiedName[] qnames = (XmlQualifiedName[]) attributeValue;
- writer.WriteStartAttribute (attributeName, attributeNs);
- int count = 0;
- foreach (XmlQualifiedName qname in qnames) {
- if (qname.IsEmpty)
- continue;
- if (count++ > 0)
- writer.WriteWhitespace (" ");
- writer.WriteQualifiedName (qname.Name, qname.Namespace);
- }
- writer.WriteEndAttribute ();
- continue;
- }
- else if (attributeValue is XmlAttribute[]) {
- XmlAttribute[] xmlattrs = (XmlAttribute[]) attributeValue;
- foreach (XmlAttribute xmlattr in xmlattrs) {
- xmlattr.WriteTo(writer);
- }
- continue;
- }
- attributeValueString = GetXmlValue (attributeValue);
- if (attributeValueString != GetXmlValue (xmlAttributes.XmlDefaultValue))
- writer.WriteAttributeString (attributeName, attributeNs, attributeValueString);
- }
- // Serialize Elements
- foreach (XmlAttributes xmlElements in elements) {
- MemberInfo member = xmlElements.MemberInfo;
- FieldInfo fieldInfo = member as FieldInfo;
- PropertyInfo propertyInfo = member as PropertyInfo;
- Type elementType;
- object elementValue;
- string elementName;
- string elementNs;
- if (fieldInfo != null) {
- elementType = fieldInfo.FieldType;
- elementValue = fieldInfo.GetValue (o);
- }
- else {
- elementType = propertyInfo.PropertyType;
- elementValue = propertyInfo.GetValue (o, null);
- }
- elementName = xmlElements.GetElementName (elementType, member.Name);
- elementNs = xmlElements.GetElementNamespace (elementType);
- WriteElement (writer, xmlElements, elementName, elementNs, elementType, elementValue);
- }
- }
- [MonoTODO ("Remove FIXMEs")]
- private void WriteElement (XmlWriter writer, XmlAttributes attrs, string name, string ns, Type type, Object value)
- {
- //IF the element has XmlText Attribute, the name of the member is not serialized;
- if (attrs.XmlText != null && value != null)
- {
- if (type == typeof (object[]))
- {
- foreach(object obj in (object[]) value)
- writer.WriteRaw(""+obj);
- }
- else if (type == typeof (string[]))
- {
- foreach(string str in (string[]) value)
- writer.WriteRaw(str);
- }
- else if (type == typeof (XmlNode))
- {
- ((XmlNode) value).WriteTo (writer);
- }
- else if (type == typeof (XmlNode[]))
- {
- XmlNode[] nodes = (XmlNode[]) value;
- foreach (XmlNode node in nodes)
- node.WriteTo (writer);
- }
- return;
- }
- //If not text, serialize as an element
- //Start the element tag
- writer.WriteStartElement (name, ns);
- if (IsInbuiltType (type))
- {
- WriteBuiltinValue(writer,value);
- }
- else if (type.IsArray && value != null)
- {
- SerializeArray (writer, value);
- }
- else if (value is ICollection)
- {
- BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
- //Find a non indexer Count Property with return type of int
- PropertyInfo countInfo = type.GetProperty ("Count", flags, null, typeof (int), new Type[0], null);
- PropertyInfo itemInfo = type.GetProperty ("Item", flags, null, null, new Type[1] {typeof (int)}, null);
- int count = (int) countInfo.GetValue (value, null);
- if (count > 0)
- for (int i = 0; i < count; i++)
- {
- object itemValue = itemInfo.GetValue (value, new object[1] {i});
- Type itemType = itemInfo.PropertyType;
- if (itemValue != null)
- {
- string itemName = attrs.GetElementName (itemValue.GetType (), TypeTranslator.GetTypeData(itemType).ElementName);
- string itemNs = attrs.GetElementNamespace (itemValue.GetType ());
- writer.WriteStartElement (itemName, itemNs);
- SerializeMembers (writer, itemValue, false);
- writer.WriteEndElement ();
- }
- }
- }
- else if (value is IEnumerable)
- {
- // FIXME
- }
- else if (type.IsEnum)
- {
- writer.WriteString(GetXmlValue(value));
- }
- else
- { //Complex Type
- SerializeMembers (writer, value, false);
- }
- // Close the Element
- writer.WriteEndElement();
- }
- //Does not take care of any array specific Xml Attributes
- [MonoTODO]
- private void SerializeArray (XmlWriter writer, object o)
- {
- Array arr = (o as Array);
- if(arr == null || arr.Rank != 1)
- throw new ApplicationException("Expected a single dimension Array, Got "+ o);
- Type arrayType = arr.GetType().GetElementType();
- string arrayTypeName = TypeTranslator.GetTypeData(arrayType).ElementName;
- TypeData td = TypeTranslator.GetTypeData (arrayType);
- // Special Treatment for Byte array
- if(arrayType.Equals(typeof(byte)))
- {
- WriteBuiltinValue(writer,o);
- }
- else
- {
- for(int i=0; i< arr.Length; i++)
- {
- writer.WriteStartElement (td.ElementName);
- object value = arr.GetValue(i);
- if (IsInbuiltType (arrayType))
- {
- WriteBuiltinValue(writer, value);
- }
- else
- {
- SerializeMembers(writer, value, false);
- }
- writer.WriteEndElement();
- }
- }
- }
- /// <summary>
- /// If the type is a string, valuetype or primitive type we do not populate the TypeTable.
- /// If the type is an array, we populate the TypeTable with Element type of the array.
- /// If the type implements ICollection, it is handled differently. We do not care for its members.
- /// If the type implements IEnumberable, we check that it implements Add(). Don't care for members.
- /// </summary>
- [MonoTODO ("Remove FIXMEs")]
- private void FillTypeTable (Type type)
- {
- // If it's already in the table, don't add it again.
- if (typeTable.Contains (type))
- return;
- //For value types and strings we don't need the members.
- //FIXME: We will need the enum types probably.
- if (IsInbuiltType (type))
- return;
- //Array, ICollection and IEnumberable are treated differenty
- if (type.IsArray) {
- FillArrayType (type);
- return;
- }
- else if (type.IsEnum) {
- FillEnum (type);
- return;
- }
- else {
- //There must be a public constructor
- //if (!HasDefaultConstructor (type))
- //throw new Exception ("Can't Serialize Type " + type.Name + " since it does not have default Constructor");
- if (type.GetInterface ("ICollection") == typeof (System.Collections.ICollection)) {
- FillICollectionType (type);
- return;
- }
- // if (type.GetInterface ("IDictionary") == typeof (System.Collections.IDictionary)) {
- // throw new Exception ("Can't Serialize Type " + type.Name + " since it implements IDictionary");
- // }
- if (type.GetInterface ("IEnumerable") == typeof (System.Collections.IEnumerable)) {
- //FillIEnumerableType(type);
- //return;
- }
- }
- //Add the Class to the hashtable.
- //Each value of the hashtable has two objects, one is the hashtable with key of membername (for deserialization)
- //Other is an Array of XmlSerializernames, Array of XmlAttributes & Array of XmlElements.
- Object[] memberObj = new Object[4];
- typeTable.Add (type,memberObj);
- Hashtable memberTable = new Hashtable ();
- memberObj[0] = memberTable;
- memberTable.Add ("", XmlAttributes.FromClass (type));
- memberObj[1] = null;
- ArrayList attributes = new ArrayList ();
- memberObj[2] = attributes;
- ArrayList elements = new ArrayList ();
- memberObj[3] = elements;
- //Get the graph of the members. Graph is nothing but the order
- //in which MS implementation serializes the members.
- MemberInfo[] minfo = GetGraph (type);
- foreach (MemberInfo member in minfo) {
- FieldInfo fieldInfo = (member as FieldInfo);
- PropertyInfo propertyInfo = (member as PropertyInfo);
- if (memberTable [member.Name] != null)
- continue;
- if (fieldInfo != null) {
- //If field is readOnly or const, do not serialize it.
- if (fieldInfo.IsLiteral || fieldInfo.IsInitOnly)
- continue;
- XmlAttributes xmlAttributes = XmlAttributes.FromField (member, fieldInfo);
- //If XmlAttributes have XmlIgnore, ignore this member
- if (xmlAttributes.XmlIgnore)
- continue;
- //If this member is a XmlNs type, set the XmlNs object.
- if (xmlAttributes.Xmlns) {
- memberObj[1] = xmlAttributes;
- continue;
- }
- //If the member is a attribute Type, Add to attribute list
- if (xmlAttributes.isAttribute)
- attributes.Add (xmlAttributes);
- else //Add to elements
- elements.Add (xmlAttributes);
- //Add in the Hashtable.
- memberTable.Add (member.Name, xmlAttributes);
- if (xmlAttributes.XmlAnyAttribute != null || xmlAttributes.XmlText != null)
- continue;
- if (xmlAttributes.XmlElements.Count > 0) {
- foreach (XmlElementAttribute elem in xmlAttributes.XmlElements) {
- if (elem.Type != null)
- FillTypeTable (elem.Type);
- else
- FillTypeTable (fieldInfo.FieldType);
- }
- continue;
- }
- if (!IsInbuiltType (fieldInfo.FieldType))
- FillTypeTable (fieldInfo.FieldType);
- }
- else if (propertyInfo != null) {
- //If property is readonly or writeonly, do not serialize it.
- //Exceptions are properties whose return type is array, ICollection or IEnumerable
- //Indexers are not serialized unless the class Implements ICollection.
- if (!(propertyInfo.PropertyType.IsArray ||
- Implements (propertyInfo.PropertyType, typeof (ICollection)) ||
- (propertyInfo.PropertyType != typeof (string) &&
- Implements (propertyInfo.PropertyType, typeof (IEnumerable)))))
- {
- if(!(propertyInfo.CanRead && propertyInfo.CanWrite) || propertyInfo.GetIndexParameters ().Length != 0)
- continue;
- }
- XmlAttributes xmlAttributes = XmlAttributes.FromProperty (member, propertyInfo);
- // If XmlAttributes have XmlIgnore, ignore this member
- if (xmlAttributes.XmlIgnore)
- continue;
- // If this member is a XmlNs type, set the XmlNs object.
- if (xmlAttributes.Xmlns) {
- memberObj[1] = xmlAttributes;
- continue;
- }
- // If the member is a attribute Type, Add to attribute list
- if (xmlAttributes.isAttribute)
- attributes.Add (xmlAttributes);
- else //Add to elements
- elements.Add (xmlAttributes);
- // OtherWise add in the Hashtable.
- memberTable.Add (member.Name, xmlAttributes);
- if (xmlAttributes.XmlAnyAttribute != null || xmlAttributes.XmlText != null)
- continue;
- if (xmlAttributes.XmlElements.Count > 0) {
- foreach (XmlElementAttribute elem in xmlAttributes.XmlElements) {
- if (elem.Type != null)
- FillTypeTable (elem.Type);
- else
- FillTypeTable (propertyInfo.PropertyType);
- }
- continue;
- }
- if (!IsInbuiltType (propertyInfo.PropertyType))
- FillTypeTable (propertyInfo.PropertyType);
- }
- }
- // Sort the attributes for the members according to their Order
- // This is an extension to MS's Implementation and will be useful
- // if our reflection does not return the same order of elements
- // as MS .NET impl
- if (useOrder)
- BubbleSort (elements, XmlAttributes.attrComparer);
- }
- private void FillArrayType (Type type)
- {
- if (type.GetArrayRank () != 1)
- throw new Exception ("MultiDimensional Arrays are not Supported");
- Type arrayType = type.GetElementType ();
- if (arrayType.IsArray)
- FillArrayType (arrayType);
- else if (!IsInbuiltType (arrayType))
- FillTypeTable (arrayType);
- }
- private void FillICollectionType (Type type)
- {
- //Must have an public Indexer that takes an integer and
- //a public Count Property which returns an int.
- BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
- //Find a non indexer Count Property with return type of int
- PropertyInfo countProp = type.GetProperty ("Count", flags, null, typeof (int), new Type[0], null);
- if (countProp == null || !countProp.CanRead)
- throw new Exception ("Cannot Serialize " + type + " because it implements ICollectoion, but does not implement public Count property");
- //Find a indexer Item Property which takes an int
- PropertyInfo itemProp = type.GetProperty ("Item", flags, null, null, new Type[1] {typeof (int)}, null);
- if (itemProp == null || !itemProp.CanRead || !itemProp.CanWrite)
- throw new Exception ("Cannot Serialize " + type + " because it does not have a read/write indexer property that takes an int as argument");
- FillTypeTable (itemProp.PropertyType);
- }
- [MonoTODO]
- private void FillIEnumerableType (Type type)
- {
- //Must implement a public Add method that takes a single parameter.
- //The Add method's parameter must be of the same type as is returned from
- //the Current property on the value returned from GetEnumerator, or one of that type's bases.
- // We currently ignore enumerable types anyway, so this method was junked.
- // The code did not do what the documentation above says (if that is even possible!)
- return;
- }
- private void FillEnum (Type type)
- {
- Hashtable memberTable = new Hashtable ();
- BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
- typeTable.Add (type, memberTable);
- string[] names = Enum.GetNames (type);
- foreach (string name in names) {
- MemberInfo[] members = type.GetMember (name);
- if (members.Length != 1)
- throw new Exception("Should never happen. Enum member not present or more than one. " + name);
- XmlAttributes xmlAttributes = new XmlAttributes (members[0]);
- if (xmlAttributes.XmlIgnore)
- continue;
- if (xmlAttributes.XmlEnum != null)
- memberTable.Add (members[0].Name, xmlAttributes.XmlEnum.Name);
- else
- memberTable.Add (members[0].Name, members[0].Name);
- }
- }
- private bool HasDefaultConstructor (Type type)
- {
- ConstructorInfo defaultConstructor = type.GetConstructor (new Type[0]);
- if (defaultConstructor == null || defaultConstructor.IsAbstract || defaultConstructor.IsStatic || !defaultConstructor.IsPublic)
- return false;
- return true;
- }
- private bool IsInbuiltType (Type type)
- {
- if (type.IsEnum)
- return false;
- if (/* type.IsValueType || */type == typeof (string) || type.IsPrimitive)
- return true;
- if (type == typeof (DateTime) ||
- type == typeof (Guid) ||
- type == typeof (XmlNode) ||
- type.IsSubclassOf (typeof (XmlNode)))
- return true;
- return false;
- }
- private static MemberInfo[] GetGraph(Type type)
- {
- ArrayList typeGraph = new ArrayList ();
- GetGraph (type, typeGraph);
- return (MemberInfo[]) typeGraph.ToArray (typeof (MemberInfo));
- }
- private static void GetGraph (Type type, ArrayList typeGraph)
- {
- BindingFlags flags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
- if (type.BaseType == null)
- return;
- GetGraph (type.BaseType, typeGraph);
- typeGraph.AddRange (type.GetFields (flags));
- typeGraph.AddRange (type.GetProperties (flags));
- }
- private string GetXmlValue (object value)
- {
- if (value == null)
- return null;
- #region enum type
- if (value is Enum)
- {
- Type type = value.GetType ();
- if (typeTable.ContainsKey (type)) {
- Hashtable memberTable = (Hashtable) (typeTable[type]);
- if (type.IsDefined (typeof (FlagsAttribute), false)) {
- //If value is exactly a single enum member
- if (memberTable.Contains (value.ToString ()))
- return (string) memberTable[value.ToString ()];
- string retval = "";
- int enumval = (int) value;
- string[] names = Enum.GetNames (type);
- foreach (string key in names) {
- if (!memberTable.ContainsKey (key))
- continue;
- //Otherwise multiple values.
- int val = (int) Enum.Parse (type, key);
- if (val != 0 && (enumval & val) == val)
- retval += " " + (string) memberTable[Enum.GetName (type, val)];
- }
- retval = retval.Trim ();
- if (retval.Length == 0)
- return null;
- return retval;
- }
- else if (memberTable.ContainsKey (value.ToString ()))
- return (string) memberTable[value.ToString()];
- else
- return null;
- }
- else
- throw new Exception ("Unknown Enumeration");
- }
- #endregion
- if (value is byte[])
- return XmlCustomFormatter.FromByteArrayBase64((byte[])value);
- if (value is Guid)
- return XmlConvert.ToString((Guid)value);
- if(value is DateTime)
- return XmlConvert.ToString((DateTime)value);
- if(value is TimeSpan)
- return XmlConvert.ToString((TimeSpan)value);
- if(value is bool)
- return XmlConvert.ToString((bool)value);
- if(value is byte)
- return XmlConvert.ToString((byte)value);
- if(value is char)
- return XmlCustomFormatter.FromChar((char)value);
- if(value is decimal)
- return XmlConvert.ToString((decimal)value);
- if(value is double)
- return XmlConvert.ToString((double)value);
- if(value is short)
- return XmlConvert.ToString((short)value);
- if(value is int)
- return XmlConvert.ToString((int)value);
- if(value is long)
- return XmlConvert.ToString((long)value);
- if(value is sbyte)
- return XmlConvert.ToString((sbyte)value);
- if(value is float)
- return XmlConvert.ToString((float)value);
- if(value is ushort)
- return XmlConvert.ToString((ushort)value);
- if(value is uint)
- return XmlConvert.ToString((uint)value);
- if(value is ulong)
- return XmlConvert.ToString((ulong)value);
- if (value is XmlQualifiedName) {
- if (((XmlQualifiedName) value).IsEmpty)
- return null;
- }
- return (value == null) ? null : value.ToString ();
- }
- [MonoTODO ("Remove FIXMEs")]
- private static void ProcessAttributes (XmlAttributes attrs, Hashtable memberTable)
- {
- if (attrs.XmlAnyAttribute != null) {
- // FIXME
- }
- foreach (XmlAnyElementAttribute anyelem in attrs.XmlAnyElements)
- memberTable.Add (new XmlQualifiedName (anyelem.Name, anyelem.Namespace), attrs);
- if (attrs.XmlArray != null) {
- // FIXME
- }
- foreach (XmlArrayItemAttribute item in attrs.XmlArrayItems)
- memberTable.Add (new XmlQualifiedName (item.ElementName, item.Namespace), attrs);
- if (attrs.XmlAttribute != null)
- memberTable.Add (new XmlQualifiedName (attrs.XmlAttribute.AttributeName,attrs.XmlAttribute.Namespace), attrs);
- if (attrs.XmlChoiceIdentifier != null) {
- // FIXME
- }
- foreach (XmlElementAttribute elem in attrs.XmlElements)
- memberTable.Add (new XmlQualifiedName (elem.ElementName, elem.Namespace), attrs);
- if (attrs.XmlEnum != null) {
- // FIXME
- }
- if (attrs.XmlType != null)
- memberTable.Add (new XmlQualifiedName (attrs.XmlType.TypeName, attrs.XmlType.Namespace), attrs);
- }
- private bool Implements (Type type, Type interfaceType)
- {
- return (type.GetInterface (interfaceType.Name) == interfaceType);
- }
- private static void BubbleSort (ArrayList array, IComparer comparer)
- {
- int len = array.Count;
- object obj1, obj2;
- for (int i=0; i < len; i++) {
- for (int j=0; j < len -i -1; j++) {
- obj1 = array[j];
- obj2 = array[j+1];
- if (comparer.Compare (obj2 , obj1 ) < 0) {
- array[j] = obj2;
- array[j+1] = obj1;
- }
- }
- }
- }
- #endregion // Methods
- }
- }
|