get { return references; }
}
+ XmlDocument document;
+
+ XmlDocument XmlDocument {
+ get { return (document = document ?? new XmlDocument ()); }
+ }
+
// This method handles z:Ref, xsi:nil and primitive types, and then delegates to DeserializeByMap() for anything else.
+
public object Deserialize (Type type, XmlReader reader)
{
- QName graph_qname = types.GetQName (type);
+ if (type == typeof (XmlElement))
+ return XmlDocument.ReadNode (reader);
+ else if (type == typeof (XmlNode [])) {
+ reader.ReadStartElement ();
+ var l = new List<XmlNode> ();
+ for(; !reader.EOF && reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ())
+ l.Add (XmlDocument.ReadNode (reader));
+ reader.ReadEndElement ();
+ return l.ToArray ();
+ }
+ QName graph_qname = null;
+
+ if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>)) {
+ Type internal_type = type.GetGenericArguments () [0];
+
+ if (types.FindUserMap(internal_type) != null) {
+ graph_qname = types.GetQName (internal_type);
+ }
+ }
+
+ if (graph_qname == null)
+ graph_qname = types.GetQName (type);
+
string itype = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
if (itype != null) {
- string[] parts = itype.Split (':');
+ string [] parts = itype.Split (':');
if (parts.Length > 1)
- graph_qname = new QName (parts [1], reader.LookupNamespace (reader.NameTable.Get (parts[0])));
+ graph_qname = new QName (parts [1], reader.LookupNamespace (reader.NameTable.Get (parts [0])));
else
- graph_qname = new QName (itype, reader.NamespaceURI);
+ graph_qname = new QName (itype, reader.LookupNamespace (String.Empty));
}
string label = reader.GetAttribute ("Ref", KnownTypeCollection.MSSimpleNamespace);
if (isNil) {
reader.Skip ();
- if (!type.IsValueType)
+ if (!type.IsValueType || type == typeof (void))
return null;
else if (type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
return null;
}
}
- if (KnownTypeCollection.GetPrimitiveTypeFromName (graph_qname.Name) != null) {
+ if (KnownTypeCollection.GetPrimitiveTypeFromName (graph_qname) != null) {
string id = reader.GetAttribute ("Id", KnownTypeCollection.MSSimpleNamespace);
- string value;
- if (reader.IsEmptyElement) {
- reader.Read (); // advance
- if (type.IsValueType)
- return Activator.CreateInstance (type);
- else
- // FIXME: Workaround for creating empty objects of the correct type.
- value = String.Empty;
- }
- else
- value = reader.ReadElementContentAsString ();
- object ret = KnownTypeCollection.PredefinedTypeStringToObject (value, graph_qname.Name, reader);
+ object ret = DeserializePrimitive (type, reader, graph_qname);
+
if (id != null) {
if (references.ContainsKey (id))
throw new InvalidOperationException (String.Format ("Object with Id '{0}' already exists as '{1}'", id, references [id]));
return DeserializeByMap (graph_qname, type, reader);
}
+ object DeserializePrimitive (Type type, XmlReader reader, QName qname)
+ {
+ bool isDateTimeOffset = false;
+ // Handle DateTimeOffset type and DateTimeOffset?.
+ if (type == typeof (DateTimeOffset))
+ isDateTimeOffset = true;
+ else if(type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>))
+ isDateTimeOffset = type.GetGenericArguments () [0] == typeof (DateTimeOffset);
+ // It is the only exceptional type that does not serialize to string but serializes into complex element.
+ if (isDateTimeOffset) {
+ if (reader.IsEmptyElement) {
+ reader.Read ();
+ return default (DateTimeOffset);
+ }
+ reader.ReadStartElement ();
+ reader.MoveToContent ();
+ var date = reader.ReadElementContentAsDateTime ("DateTime", KnownTypeCollection.DefaultClrNamespaceSystem);
+ var off = TimeSpan.FromMinutes (reader.ReadElementContentAsInt ("OffsetMinutes", KnownTypeCollection.DefaultClrNamespaceSystem));
+ reader.MoveToContent ();
+ reader.ReadEndElement ();
+ return new DateTimeOffset (DateTime.SpecifyKind (date.ToUniversalTime () + off, DateTimeKind.Unspecified), off);
+ }
+
+ string value;
+ if (reader.IsEmptyElement) {
+ reader.Read (); // advance
+ if (type.IsValueType)
+ return Activator.CreateInstance (type);
+ else
+ // FIXME: Workaround for creating empty objects of the correct type.
+ value = String.Empty;
+ }
+ else
+ value = reader.ReadElementContentAsString ();
+ return KnownTypeCollection.PredefinedTypeStringToObject (value, qname.Name, reader);
+ }
+
object DeserializeByMap (QName name, Type type, XmlReader reader)
{
- SerializationMap map = types.FindUserMap (type); // use type rather than name as the type could be a "resolved" one.
+ SerializationMap map = null;
+ // List<T> and T[] have the same QName, use type to find map work better.
+ if(name.Name.StartsWith ("ArrayOf", StringComparison.Ordinal) || resolved_qnames.ContainsKey (name))
+ map = types.FindUserMap (type);
+ else
+ map = types.FindUserMap (name); // use type when the name is "resolved" one. Otherwise use name (there are cases that type cannot be resolved by type).
if (map == null && (name.Name.StartsWith ("ArrayOf", StringComparison.Ordinal) ||
name.Namespace == KnownTypeCollection.MSArraysNamespace ||
name.Namespace.StartsWith (KnownTypeCollection.DefaultClrNamespaceBase, StringComparison.Ordinal))) {
Type GetTypeFromNamePair (string name, string ns)
{
- Type p = KnownTypeCollection.GetPrimitiveTypeFromName (name); // FIXME: namespace?
+ Type p = KnownTypeCollection.GetPrimitiveTypeFromName (new QName (name, ns));
if (p != null)
return p;
bool makeArray = false;
if (name.StartsWith ("ArrayOf", StringComparison.Ordinal)) {
name = name.Substring (7); // strip "ArrayOf"
if (ns == KnownTypeCollection.MSArraysNamespace)
- return GetTypeFromNamePair (name, String.Empty).MakeArrayType ();
+ return GetTypeFromNamePair (name, KnownTypeCollection.MSSimpleNamespace).MakeArrayType ();
makeArray = true;
}
foreach (var ass in AppDomain.CurrentDomain.GetAssemblies ()) {
Type [] types;
-#if MOONLIGHT
- try {
- types = ass.GetTypes ();
- } catch (System.Reflection.ReflectionTypeLoadException rtle) {
- types = rtle.Types;
- }
-#else
types = ass.GetTypes ();
-#endif
if (types == null)
continue;