[wcf] serialization member namespace was wrong when root namesp ace is given. Fixed...
[mono.git] / mcs / class / System.Runtime.Serialization / System.Runtime.Serialization / XmlFormatterSerializer.cs
1 //
2 // XmlFormatterSerializer.cs
3 //
4 // Author:
5 //      Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2005 Novell, Inc.  http://www.novell.com
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 #if NET_2_0
29 using System;
30 using System.Collections;
31 using System.IO;
32 using System.Reflection;
33 using System.Runtime.Serialization.Formatters.Binary;
34 using System.Xml;
35 using System.Xml.Schema;
36
37 using QName = System.Xml.XmlQualifiedName;
38
39 namespace System.Runtime.Serialization
40 {
41         internal class XmlFormatterSerializer
42         {
43                 XmlDictionaryWriter writer;
44                 object graph;
45                 KnownTypeCollection types;
46                 
47                 bool save_id;
48                 bool ignore_unknown;
49                 IDataContractSurrogate surrogate;
50                 int max_items;
51
52                 ArrayList objects = new ArrayList ();
53                 Hashtable references = new Hashtable (); // preserve possibly referenced objects to ids. (new in 3.5 SP1)
54
55                 public static void Serialize (XmlDictionaryWriter writer, object graph,
56                         KnownTypeCollection types,
57                         bool ignoreUnknown, int maxItems, string root_ns, bool preserveObjectReferences)
58                 {
59                         new XmlFormatterSerializer (writer, types, ignoreUnknown, maxItems, root_ns, preserveObjectReferences)
60                                 .Serialize (graph != null ? graph.GetType () : null, graph);
61                 }
62
63                 public XmlFormatterSerializer (XmlDictionaryWriter writer,
64                         KnownTypeCollection types,
65                         bool ignoreUnknown, int maxItems, string root_ns, bool preserveObjectReferences)
66                 {
67                         this.writer = writer;
68                         this.types = types;
69                         ignore_unknown = ignoreUnknown;
70                         max_items = maxItems;
71                         PreserveObjectReferences = preserveObjectReferences;
72                 }
73
74                 public bool PreserveObjectReferences { get; private set; }
75
76                 public ArrayList SerializingObjects {
77                         get { return objects; }
78                 }
79
80                 public IDictionary References {
81                         get { return references; }
82                 }
83
84                 public XmlDictionaryWriter Writer {
85                         get { return writer; }
86                 }
87
88                 public void Serialize (Type type, object graph)
89                 {
90                         if (graph == null)
91                                 writer.WriteAttributeString ("nil", XmlSchema.InstanceNamespace, "true");
92                         else {
93                                 Type actualType = graph.GetType ();
94
95                                 SerializationMap map = types.FindUserMap (actualType);
96                                 // For some collection types, the actual type does not matter. So get nominal serialization type instead.
97                                 // (The code below also covers the lines above, but I don't remove above lines to avoid extra search cost.)
98                                 if (map == null) {
99                                         actualType = types.GetSerializedType (actualType);
100                                         map = types.FindUserMap (actualType);
101                                 }
102                                 // If it is still unknown, then register it.
103                                 if (map == null) {
104                                         types.Add (actualType);
105                                         map = types.FindUserMap (actualType);
106                                 }
107
108                                 if (actualType != type && (map == null || map.OutputXsiType)) {
109                                         QName qname = types.GetXmlName (actualType);
110                                         string name = qname.Name;
111                                         string ns = qname.Namespace;
112                                         if (qname == QName.Empty) {
113                                                 name = XmlConvert.EncodeLocalName (actualType.Name);
114                                                 ns = KnownTypeCollection.DefaultClrNamespaceBase + actualType.Namespace;
115                                         } else if (qname.Namespace == KnownTypeCollection.MSSimpleNamespace)
116                                                 ns = XmlSchema.Namespace;
117                                         if (writer.LookupPrefix (ns) == null) // it goes first (extraneous, but it makes att order compatible)
118                                                 writer.WriteXmlnsAttribute (null, ns);
119                                         writer.WriteStartAttribute ("type", XmlSchema.InstanceNamespace);
120                                         writer.WriteQualifiedName (name, ns);
121                                         writer.WriteEndAttribute ();
122                                 }
123                                 QName predef = KnownTypeCollection.GetPredefinedTypeName (actualType);
124                                 if (predef != QName.Empty)
125                                         SerializePrimitive (type, graph, predef);
126                                 else
127                                         map.Serialize (graph, this);
128                         }
129                 }
130
131                 public void SerializePrimitive (Type type, object graph, QName qname)
132                 {
133                         string label;
134                         if (TrySerializeAsReference (false, graph, out label))
135                                 return;
136                         if (label != null)
137                                 Writer.WriteAttributeString ("z", "Id", KnownTypeCollection.MSSimpleNamespace, label);
138
139 //                      writer.WriteStartAttribute ("type", XmlSchema.InstanceNamespace);
140 //                      writer.WriteQualifiedName (qname.Name, qname.Namespace);
141 //                      writer.WriteEndAttribute ();
142                         writer.WriteString (KnownTypeCollection.PredefinedTypeObjectToString (graph));
143                 }
144
145                 public void WriteStartElement (string memberName, string memberNamespace, string contentNamespace)
146                 {
147                         writer.WriteStartElement (memberName, memberNamespace);
148                         if (!string.IsNullOrEmpty (contentNamespace) && contentNamespace != memberNamespace)
149                                 writer.WriteXmlnsAttribute (null, contentNamespace);
150                 }
151
152                 public void WriteEndElement ()
153                 {
154                         writer.WriteEndElement ();
155                 }
156
157                 // returned bool: whether z:Ref is written or not.
158                 // out label: object label either in use or newly allocated.
159                 public bool TrySerializeAsReference (bool isMapReference, object graph, out string label)
160                 {
161                         label = null;
162                         if (!isMapReference && (!PreserveObjectReferences || graph == null || graph.GetType ().IsValueType))
163                                 return false;
164
165                         label = (string) References [graph];
166                         if (label != null) {
167                                 Writer.WriteAttributeString ("z", "Ref", KnownTypeCollection.MSSimpleNamespace, label);
168                                 label = null; // do not write label
169                                 return true;
170                         }
171
172                         label = "i" + (References.Count + 1);
173                         References.Add (graph, label);
174
175                         return false;
176                 }
177         }
178 }
179 #endif