2 // XmlFormatterSerializer.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2005 Novell, Inc. http://www.novell.com
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:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
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.
30 using System.Collections;
32 using System.Reflection;
33 using System.Runtime.Serialization.Formatters.Binary;
35 using System.Xml.Schema;
37 using QName = System.Xml.XmlQualifiedName;
39 namespace System.Runtime.Serialization
41 internal class XmlFormatterSerializer
43 XmlDictionaryWriter writer;
45 KnownTypeCollection types;
49 IDataContractSurrogate surrogate;
52 ArrayList objects = new ArrayList ();
53 Hashtable references = new Hashtable (); // preserve possibly referenced objects to ids. (new in 3.5 SP1)
55 public static void Serialize (XmlDictionaryWriter writer, object graph,
56 KnownTypeCollection types,
57 bool ignoreUnknown, int maxItems, string root_ns, bool preserveObjectReferences)
59 new XmlFormatterSerializer (writer, types, ignoreUnknown, maxItems, root_ns, preserveObjectReferences)
60 .Serialize (graph != null ? graph.GetType () : null, graph);
63 public XmlFormatterSerializer (XmlDictionaryWriter writer,
64 KnownTypeCollection types,
65 bool ignoreUnknown, int maxItems, string root_ns, bool preserveObjectReferences)
69 ignore_unknown = ignoreUnknown;
71 PreserveObjectReferences = preserveObjectReferences;
74 public bool PreserveObjectReferences { get; private set; }
76 public ArrayList SerializingObjects {
77 get { return objects; }
80 public IDictionary References {
81 get { return references; }
84 public XmlDictionaryWriter Writer {
85 get { return writer; }
88 public void Serialize (Type type, object graph)
91 writer.WriteAttributeString ("nil", XmlSchema.InstanceNamespace, "true");
93 Type actualType = graph.GetType ();
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.)
99 actualType = types.GetSerializedType (actualType);
100 map = types.FindUserMap (actualType);
102 // If it is still unknown, then register it.
104 types.Add (actualType);
105 map = types.FindUserMap (actualType);
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 ();
123 QName predef = KnownTypeCollection.GetPredefinedTypeName (actualType);
124 if (predef != QName.Empty)
125 SerializePrimitive (type, graph, predef);
127 map.Serialize (graph, this);
131 public void SerializePrimitive (Type type, object graph, QName qname)
134 if (TrySerializeAsReference (false, graph, out label))
137 Writer.WriteAttributeString ("z", "Id", KnownTypeCollection.MSSimpleNamespace, label);
139 // writer.WriteStartAttribute ("type", XmlSchema.InstanceNamespace);
140 // writer.WriteQualifiedName (qname.Name, qname.Namespace);
141 // writer.WriteEndAttribute ();
142 writer.WriteString (KnownTypeCollection.PredefinedTypeObjectToString (graph));
145 public void WriteStartElement (string memberName, string memberNamespace, string contentNamespace)
147 writer.WriteStartElement (memberName, memberNamespace);
148 if (!string.IsNullOrEmpty (contentNamespace) && contentNamespace != memberNamespace)
149 writer.WriteXmlnsAttribute (null, contentNamespace);
152 public void WriteEndElement ()
154 writer.WriteEndElement ();
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)
162 if (!isMapReference && (!PreserveObjectReferences || graph == null || graph.GetType ().IsValueType))
165 label = (string) References [graph];
167 Writer.WriteAttributeString ("z", "Ref", KnownTypeCollection.MSSimpleNamespace, label);
168 label = null; // do not write label
172 label = "i" + (References.Count + 1);
173 References.Add (graph, label);