2003-01-26 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSerializer.cs
index bd60aeee2fb2ca2cd14f3f190730e13d5324aacb..252a1c7f2f3adda8618ad7526316f44b5c061317 100644 (file)
@@ -26,14 +26,15 @@ namespace System.Xml.Serialization {
 
                #region Fields
 
-               Type type;
+               Type xsertype;
                XmlAttributeOverrides overrides;
                Type[] extraTypes;
                XmlRootAttribute rootAttribute;
                string defaultNamespace;
-               static Hashtable typeTable;
+               Hashtable typeTable;
                bool useOrder;
                bool isNullable;
+               Hashtable typeMappings = new Hashtable ();
 
                #endregion // Fields
 
@@ -48,9 +49,9 @@ namespace System.Xml.Serialization {
                {
                }
 
-               [MonoTODO]
-               public XmlSerializer (XmlTypeMapping xmltypemapping)
+               public XmlSerializer (XmlTypeMapping xmlTypeMapping)
                {
+                       typeMappings.Add (xmlTypeMapping.TypeFullName, xmlTypeMapping);
                }
 
                public XmlSerializer (Type type, string defaultNamespace)
@@ -75,15 +76,33 @@ namespace System.Xml.Serialization {
 
                internal XmlSerializer (Hashtable typeTable)
                {
-                       typeTable = typeTable;
+                       this.typeTable = typeTable;
                }
 
-               public XmlSerializer (Type type, XmlAttributeOverrides overrides, Type[] extraTypes, XmlRootAttribute root, string defaultNamespace)
+               public XmlSerializer (Type type,
+                                     XmlAttributeOverrides overrides,
+                                     Type [] extraTypes,
+                                     XmlRootAttribute root,
+                                     string defaultNamespace)
                {
                        if (type == null)
-                               throw new ArgumentNullException ("type", "XmlSerializer can't be constructed with a null type");
-
-                       this.type = type;
+                               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);
                
@@ -131,15 +150,15 @@ namespace System.Xml.Serialization {
                        throw new NotImplementedException ();
                }
 
-               [MonoTODO]
                protected virtual XmlSerializationReader CreateReader ()
                {
+                       // This is what MS does!!!
                        throw new NotImplementedException ();
                }
 
-               [MonoTODO]
                protected virtual XmlSerializationWriter CreateWriter ()
                {
+                       // This is what MS does!!!
                        throw new NotImplementedException ();
                }
 
@@ -159,9 +178,9 @@ namespace System.Xml.Serialization {
                        throw new NotImplementedException ();
                }
 
-               [MonoTODO]
                protected virtual object Deserialize (XmlSerializationReader reader)
                {
+                       // This is what MS does!!!
                        throw new NotImplementedException ();
                }
 
@@ -199,7 +218,7 @@ namespace System.Xml.Serialization {
                
                public void Serialize (XmlWriter xmlWriter, object o)
                {
-                       Serialize (xmlWriter, o);
+                       Serialize (xmlWriter, o, null);
                }
                
                public void Serialize (Stream stream, object o, XmlSerializerNamespaces namespaces)
@@ -218,7 +237,16 @@ namespace System.Xml.Serialization {
 
                public void Serialize (XmlWriter writer, object o, XmlSerializerNamespaces namespaces)
                {       
-                       Type objType = o.GetType ();
+                       Type objType = xsertype;//o.GetType ();
+
+                       if (IsInbuiltType(objType)) \r
+                       {
+                               writer.WriteStartDocument ();
+                               SerializeBuiltIn (writer, o);
+                               writer.WriteEndDocument();
+                               return;
+                       }
+
                        string rootName = objType.Name;
                        string rootNs = String.Empty;
                        string rootPrefix = String.Empty;
@@ -233,15 +261,15 @@ namespace System.Xml.Serialization {
 
                        XmlSerializerNamespaces nss = new XmlSerializerNamespaces ();
                        XmlQualifiedName[] qnames;
-
-                       writer.WriteStartDocument ();
                        
-                       object[] memberObj = (object[]) typeTable[objType];
+                       writer.WriteStartDocument ();
+                       object [] memberObj = (object []) typeTable [objType];
                        if (memberObj == null)
-                               throw new Exception ("Unknown Type " + objType + " encountered during Serialization");
+                               throw new Exception ("Unknown Type " + objType +
+                                                    " encountered during Serialization");
 
-                       Hashtable memberTable = (Hashtable) memberObj[0];
-                       XmlAttributes xmlAttributes = (XmlAttributes) memberTable[""];
+                       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)
@@ -254,11 +282,12 @@ namespace System.Xml.Serialization {
                                rootNs  = xmlAttributes.XmlRoot.Namespace;
                        }
 
-                       if (namespaces.GetPrefix (rootNs) != null)
+                       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;
@@ -293,17 +322,63 @@ namespace System.Xml.Serialization {
                                writer.WriteAttributeString (String.Empty, "xmlns", null, rootNs);
 
                        SerializeMembers (writer, o, true);//, namespaces);
+
                        writer.WriteEndDocument ();
                }
 
+               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)) \r
+                       {
+                               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;
@@ -412,33 +487,47 @@ namespace System.Xml.Serialization {
                [MonoTODO ("Remove FIXMEs")]
                private void WriteElement (XmlWriter writer, XmlAttributes attrs, string name, string ns, Type type, Object value)
                {
-                       if (IsInbuiltType (type)) {
-                               string xmlValue = GetXmlValue (value);
-                               if (xmlValue != String.Empty && xmlValue != null)
-                                       writer.WriteElementString (name, ns,  xmlValue);
-                       }
-                       else if (attrs.XmlText != null && value != null) {
-                               if (type == typeof (object[])) {
-                                       // FIXME
+                       //IF the element has XmlText Attribute, the name of the member is not serialized;
+                       if (attrs.XmlText != null && value != null) \r
+                       {
+                               if (type == typeof (object[])) \r
+                               {
+                                       foreach(object obj in (object[]) value)
+                                               writer.WriteRaw(""+obj);
                                }
-                               else if (type == typeof (string[])) {
-                                       // FIXME
+                               else if (type == typeof (string[])) \r
+                               {
+                                       foreach(string str in (string[]) value)
+                                               writer.WriteRaw(str);
                                }
-                               else if (type == typeof (XmlNode)) {
+                               else if (type == typeof (XmlNode)) \r
+                               {
                                        ((XmlNode) value).WriteTo (writer);
                                }
-                               else if (type == typeof (XmlNode[])) {
+                               else if (type == typeof (XmlNode[])) \r
+                               {
                                        XmlNode[] nodes = (XmlNode[]) value;
                                        foreach (XmlNode node in nodes)
                                                node.WriteTo (writer);
                                }
+                               return;
                        }
-                       else if (type.IsArray && value != null) {
-                               writer.WriteStartElement (name, ns);
+
+                       //If not text, serialize as an element
+                       
+                       //Start the element tag
+                       writer.WriteStartElement  (name, ns);
+                       \r
+                       if (IsInbuiltType (type)) \r
+                       {
+                               WriteBuiltinValue(writer,value);
+                       }
+                       else if (type.IsArray && value != null) \r
+                       {
                                SerializeArray (writer, value);
-                               writer.WriteEndElement ();
                        }
-                       else if (value is ICollection) {
+                       else if (value is ICollection) \r
+                       {
                                BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
 
                                //Find a non indexer Count Property with return type of int
@@ -447,11 +536,14 @@ namespace System.Xml.Serialization {
                                int count = (int) countInfo.GetValue (value, null);
 
                                if (count > 0) 
-                                       for (int i = 0; i < count; i++) {
+                                       for (int i = 0; i < count; i++) \r
+                                       {
                                                object itemValue = itemInfo.GetValue (value, new object[1] {i});
+                                               Type   itemType  = itemInfo.PropertyType;
 
-                                               if (itemValue != null) {
-                                                       string itemName = attrs.GetElementName (itemValue.GetType (), name);
+                                               if (itemValue != null) \r
+                                               {
+                                                       string itemName = attrs.GetElementName (itemValue.GetType (), TypeTranslator.GetTypeData(itemType).ElementName);
                                                        string itemNs = attrs.GetElementNamespace (itemValue.GetType ());
 
                                                        writer.WriteStartElement (itemName, itemNs);
@@ -460,28 +552,58 @@ namespace System.Xml.Serialization {
                                                }
                                        }
                        }
-                       else if (value is IEnumerable) {
+                       else if (value is IEnumerable) \r
+                       {
                                // FIXME
                        }
-                       else if (type.IsEnum) {
+                       else if (type.IsEnum) \r
+                       {
                                // FIXME
                        }
-                       else if (value != null) { //Complex Type?
-                               string itemName = attrs.GetElementName (value.GetType (), name);
-                               string itemNs = attrs.GetElementNamespace (value.GetType ());
-                               writer.WriteStartElement (itemName, itemNs);
+                       else\r
+                       { //Complex Type
                                SerializeMembers (writer, value, false);
-                               writer.WriteEndElement ();
-                       }
-                       else {
-                               // FIXME
                        }
+
+                       // Close the Element
+                       writer.WriteEndElement();
                }
 
+               //Does not take care of any array specific Xml Attributes
                [MonoTODO]
                private void SerializeArray (XmlWriter writer, object o)
                {
-                       throw new NotImplementedException ();
+                       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);
+                       writer.WriteStartElement (td.ElementName);
+                       Console.WriteLine(td.ElementName);
+                       //Special Treatment for Byte array
+                       if(arrayType.Equals(typeof(byte)))
+                       {
+                               WriteBuiltinValue(writer,o);
+                       }
+                       else
+                       {
+                               for(int i=0; i< arr.Length; i++)
+                               {
+                                       object value = arr.GetValue(i);
+                                       if (IsInbuiltType (arrayType)) \r
+                                       {
+                                               WriteBuiltinValue(writer, value);
+                                       }
+                                       else
+                                       {
+                                               SerializeMembers(writer, value, false);
+                                       }
+                               }
+                       }
+                       writer.WriteEndElement();
                }
 
                /// <summary>
@@ -519,6 +641,9 @@ namespace System.Xml.Serialization {
                                        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;
@@ -732,6 +857,9 @@ namespace System.Xml.Serialization {
                                return false;
                        if (type.IsValueType || type == typeof (string) || type.IsPrimitive)
                                return true;
+                       if (type == typeof (DateTime) || type == typeof (XmlNode) || type.IsSubclassOf (typeof (XmlNode)))
+                               return true;
+                               
                        return false;
                }
 
@@ -757,8 +885,9 @@ namespace System.Xml.Serialization {
                {
                        if (value == null)
                                return null;
-
-                       if (value is Enum) {
+                       #region enum type
+                       if (value is Enum) \r
+                       {
                                Type type = value.GetType ();
                                
                                if (typeTable.ContainsKey (type)) {
@@ -797,8 +926,41 @@ namespace System.Xml.Serialization {
                                else
                                        throw new Exception ("Unknown Enumeration");
                        }
-                       if (value is bool)
-                               return (bool) value ? "true" : "false";
+                       #endregion
+                       if (value is byte[])
+                               return XmlCustomFormatter.FromByteArrayHex((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;