Build a Custom Serialization as String in System.Xml.Serialization - c#

Hi guys I have 2 classes like this:
[XmlRoot("Config")]
public class ConfigClass
{
[XmlElement("Configuration1")]
public string Config1 { get; set; }
[XmlArray("Infos")]
[XmlArrayItem("Info")]
public OtherInfo[] OtherInfos { get; set; }
}
public class OtherInfo
{
public string Info1 { get; set; }
public string Info2 { get; set; }
}
When I serialize the root class the XML result is like this:
<?xml version="1.0"?>
<Config>
<Configuration1>Text</Configuration1>
<Infos>
<Info>
<Info1>Test 2</Info1>
<Info2>Text 3</Info2>
</Info>
<Info>
<Info1>Test 4</Info1>
<Info2>Text 5</Info2>
</Info>
</Infos>
</Config>
But I would like the OtherInfo class was serialized as a single string like this:
<?xml version="1.0"?>
<Config>
<Configuration1>Text</Configuration1>
<Infos>
<Info>
Test 2:Text 3
</Info>
<Info>
Test 4:Text 5
</Info>
</Infos>
</Config>
How I can do that?

You can implement the IXmlSerializable interface, so the Info1 and Info2 properties are serialized the way <Info>Info1:Info2</Info>:
public class OtherInfo: IXmlSerializable
{
public string Info1 { get; set; }
public string Info2 { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
var content = reader.ReadElementContentAsString();
if (String.IsNullOrWhiteSpace(content))
return;
var infos = content.Split(':');
if (infos.Length < 2)
return;
this.Info1 = infos[0];
this.Info2 = infos[1];
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteString(String.Format("{0}:{1}", this.Info1, this.Info2));
}
}
If having those properties in the format "Info1:Info2" is also needed inside the application and not just for Xml serialization, then you could have a property in OtherInfo like the following and hide Info1 and Info2 from the serialization:
public class OtherInfo
{
[XmlIgnore]
public string Info1 { get; set; }
[XmlIgnore]
public string Info2 { get; set; }
[XmlText]
public string InfoString
{
get
{
return String.Format("{0}:{1}", this.Info1, this.Info2);
}
set
{
if (String.IsNullOrWhiteSpace(value))
return;
var infos = value.Split(':');
if (infos.Length < 2)
return;
this.Info1 = infos[0];
this.Info2 = infos[1];
}
}
}

Related

How to make list from XML deserialization

I have an XML file with many devices and many slots. I need to make lists of both. I am trying with the device type but it is always null.
<?xml version="1.0" encoding="UTF-8"?>
<DataFileSetup>
<System Name="Local">
<SysInfo>
<Software>
<VersionCreated>X3 SP5 (RELEASE-181228) (64-bit)</VersionCreated>
<VersionModifed>X3 SP5 (RELEASE-181228) (64-bit)</VersionModifed>
<License_Type>Professional</License_Type>
</Software>
</SysInfo>
<DewesoftSetup>
<Devices>
<StartStoreTime>43874.6969328704</StartStoreTime>
<SampleRate>50000</SampleRate>
<BlockSize>1000</BlockSize>
<IBRate>10</IBRate>
<AAFsr>21000</AAFsr>
<MaxSampling>200000</MaxSampling>
<Device Type="AI">
<Slot Index="0">
<MeasuredValue>VOLTAGE</MeasuredValue>
<Range>10 V</Range>
<LPFilter_Type>BU</LPFilter_Type>
<LPFilter_Hz>10000</LPFilter_Hz>
<LPFilter_Order>2</LPFilter_Order>
<HPFilter_Hz>1</HPFilter_Hz>
<OutMathChEnabled>8;1;0;0;0;0;0;0;0</OutMathChEnabled>
</Slot>
</Device>
<Device Type="DI">
....
</Device>
</Devices>
</DewesoftSetup>
</System>
</DataFileSetup>
public static void readXML()
{
string deviceType;
XmlReader reader = XmlReader.Create(DewesoftCard.xmlFileName);
reader.ReadToFollowing("DeviceName");
reader.Read();
deviceType = reader.Value;
reader.ReadToFollowing("DewesoftSetup");
if (deviceType == "SIRIUSi")
{
XmlSerializer serializer = new XmlSerializer(typeof(DewesoftSiriusDevices));
DewesoftSiriusDevices setupSirius = (DewesoftSiriusDevices)serializer.Deserialize(reader);
}
else if (deviceType == "KRYPTONi TH")
{
XmlSerializer serializer = new XmlSerializer(typeof(DewesoftKryptonDevices));
DewesoftKryptonDevices setupKrypton = (DewesoftKryptonDevices)serializer.Deserialize(reader);
}
}
[XmlRoot(ElementName = "DewesoftSetup")]
public class DewesoftSiriusDevices
{
[XmlElement(ElementName ="Devices")]
public DewesoftSiriusSetup dewesoftSiriusSetup { get; set; }
[XmlElement(ElementName = "Device")]
public List<DeviceType> deviceType { get; set; }
};
[XmlRoot(ElementName = "DewesoftSetup")]
public class DewesoftKryptonDevices
{
[XmlElement(ElementName = "Devices")]
public DewesoftKryptonSetup dewesoftKryptonSetup { get; set; }
[XmlElement(ElementName = "Device")]
public List<DeviceType> deviceType { get; set; }
};
public class DewesoftSiriusSetup
{
public double StartStoreTime;
public int SampleRate;
public int IBRate;
public int AAFsr;
public int MaxSampling;
};
public class DewesoftKryptonSetup
{
public double StartStoreTime;
public int SampleRate;
public int BlockSize;
public int IBRate;
public int MaxSampling;
};
public class DeviceType
{
[XmlAttribute(AttributeName = "Type")]
public string type;
};
The dewesoftSiriusSetup or dewesoftKryptonSetup is populated correctly.
Is there something I am missing from the code? Along with the device type, inside of there I also need the different slots as a list but I havent gotten that far since I feel like if I get the device figured out it will be the same for slots

Deserialize portion of XmlDocument into object

I see this question often enough, but nobody's title really seems to depict their question. I get a large response object back from a Web API that contains general response information, along with the data object I want to deserialize.
Full XML:
<?xml version="1.0"?>
<root>
<status>
<apiErrorCode>0</apiErrorCode>
<apiErrorMessage/>
<dbErrorCode>0</dbErrorCode>
<dbErrorMessage/>
<dbErrorList/>
</status>
<data>
<modelName>ReportXDTO</modelName>
<modelData>
<id>1780</id>
<reportTitle>Access Level (select) with Door Assignment</reportTitle>
<hasParameters>true</hasParameters>
<parameters>
<dataType>STRING</dataType>
<title>Access Level:</title>
<index>1</index>
<allowMulti>true</allowMulti>
<selectSql>SELECT DISTINCT [Name] FROM dbo.[Levels] WHERE [PrecisionFlag] = '0' ORDER BY [Name] </selectSql>
<values>
<value>Door 1</value>
<used>1</used>
</values>
<values>
<value>Door 2</value>
<used>1</used>
</values>
<values>
<value>Door 3</value>
<used>1</used>
</values>
</parameters>
<sourceSql>SELECT [Name], [SData] FROM [Schedules]</sourceSql>
<report/>
</modelData>
<itemReturned>1</itemReturned>
<itemTotal>1</itemTotal>
</data>
<listInfo>
<pageIdRequested>1</pageIdRequested>
<pageIdCurrent>1</pageIdCurrent>
<pageIdFirst>1</pageIdFirst>
<pageIdPrev>1</pageIdPrev>
<pageIdNext>1</pageIdNext>
<pageIdLast>1</pageIdLast>
<itemRequested>1</itemRequested>
<itemReturned>1</itemReturned>
<itemStart>1</itemStart>
<itemEnd>1</itemEnd>
<itemTotal>1</itemTotal>
</listInfo>
</root>
I only want to deserialize the modelData element. The modelData object type is dynamic, depending on the API call.
I deserialize xml in other applications, and created the following method, but don't know how to specifically ONLY get the modelData element:
public static T ConvertXmltoClass<T>(HttpResponseMessage http, string elementName) where T : new()
{
var newClass = new T();
try
{
var doc = JsonConvert.DeserializeXmlNode(http.Content.ReadAsStringAsync().Result, "root");
XmlReader reader = new XmlNodeReader(doc);
reader.ReadToFollowing(elementName);
//The xml needs to show the proper object name
var xml = reader.ReadOuterXml().Replace(elementName, newClass.GetType().Name);
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
{
var serializer = new XmlSerializer(typeof(T));
newClass = (T)serializer.Deserialize(stream);
}
}
catch (Exception e)
{
AppLog.LogException(System.Reflection.MethodBase.GetCurrentMethod().Name, e);
}
return newClass;
}
I have updated this thread multiple times now, to stay current. I started updating it with the first solution. But that solution by itself didn't solve the problem. With the code how it is right now, I get no exceptions, but don't get the xml deserialized to my object. Instead I get a new, blank object. Thoughts?
THOUGH the object type can change, here is my current object I am dealing with: (PLEASE NOTE, that I deserialize the exact xml in modelData, in the Web API)
namespace WebApiCommon.DataObjects
{
[Serializable]
public class ReportXDto
{
public ReportXDto()
{
Parameters = new List<ReportParameterXDto>();
}
public int Id { get; set; }
public string ReportTitle { get; set; }
public bool HasParameters { get; set; } = false;
public List<ReportParameterXDto> Parameters { get; set; }
public string SourceSql { get; set; }
public DataTable Report { get; set; }
}
[Serializable]
public class ReportXDto
{
public ReportXDto()
{
Parameters = new List<ReportParameterXDto>();
}
public int Id { get; set; }
public string ReportTitle { get; set; }
public bool HasParameters { get; set; } = false;
public List<ReportParameterXDto> Parameters { get; set; }
public string SourceSql { get; set; }
public DataTable Report { get; set; }
}
[Serializable]
public class ReportParameterValuesXDto
{
public string Value { get; set; } = "";
public bool Used { get; set; } = false;
}
}
Firstly, XmlSerializer is case sensitive. Thus your property names need to match the XML element names exactly -- unless overridden with an attribute that controls XML serialization such as [XmlElement(ElementName="id")]. To generate a data model with the correct casing I used http://xmltocsharp.azurewebsites.net/ which resulted in:
public class ReportParameterValuesXDto
{
[XmlElement(ElementName="value")]
public string Value { get; set; }
[XmlElement(ElementName="used")]
public string Used { get; set; }
}
public class ReportParametersXDto
{
[XmlElement(ElementName="dataType")]
public string DataType { get; set; }
[XmlElement(ElementName="title")]
public string Title { get; set; }
[XmlElement(ElementName="index")]
public string Index { get; set; }
[XmlElement(ElementName="allowMulti")]
public string AllowMulti { get; set; }
[XmlElement(ElementName="selectSql")]
public string SelectSql { get; set; }
[XmlElement(ElementName="values")]
public List<ReportParameterValuesXDto> Values { get; set; }
}
public class ReportXDto
{
[XmlElement(ElementName="id")]
public string Id { get; set; }
[XmlElement(ElementName="reportTitle")]
public string ReportTitle { get; set; }
[XmlElement(ElementName="hasParameters")]
public string HasParameters { get; set; }
[XmlElement(ElementName="parameters")]
public ReportParametersXDto Parameters { get; set; }
[XmlElement(ElementName="sourceSql")]
public string SourceSql { get; set; }
[XmlElement(ElementName="report")]
public string Report { get; set; }
}
(After generating the model, I modified the class names to match your naming convention.)
Given the correct data model, you can deserialize directly from a selected XmlNode using an XmlNodeReader as shown in How to deserialize a node in a large document using XmlSerializer without having to re-serialize to an intermediate XML string. The following extension method does the trick:
public static partial class XmlExtensions
{
public static IEnumerable<T> DeserializeElements<T>(this XmlNode root, string localName, string namespaceUri)
{
return new XmlNodeReader(root).DeserializeElements<T>(localName, namespaceUri);
}
public static IEnumerable<T> DeserializeElements<T>(this XmlReader reader, string localName, string namespaceUri)
{
var serializer = XmlSerializerFactory.Create(typeof(T), localName, namespaceUri);
while (!reader.EOF)
{
if (!(reader.NodeType == XmlNodeType.Element && reader.LocalName == localName && reader.NamespaceURI == namespaceUri))
reader.ReadToFollowing(localName, namespaceUri);
if (!reader.EOF)
{
yield return (T)serializer.Deserialize(reader);
// Note that the serializer will advance the reader past the end of the node
}
}
}
}
public static class XmlSerializerFactory
{
// To avoid a memory leak the serializer must be cached.
// https://stackoverflow.com/questions/23897145/memory-leak-using-streamreader-and-xmlserializer
// This factory taken from
// https://stackoverflow.com/questions/34128757/wrap-properties-with-cdata-section-xml-serialization-c-sharp/34138648#34138648
readonly static Dictionary<Tuple<Type, string, string>, XmlSerializer> cache;
readonly static object padlock;
static XmlSerializerFactory()
{
padlock = new object();
cache = new Dictionary<Tuple<Type, string, string>, XmlSerializer>();
}
public static XmlSerializer Create(Type serializedType, string rootName, string rootNamespace)
{
if (serializedType == null)
throw new ArgumentNullException();
if (rootName == null && rootNamespace == null)
return new XmlSerializer(serializedType);
lock (padlock)
{
XmlSerializer serializer;
var key = Tuple.Create(serializedType, rootName, rootNamespace);
if (!cache.TryGetValue(key, out serializer))
cache[key] = serializer = new XmlSerializer(serializedType, new XmlRootAttribute { ElementName = rootName, Namespace = rootNamespace });
return serializer;
}
}
}
Then you would deserialize as follows:
var modelData = doc.DeserializeElements<ReportXDto>("modelData", "").FirstOrDefault();
Working sample .Net fiddle here.
For Huge xml files always use XmlReader so you do not get an out of memory issue. See code below to get the element as a string :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
//or Create(Stream)
XmlReader reader = XmlReader.Create(FILENAME);
reader.ReadToFollowing("modelData");
if (!reader.EOF)
{
string modelDataStr = reader.ReadOuterXml();
}
}
}
}

How to serialize List<IFilter> (Nokia Imaging SDK)?

I'm trying to save a List of IFilter(of type Interface) which are applied to an image using XML serialization, so that user can edit the same image from where he left off.
[XmlRoot]
public class ImageProperties
{
public string ImageName { get; set; }
public string ImageFilePath { get; set; }
public List<IFilter> Filters { get; set; }
}
Is this possible? Is there another alternative to do the same?
You could use IXmlSerializable to achieve this.. assuming you can change the ImageProperties class.
Upon serialization, you can get the type by looking at each filter instance and querying for it. You can store this type information in the XML so when you come to read it, you know which type it is, and you can then just invoke the default XML serializer for each filter.
Here is a possible implementation.
public class ImageProperties : IXmlSerializable
{
public string ImageName { get; set; }
public string ImageFilePath { get; set; }
public List<IFilter> Filters { get; set; }
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
string startEle = reader.Name;
reader.ReadStartElement();
Filters = new List<IFilter>();
do
{
switch (reader.Name)
{
case "imgName":
ImageName = reader.ReadElementContentAsString();
break;
case "imgFilePath":
ImageFilePath = reader.ReadElementContentAsString();
break;
case "filters":
reader.ReadStartElement("filters");
while (reader.Name.Equals("iFilter"))
{
XmlSerializer filterSerializer = new XmlSerializer(Type.GetType(reader.GetAttribute("type")));
reader.ReadStartElement("iFilter");
Filters.Add((IFilter)filterSerializer.Deserialize(reader));
reader.ReadEndElement();
}
reader.ReadEndElement();
break;
default:
reader.ReadOuterXml();
break;
}
} while (reader.Name != startEle);
}
public void WriteXml(System.Xml.XmlWriter writer)
{
writer.WriteElementString("imgName", ImageName);
writer.WriteElementString("imgFilePath", ImageFilePath);
writer.WriteStartElement("filters");
foreach (IFilter filter in Filters)
{
writer.WriteStartElement("iFilter");
writer.WriteAttributeString("type", filter.GetType().FullName);
XmlSerializer filterSerializer = new XmlSerializer(filter.GetType());
filterSerializer.Serialize(writer, filter);
writer.WriteEndElement();
}
writer.WriteEndElement();
}
}
If you have different types of filter, the default serializer of the real type is invoked, so their unique properties will get recorded.
For example, with these filter classes available:
public interface IFilter
{
string SomeCommonProp { get; set;}
}
[XmlRoot("myFilter")]
public class MyFilter : IFilter
{
[XmlElement("somemyFilterProp")]
public string SomeMyFilterProp { get; set; }
[XmlElement("someCommonProp")]
public string SomeCommonProp { get; set;}
}
[XmlRoot("myOtherFilter")]
public class MyOtherFilter : IFilter
{
[XmlElement("someOtherFilterProp")]
public string SomeOtherFilterProp { get; set; }
[XmlElement("someCommonProp")]
public string SomeCommonProp { get; set;}
}
You can use as follows to serialise and deserialise two different types of filter in IFilters to xml.
static void Main(string[] args)
{
ImageProperties props = new ImageProperties();
props.ImageName = "img.png";
props.ImageFilePath = "c:\\temp\\img.png";
props.Filters = new List<IFilter>();
props.Filters.Add(new MyFilter() { SomeMyFilterProp = "x", SomeCommonProp ="p" });
props.Filters.Add(new MyOtherFilter() { SomeOtherFilterProp = "y", SomeCommonProp ="p" });
XmlSerializer s = new XmlSerializer(typeof(ImageProperties));
using (StreamWriter writer = new StreamWriter(#"c:\temp\imgprops.xml"))
s.Serialize(writer, props);
using (StreamReader reader = new StreamReader(#"c:\temp\imgprops.xml"))
{
object andBack = s.Deserialize(reader);
}
Console.ReadKey();
}
This produces an XML that looks like this.
<?xml version="1.0" encoding="utf-8"?>
<ImageProperties>
<imgName>img.png</imgName>
<imgFilePath>c:\temp\img.png</imgFilePath>
<filters>
<iFilter type="SomeNameSpace.Whatever.MyFilter">
<myFilter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<somemyFilterProp>x</somemyFilterProp>
<someCommonProp>p</someCommonProp>
</myFilter>
</iFilter>
<iFilter type="SomeNameSpace.Whatever.MyOtherFilter">
<myOtherFilter xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<someOtherFilterProp>y</someOtherFilterProp>
<someCommonProp>p</someCommonProp>
</myOtherFilter>
</iFilter>
</filters>
</ImageProperties>
No. Interface instances cannot be serialized. It doesn't know the implementation to "deserialize" to. It will require a concrete class or custom serialization in this case.

XML serialization in C#.Net, serialize all class properties

I wanna serialize this class:
[Serializable]
[XmlRoot(ElementName = "Rates")]
public class CbrRate : IRate
{
public CbrRate()
{
}
public CbrRate(DateTime date, ICurrency currency, decimal rate)
{
Currency = currency;
Date = date;
Rate = rate;
}
[XmlIgnore]
public string SrcName
{
get { return "CBR"; }
}
[XmlElement(ElementName = "RequestDate")]
public DateTime Date { get; set; }
[XmlIgnore]
public ICurrency Currency { get; set; }
[XmlElement(ElementName = "Direction")]
public string Direction
{
get { return "RUR=>" + CodeChar.Trim(); }
}
[XmlElement(ElementName = "RateValue")]
public decimal Rate { get; set; }
[XmlElement(ElementName = "RateBase")]
public decimal BaseRate
{
get { return Math.Round(Rate/Nominal, 4); }
}
[XmlElement(ElementName = "RateCross")]
public decimal CrossRate
{
get { return Math.Round(1.00M/BaseRate, 4); }
}
[XmlElement(ElementName = "CodeNum")]
public int CodeNum
{
get { return Currency.CodeNumIso; }
}
[XmlElement(ElementName = "CodeISO")]
public string CodeChar
{
get { return Currency.CodeCharIso; }
}
[XmlElement(ElementName = "CurrencyName")]
public string Name
{
get { return Currency.Name; }
}
[XmlElement(ElementName = "Nominal")]
public decimal Nominal
{
get { return Currency.Nominal; }
}
}
public static XDocument Serialize<T>(this T source)
{
var target = new XDocument();
var s = new XmlSerializer(typeof (T));
using (var writer = target.CreateWriter())
{
s.Serialize(writer, source);
writer.Close();
}
return target;
}
But, that I have:
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfCbrRate xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CbrRate>
<RequestDate>2011-09-05T18:49:55.1195696+04:00</RequestDate>
<RateValue>31.0539</RateValue>
</CbrRate>
...
How I can create correct xml, like this:
<ArrayOfRates>
<Rates>
<RequestDate></RequestDate>
<Direction></Direction>
<RateValue></RateValue>
<RateBase></RateBase>
...
First of all, .Net XmlSerializer will only serialize read/write properties (or fields). That's why only RequestDate and RateValue are serialized.
In order to achieve the XML structure you mentioned, you need to create a wrapper class as Roel said.
So, assuming you are serializing a List<CbrRate >, you will need to create a wrapper class for the list to have it serialized as you want it. Something like this:
[XmlRoot("root")]
public class ListOfRates
{
[XmlArray("ArrayOfRates")]
[XmlArrayItem("Rate")]
public List<CbrRate> Rates { get; set; }
}
this will produce the xml you want. Or you can play around with the attributes a little but if you don't want to have a root:
[XmlRoot("ArrayOfRates")]
public class ListOfRates
{
[XmlArrayItem("Rate")]
public List<CbrRate> Rates { get; set; }
}
the two attributes XmlArray and XmlArrayItem are key here. If you don't provide a name for the xml element, it will default to the property name.

Problem with XML Deserialization C#

I am having trouble with XML deserialization.
In a nutshell -
I have 2 classes:
SMSMessage
SMSSendingResponse
I call an API that takes a bunch of parameters (represented by SMSMessage class)
It returns an XML response.
The response looks like this:
<?xml version="1.0" encoding="utf-8"?>
<data>
<status>1</status>
<message>OK</message>
<results>
<result>
<account>12345</account>
<to>012345678</to>
<from>054321</from>
<message>Testing</message>
<flash></flash>
<replace></replace>
<report></report>
<concat></concat>
<id>f8d3eea1cbf6771a4bb02af3fb15253e</id>
</result>
</results>
</data>
Here is the SMSMessage class (with the xml serialization attributes so far)
using System.Xml.Serialization;
namespace XMLSerializationHelp
{
[XmlRoot("results")]
public class SMSMessage
{
public string To
{
get
{
return Result.To;
}
}
public string From
{
get
{
return Result.From;
}
}
public string Message
{
get
{
return Result.Message;
}
}
[XmlElement("result")]
public Result Result { get; set; }
}
}
Here is SMSMessageSendingResponse:
using System.Xml.Serialization;
namespace XMLSerializationHelp
{
[XmlRoot("data")]
public class SMSSendingResponse
{
//should come from the results/result/account element. in our example "12345"
public string AccountNumber
{
get
{
return SMSMessage.Result.AccountNumber;
}
}
//should come from the "status" xml element
[XmlElement("status")]
public string Status { get; set; }
//should come from the "message" xml element (in our example - "OK")
[XmlElement("message")]
public string Message { get; set; }
//should come from the "id" xml element (in our example - "f8d3eea1cbf6771a4bb02af3fb15253e")
public string ResponseID
{
get
{
return SMSMessage.Result.ResponseID;
}
}
//should be created from the results/result element - ignore flash, replace, report and concat elements for now.
[XmlElement("results")]
public SMSMessage SMSMessage { get; set; }
}
}
Here is the other class (Result) - I want to get rid of this, so only the 2 previously mentioned classes remain
using System.Xml.Serialization;
namespace XMLSerializationHelp
{
[XmlRoot("result")]
public class Result
{
[XmlElement("account")]
public string AccountNumber{ get; set; }
[XmlElement("to")]
public string To { get; set; }
[XmlElement("from")]
public string From { get; set; }
[XmlElement("message")]
public string Message { get; set; }
[XmlElement("id")]
public string ResponseID { get; set; }
}
}
I don't want SMSMessage to be aware of the SMSSendingResponse - as this will be handled by a different part of my application
I hope this helps. The XML structure implies the <result> element can occur more than once, so see if this helps you achieve what you need:
using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.Xml;
namespace XMLSerializationHelp
{
class Program
{
static void Main(string[] args)
{
string strXML = #"<?xml version=""1.0"" encoding=""utf-8""?>
<data>
<status>1</status>
<message>OK</message>
<results>
<result>
<account>12345</account>
<to>012345678</to>
<from>054321</from>
<message>Testing</message>
<flash></flash>
<replace></replace>
<report></report>
<concat></concat>
<id>f8d3eea1cbf6771a4bb02af3fb15253e</id>
</result>
</results>
</data>";
XmlSerializer serializer = new XmlSerializer(typeof(SMSSendingResponse));
SMSSendingResponse obj = (SMSSendingResponse)serializer.Deserialize(new XmlTextReader(strXML, XmlNodeType.Document, null));
Console.WriteLine("Status: {0}", obj.Status);
Console.WriteLine("Message: {0}", obj.Message);
Console.WriteLine("Account Number: {0}", obj.AccountNumber);
Console.WriteLine("ResponseID: {0}", obj.ResponseID);
Console.WriteLine("To: {0}", obj.To);
Console.WriteLine("From: {0}", obj.From);
Console.WriteLine("ResultMessage: {0}", obj.ResultMessage);
Console.ReadLine();
}
}
[Serializable]
[XmlRoot("data")]
public class SMSSendingResponse
{
public SMSSendingResponse() {}
//should come from the "status" xml element
[XmlElement("status")]
public string Status { get; set; }
//should come from the "message" xml element (in our example - "OK")
[XmlElement("message")]
public string Message { get; set; }
//should come from the results/result/account element. in our example "12345"
[XmlIgnore()]
public string AccountNumber
{
get
{
Result r = FirstResult;
return (r != null) ? r.AccountNumber : null;
}
}
//should come from the "id" xml element (in our example - "f8d3eea1cbf6771a4bb02af3fb15253e")
[XmlIgnore()]
public string ResponseID
{
get
{
Result r = FirstResult;
return (r != null) ? r.ResponseID : null;
}
}
[XmlIgnore()]
public string To
{
get
{
Result r = FirstResult;
return (r != null) ? r.To : null;
}
}
[XmlIgnore()]
public string From
{
get
{
Result r = FirstResult;
return (r != null) ? r.From : null;
}
}
[XmlIgnore()]
public string ResultMessage
{
get
{
Result r = FirstResult;
return (r != null) ? r.Message : null;
}
}
[XmlArray("results"), XmlArrayItem("result", typeof(Result))]
public List<Result> Results
{
get { return (_Results); }
set { _Results = value; }
} private List<Result> _Results = new List<Result>();
[XmlIgnore()]
public Result FirstResult
{
get
{
return (_Results != null && _Results.Count > 0) ? _Results[0] : null;
}
}
}
[XmlType(TypeName = "result"), Serializable]
public class Result
{
public Result() {}
[XmlElement("account")]
public string AccountNumber { get; set; }
[XmlElement("to")]
public string To { get; set; }
[XmlElement("from")]
public string From { get; set; }
[XmlElement("message")]
public string Message { get; set; }
[XmlElement("id")]
public string ResponseID { get; set; }
}
}

Categories

Resources