Merge pull request #103 from XTZGZoReX/master
[mono.git] / mcs / class / System.XML / System.Xml.Serialization / XmlSerializationWriter.cs
index bccbce7a9c90d2c88fd62e212cfc8bbd46f04c09..890d22022d9c65b8267d1676f96756e8ae277d19 100644 (file)
 
 using System;
 using System.Collections;
+using System.Collections.Generic;
 using System.Globalization;
 using System.Text;
 using System.Xml;
 using System.Xml.Schema;
 using System.Runtime.Serialization;
+using System.Reflection;
 
-namespace System.Xml.Serialization {
-       public abstract class XmlSerializationWriter {
+namespace System.Xml.Serialization 
+{
+       public abstract class XmlSerializationWriter 
+#if NET_2_0
+               : XmlSerializationGeneratedCode
+#endif
+       {
 
                #region Fields
 
@@ -48,7 +55,11 @@ namespace System.Xml.Serialization {
 
                ArrayList namespaces;
                XmlWriter writer;
+#if MOONLIGHT
+               Queue<object> referencedElements;
+#else
                Queue referencedElements;
+#endif
                Hashtable callbacks;
                Hashtable serializedObjects;
                const string xmlNamespace = "http://www.w3.org/2000/xmlns/";
@@ -72,7 +83,7 @@ namespace System.Xml.Serialization {
                        {
                                namespaces = new ArrayList ();
                                foreach (XmlQualifiedName ns in nss.ToArray())
-                                       if (ns.Name != "")
+                                       if (ns.Name != "" && ns.Namespace != "")
                                                namespaces.Add (ns);
                        }       
                }
@@ -81,10 +92,17 @@ namespace System.Xml.Serialization {
 
                #region Properties
 
+#if MOONLIGHT
+               protected IList XmlNamespaces {
+                       get { return namespaces; }
+                       set { namespaces = (value as ArrayList); }
+               }
+#else
                protected ArrayList Namespaces {
                        get { return namespaces; }
                        set { namespaces = value; }
                }
+#endif
 
                protected XmlWriter Writer {
                        get { return writer; }
@@ -106,7 +124,7 @@ namespace System.Xml.Serialization {
                        if (callbacks == null) callbacks = new Hashtable ();
                        callbacks.Add (type, info);
                }
-
+               
                protected Exception CreateChoiceIdentifierValueException (string value, string identifier, string name, string ns)
                {
                        string message = string.Format ("Value '{0}' of the choice"
@@ -291,6 +309,15 @@ namespace System.Xml.Serialization {
                        Writer.WriteAttributeString (prefix, localName, ns, value);
                }
 
+#if !MOONLIGHT
+               void WriteXmlNode (XmlNode node)
+               {
+                       if (node is XmlDocument)
+                               node = ((XmlDocument) node).DocumentElement;
+
+                       node.WriteTo (Writer);
+               }
+
                protected void WriteElementEncoded (XmlNode node, string name, string ns, bool isNullable, bool any)
                {
                        if (name != string.Empty)
@@ -303,12 +330,12 @@ namespace System.Xml.Serialization {
                                else
                                {
                                        Writer.WriteStartElement (name, ns);
-                                       node.WriteTo (Writer);
+                                       WriteXmlNode (node);
                                        Writer.WriteEndElement ();
                                }
                        }
                        else
-                               node.WriteTo (Writer);
+                               WriteXmlNode(node);
                }
 
                protected void WriteElementLiteral (XmlNode node, string name, string ns, bool isNullable, bool any)
@@ -323,13 +350,14 @@ namespace System.Xml.Serialization {
                                else
                                {
                                        Writer.WriteStartElement (name, ns);
-                                       node.WriteTo (Writer);
+                                       WriteXmlNode (node);
                                        Writer.WriteEndElement ();
                                }
                        }
                        else
-                               node.WriteTo (Writer);
+                               WriteXmlNode (node);
                }
+#endif
 
                protected void WriteElementQualifiedName (string localName, XmlQualifiedName value)
                {
@@ -476,10 +504,13 @@ namespace System.Xml.Serialization {
                {
                        if (ns == null)
                                return;
-
+#if MOONLIGHT
+                       IEnumerable<XmlQualifiedName> namespaces = ns.GetNamespaces ();
+#else
                        ICollection namespaces = ns.Namespaces.Values;
+#endif
                        foreach (XmlQualifiedName qn in namespaces) {
-                               if (qn.Namespace != String.Empty && Writer.LookupPrefix (qn.Namespace) == null)
+                               if (qn.Namespace != String.Empty && Writer.LookupPrefix (qn.Namespace) != qn.Name)
                                        WriteAttribute ("xmlns", qn.Name, xmlNamespace, qn.Namespace);
                        }
                }
@@ -603,7 +634,7 @@ namespace System.Xml.Serialization {
 
                        CheckReferenceQueue ();
 
-                       if (callbacks.ContainsKey (o.GetType ()))
+                       if (callbacks != null && callbacks.ContainsKey (o.GetType ()))
                        {
                                WriteCallbackInfo info = (WriteCallbackInfo) callbacks[o.GetType()];
                                if (o.GetType ().IsEnum) {
@@ -621,12 +652,16 @@ namespace System.Xml.Serialization {
                        }
                        else
                        {
-                               // Must be a primitive type
+                               // Must be a primitive type or array of primitives
                                TypeData td = TypeTranslator.GetTypeData (o.GetType ());
-                               if (td.SchemaType != SchemaTypes.Primitive)
+                               if (td.SchemaType == SchemaTypes.Primitive) {
+                                       WriteXsiType (td.XmlType, XmlSchema.Namespace);
+                                       Writer.WriteString (XmlCustomFormatter.ToXmlString (td, o));
+                               } else if (IsPrimitiveArray (td)) {
+                                       if (!AlreadyQueued (o)) referencedElements.Enqueue (o);
+                                       Writer.WriteAttributeString ("href", "#" + GetId (o, true));
+                               } else
                                        throw new InvalidOperationException ("Invalid type: " + o.GetType().FullName);
-                               WriteXsiType(td.XmlType, XmlSchema.Namespace);
-                               Writer.WriteString (XmlCustomFormatter.ToXmlString (td, o));
                        }
 
                        WriteEndElement ();
@@ -642,16 +677,61 @@ namespace System.Xml.Serialization {
                                object o = referencedElements.Dequeue ();
                                TypeData td = TypeTranslator.GetTypeData (o.GetType ());
                                WriteCallbackInfo info = (WriteCallbackInfo) callbacks[o.GetType()];
-                               WriteStartElement (info.TypeName, info.TypeNs, true);
-                               Writer.WriteAttributeString ("id", GetId (o, false));
+                               
+                               if (info != null) {
+                                       WriteStartElement (info.TypeName, info.TypeNs, true);
+                                       Writer.WriteAttributeString ("id", GetId (o, false));
 
-                               if (td.SchemaType != SchemaTypes.Array) // Array use its own "arrayType" attribute
-                                       WriteXsiType(info.TypeName, info.TypeNs);
+                                       if (td.SchemaType != SchemaTypes.Array) // Array use its own "arrayType" attribute
+                                               WriteXsiType(info.TypeName, info.TypeNs);
 
-                               info.Callback (o);
-                               WriteEndElement ();
+                                       info.Callback (o);
+                                       WriteEndElement ();
+                               } else if (IsPrimitiveArray (td)) {
+                                       WriteArray (o, td);
+                               }
                        }
                }
+               
+               bool IsPrimitiveArray (TypeData td)
+               {
+                       if (td.SchemaType == SchemaTypes.Array) {
+                               if (td.ListItemTypeData.SchemaType == SchemaTypes.Primitive || td.ListItemType == typeof(object))
+                                       return true;
+                               return IsPrimitiveArray (td.ListItemTypeData);
+                       } else
+                               return false;
+               }
+
+               void WriteArray (object o, TypeData td)
+               {
+                       TypeData itemTypeData = td;
+                       string xmlType;
+                       int nDims = -1;
+
+                       do {
+                               itemTypeData = itemTypeData.ListItemTypeData;
+                               xmlType = itemTypeData.XmlType;
+                               nDims++;
+                       }
+                       while (itemTypeData.SchemaType == SchemaTypes.Array );
+
+                       while (nDims-- > 0)
+                               xmlType += "[]";
+
+                       WriteStartElement("Array", XmlSerializer.EncodingNamespace, true);
+                       Writer.WriteAttributeString("id", GetId(o, false));
+                       if (td.SchemaType == SchemaTypes.Array) {
+                               Array a = (Array)o;
+                               int len = a.Length;
+                               Writer.WriteAttributeString("arrayType", XmlSerializer.EncodingNamespace, GetQualifiedName(xmlType, XmlSchema.Namespace) + "[" + len.ToString() + "]");
+                               for (int i = 0; i < len; i++) {
+                                       WritePotentiallyReferencingElement("Item", "", a.GetValue(i), td.ListItemType, false, true);
+                               }
+                       }
+                       WriteEndElement();
+               }
+
 
                protected void WriteReferencingElement (string n, string ns, object o)
                {
@@ -680,7 +760,11 @@ namespace System.Xml.Serialization {
                {
                        if (referencedElements == null)  
                        {
+#if MOONLIGHT
+                               referencedElements = new Queue<object> ();
+#else
                                referencedElements = new Queue ();
+#endif
                                InitCallbacks ();
                        }
                }
@@ -692,17 +776,27 @@ namespace System.Xml.Serialization {
                }
 
                protected void WriteSerializable (IXmlSerializable serializable, string name, string ns, bool isNullable)
+               {
+                       WriteSerializable (serializable, name, ns, isNullable, true);
+               }
+
+#if NET_2_0
+               protected
+#endif
+               void WriteSerializable (IXmlSerializable serializable, string name, string ns, bool isNullable, bool wrapped)
                {
                        if (serializable == null)
                        {
-                               if (isNullable) WriteNullTagLiteral (name, ns);
+                               if (isNullable && wrapped) WriteNullTagLiteral (name, ns);
                                return;
                        }
                        else
                        {
-                               Writer.WriteStartElement (name, ns);
+                               if (wrapped)
+                                       Writer.WriteStartElement (name, ns);
                                serializable.WriteXml (Writer);
-                               Writer.WriteEndElement ();
+                               if (wrapped)
+                                       Writer.WriteEndElement ();
                        }
                }
 
@@ -733,27 +827,38 @@ namespace System.Xml.Serialization {
                }
 
                protected void WriteStartElement (string name, string ns, object o, bool writePrefixed)
+               {
+                       WriteStartElement (name, ns, o, writePrefixed, namespaces);
+               }
+
+#if NET_2_0
+               protected void WriteStartElement (string name, string ns, Object o, bool writePrefixed, XmlSerializerNamespaces xmlns)
+               {
+                       WriteStartElement (name, ns, o, writePrefixed, xmlns != null ? xmlns.ToArray () : null);
+               }
+#endif
+
+               void WriteStartElement (string name, string ns, object o, bool writePrefixed, ICollection namespaces)
                {
                        if (o != null)
                        {
                                if (serializedObjects.Contains (o))
-                                       throw new InvalidOperationException ("A cirtular reference was detected while serializing an object of type " + o.GetType().Name);
+                                       throw new InvalidOperationException ("A circular reference was detected while serializing an object of type " + o.GetType().Name);
                                else
                                        serializedObjects [o] = o;
                        }
                        
-                       WriteState oldState = Writer.WriteState;
-                       
                        string prefix = null;
                        
                        if (topLevelElement && ns != null && ns.Length != 0)
                        {
-                               foreach (XmlQualifiedName qn in namespaces)
-                                       if (qn.Namespace == ns) {
-                                               prefix = qn.Name;
-                                               writePrefixed = true;
-                                               break;
-                                       }
+                               if (namespaces != null)
+                                       foreach (XmlQualifiedName qn in namespaces)
+                                               if (qn.Namespace == ns) {
+                                                       prefix = qn.Name;
+                                                       writePrefixed = true;
+                                                       break;
+                                               }
                        }
 
                        if (writePrefixed && ns != string.Empty)
@@ -787,8 +892,15 @@ namespace System.Xml.Serialization {
                {
                        string value;
                        TypeData td = TypeTranslator.GetTypeData (o.GetType ());
+                       if (td.SchemaType != SchemaTypes.Primitive)
+                               throw new InvalidOperationException (String.Format ("The type of the argument object '{0}' is not primitive.", td.FullTypeName));
 
-                       name = XmlCustomFormatter.FromXmlName (name);
+                       if (name == null) {
+                               ns = td.IsXsdType ? XmlSchema.Namespace : XmlSerializer.WsdlTypesNamespace;
+                               name = td.XmlType;
+                       }
+                       else
+                               name = XmlCustomFormatter.FromXmlName (name);
                        Writer.WriteStartElement (name, ns);
 
                        if (o is XmlQualifiedName)
@@ -800,10 +912,11 @@ namespace System.Xml.Serialization {
                        {
                                if (td.SchemaType != SchemaTypes.Primitive)
                                        throw new InvalidOperationException (string.Format (unexpectedTypeError, o.GetType().FullName));
-                               WriteXsiType (td.XmlType, XmlSchema.Namespace);
+                               WriteXsiType (td.XmlType, td.IsXsdType ? XmlSchema.Namespace : XmlSerializer.WsdlTypesNamespace);
                        }
 
                        WriteValue (value);
+
                        Writer.WriteEndElement ();
                }
 
@@ -818,6 +931,7 @@ namespace System.Xml.Serialization {
                                Writer.WriteString (value);
                }
 
+#if !MOONLIGHT
                protected void WriteXmlAttribute (XmlNode node)
                {
                        WriteXmlAttribute (node, null);
@@ -843,6 +957,7 @@ namespace System.Xml.Serialization {
                        
                        WriteAttribute (attr.Prefix, attr.LocalName, attr.NamespaceURI, attr.Value);
                }
+#endif
 
                protected void WriteXsiType (string name, string ns)
                {
@@ -852,6 +967,52 @@ namespace System.Xml.Serialization {
                                WriteAttribute ("type", XmlSchema.InstanceNamespace, name);
                }
                
+#if NET_2_0
+
+               protected Exception CreateInvalidAnyTypeException (object o)
+               {
+                       if (o == null)
+                               return new InvalidOperationException ("null is invalid as anyType in XmlSerializer");
+                       else
+                               return CreateInvalidAnyTypeException (o.GetType ());
+               }
+               
+               protected Exception CreateInvalidAnyTypeException (Type t)
+               {
+                       return new InvalidOperationException (String.Format ("An object of type '{0}' is invalid as anyType in XmlSerializer", t));
+               }
+
+               protected Exception CreateInvalidEnumValueException (object value, string typeName)
+               {
+                       return new InvalidOperationException (string.Format(CultureInfo.CurrentCulture,
+                               "'{0}' is not a valid value for {1}.", value, typeName));
+               }
+
+               protected static string FromEnum (long value, string[] values, long[] ids, string typeName)
+               {
+                       return XmlCustomFormatter.FromEnum (value, values, ids, typeName);
+               }
+
+               [MonoTODO]
+               protected string FromXmlQualifiedName (XmlQualifiedName xmlQualifiedName, bool ignoreEmpty)
+               {
+                       throw new NotImplementedException ();
+               }
+               
+               [MonoTODO]
+               protected static Assembly ResolveDynamicAssembly (string assemblyFullName)
+               {
+                       throw new NotImplementedException ();
+               }
+               
+               [MonoTODO]
+               protected bool EscapeName
+               {
+                       get { throw new NotImplementedException(); }
+                       set { throw new NotImplementedException(); }
+               }
+#endif
+
                #endregion
 
                class WriteCallbackInfo