In case somebody in a hunder years from now wants to know how i solved this
problem here it is.
BE warned i have not cleand this code up yet so there are still variables
and alsorts floting around. this is a proof of concept at the moment.
So the problem was that i had this bit of XML that i needed to Deserialize
into an object but i didnt know what object to use untill runtime.
EXAMPLE:
<TR CST="2008-08-28T12:15:34+01:00" SRT="2008-08-28T12:15:40.12232+01:00" />
[Serializable]
[XmlType("TR")]
public class TimeSyncResponseMessage
{
[XmlAttribute("CST")]
public DateTime ClientSendTime;
[XmlAttribute("SRT")]
public DateTime ServerResponseTime;
}
[Serializable]
[XmlType("TS")]
public class TimeSyncRequestMessage
{
[XmlAttribute("T")]
public DateTime SendTime;
}
SOLUTION:
I always Wrap the XML in a <MT> tag, and i make all the other classes
Nested in a MessageTypes class. this ment i did not have to alter the
Objects in any way and the only change to the XML was the addition of a root
tag that can be stripped away.
Now i can Deserialize any one of the message types that i need to. using the
object i know MessageTypes.
If any of the Child Classes ever change all i need to do is replace it in
the MessageTypes class and that is the only change i will need to make.
Everything else will just work.
<MT><TR CST="2008-08-28T12:15:34+01:00"
SRT="2008-08-28T12:15:40.12232+01:00" /></MT>
using System.Xml.Serialization;
using System;
using System.Collections.Generic;
using System.Text;
namespace CommsViewer
{
[Serializable]
[XmlType("MT")]
public class MessageTypes
{
[Serializable]
[XmlType("TR")]
public class TimeSyncResponseMessage
{
[XmlAttribute("CST")]
public DateTime ClientSendTime;
[XmlAttribute("SRT")]
public DateTime ServerResponseTime;
}
[Serializable]
[XmlType("TS")]
public class TimeSyncRequestMessage
{
[XmlAttribute("T")]
public DateTime SendTime;
}
}
}
//===========================================
//FORM CODE
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using System.Reflection;
namespace CommsViewer
{
/// <summary>
/// This will try and Serialize an XML string into an object
/// </summary>
/// <param name="xml">Xml Text Reader to be Serialized</param>
/// <param name="objectType">The Object Type you want
returned</param>
/// <returns>And Object of the type requested</returns>
public static object XmlToObject(XmlTextReader xml, Type objectType)
{
object obj = null;
XmlSerializer xs = new XmlSerializer(objectType);
obj = xs.Deserialize(xml);
return obj;
}
//listBox1 Holds all the XML Strings i want to test
//listBox2 Is used to display the Objects fields and there values.
private void listBox1_SelectedIndexChanged(object sender, EventArgs
e)
{
listBox2.Items.Clear();
using (MemoryStream ms = new MemoryStream())
{
MemoryStream ms2 = new MemoryStream();
//Get the XML
byte[] data =
System.Text.Encoding.Default.GetBytes(listBox1.SelectedItem.ToString());
//Put In Stream
ms.Write(data, 0, data.Length);
ms.Seek(0, SeekOrigin.Begin);
//Duplicate Streem
ms2.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
ms2.Seek(0, SeekOrigin.Begin);
//Create 2 XML Readers
XmlTextReader xrMT = new XmlTextReader(ms);
XmlTextReader xrInner = new XmlTextReader(ms2);
//Read the first
xrMT.Read();
xrMT.MoveToContent();
String xrMTTag = xrMT.LocalName;
//Create Object
MessageTypes commsData = (MessageTypes)XmlToObject(xrMT,
typeof(MessageTypes));
//Get Object Type
Type objectType = commsData.GetType();
//Get The Inner XML from second stream
xrInner.Read();
string innerXML = xrInner.ReadInnerXml();
//Create a XML reader from the Inner XML
data = System.Text.Encoding.Default.GetBytes(innerXML);
ms2 = new MemoryStream();
ms2.Write(data, 0, data.Length);
ms2.Seek(0, SeekOrigin.Begin);
xrInner = new XmlTextReader(ms2);
//Get the Tag name
xrInner.Read();
String xrTag = xrInner.LocalName;
//ms2.Close();
// get all the Nested Types for the object
foreach (Type mt in objectType.GetNestedTypes())
{
//Check all the Attributes
foreach (object oAtt in mt.GetCustomAttributes(true))
{
//If it si XML Type Attribute then Check if it is
the one we need
if (typeof(XmlTypeAttribute) == oAtt.GetType())
{
XmlTypeAttribute xa = (XmlTypeAttribute)oAtt;
//It the Tag is the same as the inner XML we
know we have the right Type
if (xrTag == xa.TypeName)
{
//Display what we are doing
listBox2.Items.Add(xa.TypeName);
listBox2.Items.Add(mt.Name);
Type myTypeA =
Type.GetType(string.Format("CommsViewer.{0}+{1}", objectType.Name,
mt.Name));
//object instance =
Activator.CreateInstance(myTypeA);
//Activator.CreateInstance(myTypeA)
innerMessage = (Activator.CreateInstance(myTypeA))XmlToObject(xrInner,
myTypeA);
object innerMessage = XmlToObject(xrInner,
myTypeA);
foreach (FieldInfo fl in
myTypeA.GetFields( ))
{
listBox2.Items.Add(string.Format("{0} =
{1}", fl.Name, fl.GetValue(innerMessage)));
}
}
}
}
}
}
}
}
//END of CODE
I hope somebody finds this usefull.
ink
ink said:
Hi all,
I would like to be able to select the object used to Deserialize an XML
string based on the XML itself.
I need to do this because the XML is being read from a database and there
are a number of different objects. The XML is being inserted into the
database as a log of all trafice between systems and I have been asked to
write an app that will display the trafic in a human readable form. Want
to use reflection to get the actual object names. For Example.
Given the following XML:
<TR CST="2008-08-28T12:15:34+01:00" SRT="2008-08-28T12:15:40.12232+01:00"
/>
How can I figger out which object I need to use to Deserialize. This must
be at run time.
[Serializable]
[XmlType("TR")]
public class TimeSyncResponseMessage
{
[XmlAttribute("CST")]
public DateTime ClientSendTime;
[XmlAttribute("SRT")]
public DateTime ServerResponseTime;
}
[Serializable]
[XmlType("TS")]
public class TimeSyncRequestMessage
{
[XmlAttribute("T")]
public DateTime SendTime;
}
Some of the Rules would be:
1. The object them selves can not change as thes are being used in a live
system.
2. I can put them into another class like a parent if needed.
I was thinking that maybe I could look at the XML tag “TR†and then using
reflection loop through the members comparing the [XmlType("TR")] till I
found the correct object. The root tags are all unique.
But I don’t know how to do this? or if it is even possible.
Any sugestions?
Thanks.
Ink