PageRenderTime 51ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization/XmlFormatterSerializer.cs

http://github.com/mono/mono
C# | 217 lines | 159 code | 22 blank | 36 comment | 56 complexity | 0f39201361be1b3329c2883e0eeb523d MD5 | raw file
Possible License(s): GPL-2.0, CC-BY-SA-3.0, LGPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.1, Unlicense, Apache-2.0
  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.Generic;
  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. using QName = System.Xml.XmlQualifiedName;
  37. namespace System.Runtime.Serialization
  38. {
  39. internal class XmlFormatterSerializer
  40. {
  41. XmlDictionaryWriter writer;
  42. object graph;
  43. KnownTypeCollection types;
  44. bool save_id;
  45. bool ignore_unknown;
  46. IDataContractSurrogate surrogate;
  47. DataContractResolver resolver, default_resolver; // new in 4.0
  48. int max_items;
  49. List<object> objects = new List<object> ();
  50. Dictionary<object,string> references = new Dictionary<object,string> (); // preserve possibly referenced objects to ids. (new in 3.5 SP1)
  51. public static void Serialize (XmlDictionaryWriter writer, object graph, Type declaredType, KnownTypeCollection types,
  52. bool ignoreUnknown, int maxItems, string root_ns, bool preserveObjectReferences, DataContractResolver resolver, DataContractResolver defaultResolver)
  53. {
  54. new XmlFormatterSerializer (writer, types, ignoreUnknown, maxItems, root_ns, preserveObjectReferences, resolver, defaultResolver)
  55. .Serialize (/*graph != null ? graph.GetType () : */declaredType, graph); // FIXME: I believe it should always use declaredType, but such a change brings some test breakages.
  56. }
  57. public XmlFormatterSerializer (XmlDictionaryWriter writer, KnownTypeCollection types, bool ignoreUnknown,
  58. int maxItems, string root_ns, bool preserveObjectReferences,
  59. DataContractResolver resolver, DataContractResolver defaultResolver)
  60. {
  61. this.writer = writer;
  62. this.types = types;
  63. ignore_unknown = ignoreUnknown;
  64. max_items = maxItems;
  65. PreserveObjectReferences = preserveObjectReferences;
  66. this.resolver = resolver;
  67. this.default_resolver = defaultResolver;
  68. }
  69. public bool PreserveObjectReferences { get; private set; }
  70. public List<object> SerializingObjects {
  71. get { return objects; }
  72. }
  73. public XmlDictionaryWriter Writer {
  74. get { return writer; }
  75. }
  76. public void Serialize (Type type, object graph)
  77. {
  78. if (graph == null)
  79. writer.WriteAttributeString ("i", "nil", XmlSchema.InstanceNamespace, "true");
  80. #if !MOONLIGHT
  81. else if (type == typeof (XmlElement))
  82. ((XmlElement) graph).WriteTo (Writer);
  83. else if (type == typeof (XmlNode [])) {
  84. foreach (var xn in (XmlNode []) graph)
  85. xn.WriteTo (Writer);
  86. }
  87. #endif
  88. else {
  89. QName resolvedQName = null;
  90. if (resolver != null) {
  91. XmlDictionaryString rname, rns;
  92. if (resolver.TryResolveType (graph != null ? graph.GetType () : typeof (object), type, default_resolver, out rname, out rns))
  93. resolvedQName = new QName (rname.Value, rns.Value);
  94. }
  95. Type actualType = graph.GetType ();
  96. SerializationMap map;
  97. map = types.FindUserMap (actualType);
  98. // For some collection types, the actual type does not matter. So get nominal serialization type instead.
  99. // (The code below also covers the lines above, but I don't remove above lines to avoid extra search cost.)
  100. if (map == null) {
  101. // FIXME: not sure if type.IsInterface is the correct condition to determine whether items are serialized with i:type or not. (e.g. bug #675144 server response).
  102. actualType = types.GetSerializedType (type.IsInterface ? type : actualType);
  103. map = types.FindUserMap (actualType);
  104. }
  105. // If it is still unknown, then register it.
  106. if (map == null) {
  107. types.Add (actualType);
  108. map = types.FindUserMap (actualType);
  109. }
  110. bool explicityType = false;
  111. if(type != actualType)
  112. {
  113. // Check if underlying type of Nullable, mismatch the current type.
  114. if(type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
  115. explicityType = (type.GetGenericArguments () [0] != actualType);
  116. else
  117. explicityType = true;
  118. }
  119. if (explicityType && (map == null || map.OutputXsiType)) {
  120. QName qname = resolvedQName ?? types.GetXmlName (actualType);
  121. string name = qname.Name;
  122. string ns = qname.Namespace;
  123. if (qname == QName.Empty) {
  124. name = XmlConvert.EncodeLocalName (actualType.Name);
  125. ns = KnownTypeCollection.DefaultClrNamespaceBase + actualType.Namespace;
  126. } else if (qname.Namespace == KnownTypeCollection.MSSimpleNamespace)
  127. ns = XmlSchema.Namespace;
  128. if (writer.LookupPrefix (ns) == null) // it goes first (extraneous, but it makes att order compatible)
  129. writer.WriteXmlnsAttribute (null, ns);
  130. writer.WriteStartAttribute ("i", "type", XmlSchema.InstanceNamespace);
  131. writer.WriteQualifiedName (name, ns);
  132. writer.WriteEndAttribute ();
  133. }
  134. QName predef = KnownTypeCollection.GetPredefinedTypeName (actualType);
  135. if (predef != QName.Empty)
  136. SerializePrimitive (type, graph, predef);
  137. else
  138. map.Serialize (graph, this);
  139. }
  140. }
  141. public void SerializePrimitive (Type type, object graph, QName qname)
  142. {
  143. string label;
  144. if (TrySerializeAsReference (false, graph, out label))
  145. return;
  146. if (label != null)
  147. Writer.WriteAttributeString ("z", "Id", KnownTypeCollection.MSSimpleNamespace, label);
  148. bool isDateTimeOffset = false;
  149. // Handle DateTimeOffset type and DateTimeOffset?
  150. if (type == typeof (DateTimeOffset))
  151. isDateTimeOffset = true;
  152. else if(type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
  153. isDateTimeOffset = type.GetGenericArguments () [0] == typeof (DateTimeOffset);
  154. // It is the only exceptional type that does not serialize to string but serializes into complex element.
  155. if (isDateTimeOffset) {
  156. var v = (DateTimeOffset) graph;
  157. writer.WriteStartElement ("DateTime", KnownTypeCollection.DefaultClrNamespaceSystem);
  158. SerializePrimitive (typeof (DateTime), DateTime.SpecifyKind (v.DateTime.Subtract (v.Offset), DateTimeKind.Utc), KnownTypeCollection.GetPredefinedTypeName (typeof (DateTime)));
  159. writer.WriteEndElement ();
  160. writer.WriteStartElement ("OffsetMinutes", KnownTypeCollection.DefaultClrNamespaceSystem);
  161. SerializePrimitive (typeof (int), v.Offset.TotalMinutes, KnownTypeCollection.GetPredefinedTypeName (typeof (int)));
  162. writer.WriteEndElement ();
  163. }
  164. else
  165. writer.WriteString (KnownTypeCollection.PredefinedTypeObjectToString (graph));
  166. }
  167. public void WriteStartElement (string memberName, string memberNamespace, string contentNamespace)
  168. {
  169. writer.WriteStartElement (memberName, memberNamespace);
  170. if (!string.IsNullOrEmpty (contentNamespace) && contentNamespace != memberNamespace)
  171. writer.WriteXmlnsAttribute (null, contentNamespace);
  172. }
  173. public void WriteEndElement ()
  174. {
  175. writer.WriteEndElement ();
  176. }
  177. // returned bool: whether z:Ref is written or not.
  178. // out label: object label either in use or newly allocated.
  179. public bool TrySerializeAsReference (bool isMapReference, object graph, out string label)
  180. {
  181. label = null;
  182. if (!isMapReference && (!PreserveObjectReferences || graph == null || graph.GetType ().IsValueType))
  183. return false;
  184. if (references.TryGetValue (graph, out label)) {
  185. Writer.WriteAttributeString ("z", "Ref", KnownTypeCollection.MSSimpleNamespace, label);
  186. label = null; // do not write label
  187. return true;
  188. }
  189. label = "i" + (references.Count + 1);
  190. references.Add (graph, label);
  191. return false;
  192. }
  193. }
  194. }
  195. #endif