[Mono-list] patch: XML Deserialization
Elan Feingold
efeingold@mn.rr.com
Thu, 27 Feb 2003 14:12:44 -0600
This is a multi-part message in MIME format.
------=_NextPart_000_00FA_01C2DE6A.4C6BFB80
Content-Type: text/plain;
charset="us-ascii"
Content-Transfer-Encoding: 7bit
I'm resending with tabs as requested.
-elan
> * XmlCustomFormatter.cs: Support for converting byte arrays to and
from
> Base64.
>
> * XmlSerialize.cs: Fix serialization of arrays to work better.
> Implemented simple XML deserialization, works for nested objects,
> arrays, etc. Most complex thing I tested was a structure containing
two
> arrays of structures. The code is fairly simple and easy to extend.
>
> My first C# and first Mono work, so please don't laugh.
>
> Best regards,
>
> -elan
------=_NextPart_000_00FA_01C2DE6A.4C6BFB80
Content-Type: application/octet-stream;
name="patch"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment;
filename="patch"
Index: System.Xml/XmlTextReader.cs=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: /mono/mcs/class/System.XML/System.Xml/XmlTextReader.cs,v=0A=
retrieving revision 1.49=0A=
diff -u -r1.49 XmlTextReader.cs=0A=
--- System.Xml/XmlTextReader.cs 16 Feb 2003 14:31:06 -0000 1.49=0A=
+++ System.Xml/XmlTextReader.cs 27 Feb 2003 20:10:52 -0000=0A=
@@ -1604,7 +1604,7 @@=0A=
private string ReadName ()=0A=
{=0A=
if (!XmlChar.IsFirstNameChar (PeekChar ()))=0A=
- throw new XmlException ("a name did not start with a legal =
character");=0A=
+ throw new XmlException ("a name did not start with a legal =
character " + PeekChar());=0A=
=0A=
nameLength =3D 0;=0A=
=0A=
Index: System.Xml.Serialization/XmlCustomFormatter.cs=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: =
/mono/mcs/class/System.XML/System.Xml.Serialization/XmlCustomFormatter.cs=
,v=0A=
retrieving revision 1.4=0A=
diff -u -r1.4 XmlCustomFormatter.cs=0A=
--- System.Xml.Serialization/XmlCustomFormatter.cs 19 Sep 2002 07:16:01 =
-0000 1.4=0A=
+++ System.Xml.Serialization/XmlCustomFormatter.cs 27 Feb 2003 20:10:53 =
-0000=0A=
@@ -16,10 +16,9 @@=0A=
=0A=
#region Methods=0A=
=0A=
- [MonoTODO]=0A=
- internal static byte[] FromByteArrayBase64 (byte[] value)=0A=
+ internal static string FromByteArrayBase64 (byte[] value)=0A=
{=0A=
- throw new NotImplementedException ();=0A=
+ return Convert.ToBase64String(value);=0A=
}=0A=
=0A=
internal static string FromByteArrayHex (byte[] value)=0A=
@@ -86,6 +85,11 @@=0A=
foreach (string token in tokens)=0A=
output.Append (FromXmlNmToken (token));=0A=
return output.ToString ();=0A=
+ }=0A=
+=0A=
+ internal static byte[] ToByteArrayBase64 (string value)=0A=
+ {=0A=
+ return Convert.FromBase64String(value);=0A=
}=0A=
=0A=
internal static char ToChar (string value)=0A=
Index: System.Xml.Serialization/XmlSerializationWriter.cs=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: =
/mono/mcs/class/System.XML/System.Xml.Serialization/XmlSerializationWrite=
r.cs,v=0A=
retrieving revision 1.6=0A=
diff -u -r1.6 XmlSerializationWriter.cs=0A=
--- System.Xml.Serialization/XmlSerializationWriter.cs 13 Sep 2002 =
21:15:11 -0000 1.6=0A=
+++ System.Xml.Serialization/XmlSerializationWriter.cs 27 Feb 2003 =
20:10:53 -0000=0A=
@@ -84,7 +84,7 @@=0A=
return new InvalidOperationException (message);=0A=
}=0A=
=0A=
- protected static byte[] FromByteArrayBase64 (byte[] value)=0A=
+ protected static string FromByteArrayBase64 (byte[] value)=0A=
{=0A=
return XmlCustomFormatter.FromByteArrayBase64 (value);=0A=
}=0A=
Index: System.Xml.Serialization/XmlSerializer.cs=0A=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=
RCS file: =
/mono/mcs/class/System.XML/System.Xml.Serialization/XmlSerializer.cs,v=0A=
retrieving revision 1.18=0A=
diff -u -r1.18 XmlSerializer.cs=0A=
--- System.Xml.Serialization/XmlSerializer.cs 16 Feb 2003 07:27:47 -0000 =
1.18=0A=
+++ System.Xml.Serialization/XmlSerializer.cs 27 Feb 2003 20:10:54 -0000=0A=
@@ -6,9 +6,11 @@=0A=
// John Donagher (john@webmeta.com)=0A=
// Ajay kumar Dwivedi (adwiv@yahoo.com)=0A=
// Tim Coleman (tim@timcoleman.com)=0A=
+// Elan Feingold (ef10@cornell.edu)=0A=
//=0A=
// (C) 2002 John Donagher, Ajay kumar Dwivedi=0A=
// Copyright (C) Tim Coleman, 2002=0A=
+// (C) 2003 Elan Feingold=0A=
// =0A=
=0A=
using System;=0A=
@@ -17,6 +19,7 @@=0A=
using System.Reflection;=0A=
using System.Xml;=0A=
using System.Xml.Schema;=0A=
+using System.Text;=0A=
=0A=
namespace System.Xml.Serialization { =0A=
/// <summary>=0A=
@@ -80,10 +83,10 @@=0A=
}=0A=
=0A=
public XmlSerializer (Type type,=0A=
- XmlAttributeOverrides overrides,=0A=
- Type [] extraTypes,=0A=
- XmlRootAttribute root,=0A=
- string defaultNamespace)=0A=
+ XmlAttributeOverrides overrides,=0A=
+ Type [] extraTypes,=0A=
+ XmlRootAttribute root,=0A=
+ string defaultNamespace)=0A=
{=0A=
if (type =3D=3D null)=0A=
throw new ArgumentNullException ("type");=0A=
@@ -162,22 +165,208 @@=0A=
throw new NotImplementedException ();=0A=
}=0A=
=0A=
- [MonoTODO]=0A=
public object Deserialize (Stream stream)=0A=
{=0A=
- throw new NotImplementedException ();=0A=
+ XmlTextReader xmlReader =3D new XmlTextReader(stream);=0A=
+ return Deserialize(xmlReader);=0A=
}=0A=
- [MonoTODO]=0A=
+=0A=
public object Deserialize (TextReader textReader)=0A=
{=0A=
- throw new NotImplementedException ();=0A=
+ XmlTextReader xmlReader =3D new XmlTextReader(textReader);=0A=
+ return Deserialize(xmlReader);=0A=
}=0A=
- [MonoTODO]=0A=
- public object Deserialize (XmlReader xmlReader)=0A=
+=0A=
+ public bool DeserializeComposite(XmlReader xmlReader, ref Object =
theObject)=0A=
{=0A=
- throw new NotImplementedException ();=0A=
+ Type objType =3D theObject.GetType();=0A=
+ bool retVal =3D true;=0A=
+=0A=
+ //Console.WriteLine("DeserializeComposite({0})", objType);=0A=
+ =0A=
+ // Are we at an empty element?=0A=
+ if (xmlReader.IsEmptyElement =3D=3D true)=0A=
+ return retVal;=0A=
+=0A=
+ // Read each field, counting how many we find.=0A=
+ for (int numFields=3D0; xmlReader.Read(); )=0A=
+ {=0A=
+ XmlNodeType xmlNodeType =3D xmlReader.NodeType;=0A=
+ bool isEmpty =3D xmlReader.IsEmptyElement;=0A=
+ =0A=
+ if (xmlNodeType =3D=3D XmlNodeType.Element)=0A=
+ {=0A=
+ // Read the field.=0A=
+ DeserializeField(xmlReader, ref theObject, xmlReader.Name);=0A=
+ numFields++;=0A=
+ }=0A=
+ else if (xmlNodeType =3D=3D XmlNodeType.EndElement)=0A=
+ {=0A=
+ if (numFields =3D=3D 0)=0A=
+ {=0A=
+ //Console.WriteLine("Empty object deserialized, ignoring.");=0A=
+ retVal =3D false;=0A=
+ }=0A=
+ =0A=
+ return retVal;=0A=
+ }=0A=
+ }=0A=
+=0A=
+ return retVal;=0A=
}=0A=
=0A=
+ public void DeserializeField(XmlReader xmlReader,=0A=
+ ref Object theObject,=0A=
+ String fieldName)=0A=
+ {=0A=
+ // Get the type=0A=
+ FieldInfo fieldInfo =3D theObject.GetType().GetField(fieldName);=0A=
+ Type fieldType =3D fieldInfo.FieldType;=0A=
+ Object value =3D null;=0A=
+ bool isEmptyField =3D xmlReader.IsEmptyElement;=0A=
+=0A=
+ //Console.WriteLine("DeserializeField({0} of type {1}", fieldName, =
fieldType);=0A=
+=0A=
+ if (fieldType.IsArray && fieldType !=3D typeof(System.Byte[]))=0A=
+ {=0A=
+ // Create an empty array list.=0A=
+ ArrayList list =3D new ArrayList();=0A=
+=0A=
+ // Call out to deserialize it.=0A=
+ DeserializeArray(xmlReader, list, fieldType.GetElementType());=0A=
+ value =3D list.ToArray(fieldType.GetElementType());=0A=
+ }=0A=
+ else if (isEmptyField =3D=3D true && fieldType.IsArray)=0A=
+ {=0A=
+ // Must be a byte array, just create an empty one.=0A=
+ value =3D new byte[0];=0A=
+ }=0A=
+ else if (isEmptyField =3D=3D false && =0A=
+ (IsInbuiltType(fieldType) || fieldType.IsEnum || =
fieldType.IsArray))=0A=
+ {=0A=
+ // Built in, set it.=0A=
+ while (xmlReader.Read())=0A=
+ {=0A=
+ if (xmlReader.NodeType =3D=3D XmlNodeType.Text)=0A=
+ {=0A=
+ //Console.WriteLine(" -> value is '{0}'", xmlReader.Value);=0A=
+ =0A=
+ if (fieldType =3D=3D typeof(Guid))=0A=
+ value =3D XmlConvert.ToGuid(xmlReader.Value);=0A=
+ else if (fieldType =3D=3D typeof(Boolean))=0A=
+ value =3D XmlConvert.ToBoolean(xmlReader.Value);=0A=
+ else if (fieldType =3D=3D typeof(String))=0A=
+ value =3D xmlReader.Value;=0A=
+ else if (fieldType =3D=3D typeof(Int64))=0A=
+ value =3D XmlConvert.ToInt64(xmlReader.Value);=0A=
+ else if (fieldType =3D=3D typeof(DateTime))=0A=
+ value =3D XmlConvert.ToDateTime(xmlReader.Value);=0A=
+ else if (fieldType.IsEnum)=0A=
+ value =3D Enum.Parse(fieldType, xmlReader.Value);=0A=
+ else if (fieldType =3D=3D typeof(System.Byte[]))=0A=
+ value =3D XmlCustomFormatter.ToByteArrayBase64(xmlReader.Value);=0A=
+ else=0A=
+ Console.WriteLine("Error (type is '{0})'", fieldType);=0A=
+ =0A=
+ break;=0A=
+ }=0A=
+ }=0A=
+ }=0A=
+ else=0A=
+ {=0A=
+ //Console.WriteLine("Creating new {0}", fieldType);=0A=
+=0A=
+ // Create the new complex object.=0A=
+ value =3D System.Activator.CreateInstance(fieldType);=0A=
+=0A=
+ // Recurse, allowing the method to whack the object if it's empty.=0A=
+ DeserializeComposite(xmlReader, ref value);=0A=
+ }=0A=
+=0A=
+ //Console.WriteLine(" Setting {0} to '{1}'", fieldName, value);=0A=
+=0A=
+ // Set the field value.=0A=
+ theObject.GetType().InvokeMember(fieldName,=0A=
+ BindingFlags.SetField, =0A=
+ null,=0A=
+ theObject, =0A=
+ new Object[] { value },=0A=
+ null, null, null);=0A=
+=0A=
+ // We need to munch the end.=0A=
+ if (IsInbuiltType(fieldType) || =0A=
+ fieldType.IsEnum || =0A=
+ fieldType =3D=3D typeof(System.Byte[]))=0A=
+ {=0A=
+ if (isEmptyField =3D=3D false)=0A=
+ while (xmlReader.Read() && xmlReader.NodeType !=3D =
XmlNodeType.EndElement)=0A=
+ ;=0A=
+ }=0A=
+ =0A=
+ }=0A=
+=0A=
+ public void DeserializeArray(XmlReader xmlReader, ArrayList theList, =
Type theType)=0A=
+ {=0A=
+ //Console.WriteLine(" DeserializeArray({0})", theType);=0A=
+=0A=
+ if (xmlReader.IsEmptyElement)=0A=
+ {=0A=
+ //Console.WriteLine(" DeserializeArray -> empty, nothing to do =
here");=0A=
+ return;=0A=
+ }=0A=
+=0A=
+ while (xmlReader.Read())=0A=
+ {=0A=
+ XmlNodeType xmlNodeType =3D xmlReader.NodeType;=0A=
+ bool isEmpty =3D xmlReader.IsEmptyElement;=0A=
+=0A=
+ if (xmlNodeType =3D=3D XmlNodeType.Element)=0A=
+ {=0A=
+ // Must be an element of the array, create it.=0A=
+ Object obj =3D System.Activator.CreateInstance(theType);=0A=
+=0A=
+ //Console.WriteLine(" created obj of type '{0}'", obj.GetType());=0A=
+=0A=
+ // Deserialize and add.=0A=
+ if (DeserializeComposite(xmlReader, ref obj))=0A=
+ {=0A=
+ theList.Add(obj);=0A=
+ }=0A=
+ }=0A=
+ =0A=
+ if ((xmlNodeType =3D=3D XmlNodeType.Element && isEmpty) ||=0A=
+ (xmlNodeType =3D=3D XmlNodeType.EndElement))=0A=
+ {=0A=
+ return;=0A=
+ }=0A=
+ }=0A=
+ }=0A=
+=0A=
+ public object Deserialize(XmlReader xmlReader)=0A=
+ {=0A=
+ Object obj =3D null;=0A=
+=0A=
+ // Read each node in the tree.=0A=
+ while (xmlReader.Read())=0A=
+ {=0A=
+ if (xmlReader.NodeType =3D=3D XmlNodeType.Element)=0A=
+ {=0A=
+ // Create the top level object.=0A=
+ //Console.WriteLine("Creating '{0}'", xsertype.FullName);=0A=
+ obj =3D System.Activator.CreateInstance(xsertype);=0A=
+=0A=
+ // Deserialize it.=0A=
+ DeserializeComposite(xmlReader, ref obj);=0A=
+ }=0A=
+ else if (xmlReader.NodeType =3D=3D XmlNodeType.EndElement)=0A=
+ {=0A=
+ return obj;=0A=
+ }=0A=
+ } =0A=
+=0A=
+ return obj;=0A=
+ } =0A=
+=0A=
protected virtual object Deserialize (XmlSerializationReader reader)=0A=
{=0A=
// This is what MS does!!!=0A=
@@ -266,7 +455,7 @@=0A=
object [] memberObj =3D (object []) typeTable [objType];=0A=
if (memberObj =3D=3D null)=0A=
throw new Exception ("Unknown Type " + objType +=0A=
- " encountered during Serialization");=0A=
+ " encountered during Serialization");=0A=
=0A=
Hashtable memberTable =3D (Hashtable) memberObj [0];=0A=
XmlAttributes xmlAttributes =3D (XmlAttributes) memberTable [""];=0A=
@@ -369,7 +558,7 @@=0A=
=0A=
Type objType =3D o.GetType ();=0A=
=0A=
- if (IsInbuiltType(objType))=20
+ if (IsInbuiltType(objType))=0A=
{=0A=
SerializeBuiltIn (writer, o);=0A=
return;=0A=
@@ -420,7 +609,7 @@=0A=
=0A=
attributeName =3D xmlAttributes.GetAttributeName (attributeType, =
member.Name);=0A=
attributeNs =3D xmlAttributes.GetAttributeNamespace (attributeType);=0A=
- =0A=
+=0A=
if (attributeValue is XmlQualifiedName) {=0A=
XmlQualifiedName qname =3D (XmlQualifiedName) attributeValue;=0A=
=0A=
@@ -474,12 +663,12 @@=0A=
elementValue =3D fieldInfo.GetValue (o);=0A=
}=0A=
else {=0A=
- elementType =3D propertyInfo.PropertyType;=0A=
+ elementType =3D propertyInfo.PropertyType;=0A=
elementValue =3D propertyInfo.GetValue (o, null);=0A=
}=0A=
-=0A=
elementName =3D xmlElements.GetElementName (elementType, =
member.Name);=0A=
elementNs =3D xmlElements.GetElementNamespace (elementType);=0A=
+=0A=
WriteElement (writer, xmlElements, elementName, elementNs, =
elementType, elementValue);=0A=
}=0A=
}=0A=
@@ -539,7 +728,7 @@=0A=
for (int i =3D 0; i < count; i++)=20
{=0A=
object itemValue =3D itemInfo.GetValue (value, new object[1] {i});=0A=
- Type itemType =3D itemInfo.PropertyType;=0A=
+ Type itemType =3D itemInfo.PropertyType;=0A=
=0A=
if (itemValue !=3D null)=20
{=0A=
@@ -558,7 +747,7 @@=0A=
}=0A=
else if (type.IsEnum)=20
{=0A=
- // FIXME=0A=
+ writer.WriteString(GetXmlValue(value));=0A=
}=0A=
else
{ //Complex Type=0A=
@@ -581,9 +770,8 @@=0A=
string arrayTypeName =3D =
TypeTranslator.GetTypeData(arrayType).ElementName;=0A=
=0A=
TypeData td =3D TypeTranslator.GetTypeData (arrayType);=0A=
- writer.WriteStartElement (td.ElementName);=0A=
- Console.WriteLine(td.ElementName);=0A=
- //Special Treatment for Byte array=0A=
+=0A=
+ // Special Treatment for Byte array=0A=
if(arrayType.Equals(typeof(byte)))=0A=
{=0A=
WriteBuiltinValue(writer,o);=0A=
@@ -592,8 +780,10 @@=0A=
{=0A=
for(int i=3D0; i< arr.Length; i++)=0A=
{=0A=
+ writer.WriteStartElement (td.ElementName);=0A=
+=0A=
object value =3D arr.GetValue(i);=0A=
- if (IsInbuiltType (arrayType))=20
+ if (IsInbuiltType (arrayType))=0A=
{=0A=
WriteBuiltinValue(writer, value);=0A=
}=0A=
@@ -601,9 +791,10 @@=0A=
{=0A=
SerializeMembers(writer, value, false);=0A=
}=0A=
+=0A=
+ writer.WriteEndElement();=0A=
}=0A=
}=0A=
- writer.WriteEndElement();=0A=
}=0A=
=0A=
/// <summary>=0A=
@@ -615,6 +806,7 @@=0A=
[MonoTODO ("Remove FIXMEs")]=0A=
private void FillTypeTable (Type type)=0A=
{=0A=
+ // If it's already in the table, don't add it again.=0A=
if (typeTable.Contains (type))=0A=
return;=0A=
=0A=
@@ -634,8 +826,8 @@=0A=
}=0A=
else {=0A=
//There must be a public constructor=0A=
- if (!HasDefaultConstructor (type))=0A=
- throw new Exception ("Can't Serialize Type " + type.Name + " since =
it does not have default Constructor");=0A=
+ //if (!HasDefaultConstructor (type))=0A=
+ //throw new Exception ("Can't Serialize Type " + type.Name + " =
since it does not have default Constructor");=0A=
=0A=
if (type.GetInterface ("ICollection") =3D=3D typeof =
(System.Collections.ICollection)) {=0A=
FillICollectionType (type);=0A=
@@ -681,6 +873,7 @@=0A=
continue;=0A=
=0A=
if (fieldInfo !=3D null) {=0A=
+=0A=
//If field is readOnly or const, do not serialize it.=0A=
if (fieldInfo.IsLiteral || fieldInfo.IsInitOnly)=0A=
continue;=0A=
@@ -724,11 +917,15 @@=0A=
FillTypeTable (fieldInfo.FieldType);=0A=
} =0A=
else if (propertyInfo !=3D null) {=0A=
+=0A=
//If property is readonly or writeonly, do not serialize it.=0A=
//Exceptions are properties whose return type is array, =
ICollection or IEnumerable=0A=
//Indexers are not serialized unless the class Implements =
ICollection.=0A=
- if (!(propertyInfo.PropertyType.IsArray || Implements =
(propertyInfo.PropertyType, typeof (ICollection)) || =0A=
- (propertyInfo.PropertyType !=3D typeof (string) && Implements =
(propertyInfo.PropertyType, typeof (IEnumerable))))) {=0A=
+ if (!(propertyInfo.PropertyType.IsArray || =0A=
+ Implements (propertyInfo.PropertyType, typeof (ICollection)) || =0A=
+ (propertyInfo.PropertyType !=3D typeof (string) && =0A=
+ Implements (propertyInfo.PropertyType, typeof (IEnumerable)))))=0A=
+ {=0A=
if(!(propertyInfo.CanRead && propertyInfo.CanWrite) || =
propertyInfo.GetIndexParameters ().Length !=3D 0)=0A=
continue;=0A=
}=0A=
@@ -858,9 +1055,12 @@=0A=
{=0A=
if (type.IsEnum)=0A=
return false;=0A=
- if (type.IsValueType || type =3D=3D typeof (string) || =
type.IsPrimitive)=0A=
+ if (/* type.IsValueType || */type =3D=3D typeof (string) || =
type.IsPrimitive)=0A=
return true;=0A=
- if (type =3D=3D typeof (DateTime) || type =3D=3D typeof (XmlNode) || =
type.IsSubclassOf (typeof (XmlNode)))=0A=
+ if (type =3D=3D typeof (DateTime) || =0A=
+ type =3D=3D typeof (Guid) ||=0A=
+ type =3D=3D typeof (XmlNode) || =0A=
+ type.IsSubclassOf (typeof (XmlNode)))=0A=
return true;=0A=
=0A=
return false;=0A=
@@ -931,7 +1131,7 @@=0A=
}=0A=
#endregion=0A=
if (value is byte[])=0A=
- return XmlCustomFormatter.FromByteArrayHex((byte[])value);=0A=
+ return XmlCustomFormatter.FromByteArrayBase64((byte[])value);=0A=
if (value is Guid)=0A=
return XmlConvert.ToString((Guid)value);=0A=
if(value is DateTime)=0A=
------=_NextPart_000_00FA_01C2DE6A.4C6BFB80--