Deserialize xml file with mixed types - c#

Many Thanks in advance for any help in creating a class and deserializing xml file like below in .NET
example of xml data
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
<Article>
<Story>
<Title>Some Title 1</Title>
<Author>John</Author>
<Lead>Some Lead 1</Lead>
<Subtitle>SubTitle 1-1</Subtitle>
<Body>body 1-1-1</Body>
<Body>body 1-1-2</Body>
<Body>body 1-1-3</Body>
<Body>body 1-1-4</Body>
<Subtitle>SubTitle 1-2</Subtitle>
<Body>body 1-2-1</Body>
<Body>body 1-2-2</Body>
<Subtitle>SubTitle 1-3</Subtitle>
<Body>body 1-3-1</Body>
<Body>body 1-3-2</Body>
<Body>body 1-3-3</Body>
</Story>
<Story>
<Title>Some Title 2</Title>
<Author>Adam</Author>
<Lead>Some Lead 2</Lead>
<Subtitle>SubTitle 2-1</Subtitle>
<Body>body 2-1-1</Body>
<Body>body 2-1-2</Body>
<Body>body 2-1-3</Body>
<Subtitle>SubTitle 2-2</Subtitle>
<Body>body 2-2-1</Body>
<Body>body 2-2-2</Body>
<Subtitle>SubTitle 2-3</Subtitle>
<Body>body 2-3-1</Body>
</Story>
<Story>
<Picture>
<Image href="someFile1.jpg"></Image>
<Credit>Credit 1</Credit>
<Description>Description Image 1</Description>
</Picture>
</Story>
<Story>
<Picture>
<Image href="someFile2.jpg"></Image>
<Credit>Credit 2</Credit>
</Picture>
</Story>
</Article>
</Root>
I have prepared Domain class for like this (but maybe it's not the best idea for my xml file)
using System.Collections.Generic;
using System.Xml.Serialization;
namespace QgeImagingXmlConnector.Domain
{
[XmlRoot(ElementName = "Root")]
public class InputXmlModel
{
[XmlElement("Article")]
public List<Article> Articles { get; set; }
}
public class Article
{
[XmlElement("Story")]
public List<Story> Stories { get; set; }
}
public class Story
{
public string Title { get; set; }
public string Author { get; set; }
public string Lead { get; set; }
public List<Item> Items { get; set; }
//OR
public List<StoryPicture> Pictures { get; set; }
}
public class StoryPicture
{
public string ImageHref { get; set; }
public string Credit { get; set; }
public string Description { get; set; }
}
public class Item
{
public string ItemType { get; set; } // Possible: Body or Subtitle
public string ItemText { get; set; }
}
}
and method for deserialize
public InputXmlModel GetInputXmlModelByXmlFile(string filePath)
{
XmlSerializer serializer = new XmlSerializer(typeof(InputXmlModel));
TextReader tr = new StreamReader(filePath);
var result = (InputXmlModel)serializer.Deserialize(tr);
tr.Close();
return result;
}
And my question is: How to change my class to work ( by adding some attributes or change structure )
STORY could by like Story with some content or Story with only picture
so in my class i added 2 classes Story and StoryPicture
In Content of Story we can have many body or subtitle tags - but the order is important
Regards
P.S.
this is what i want to get as an result
I put data only for first Story
var result = new InputXmlModel
{
Articles = new List<Article>
{
{
new Article
{
Stories = new List<Story>
{
{new Story
{
Title = "Some Title 1",
Author = "John",
Lead="Some Lead 1",
Items = new List<Item>
{
new Item{ItemType = "Subtitle", ItemText = "SubTitle 1-1"},
new Item{ItemType = "Body", ItemText = "body 1-1-1"},
new Item{ItemType = "Body", ItemText = "body 1-1-2"},
new Item{ItemType = "Body", ItemText = "body 1-1-3"},
new Item{ItemType = "Body", ItemText = "body 1-1-4"},
new Item{ItemType = "Subtitle", ItemText = "SubTitle 1-2"},
new Item{ItemType = "Body", ItemText = "body 1-2-1"},
new Item{ItemType = "Body", ItemText = "body 1-2-2"},
new Item{ItemType = "Subtitle", ItemText = "SubTitle 1-3"},
new Item{ItemType = "Body", ItemText = "body 1-3-1"},
new Item{ItemType = "Body", ItemText = "body 1-3-2"},
new Item{ItemType = "Body", ItemText = "body 1-3-3"},
}
}
}
// here next 3 stories ( one with Items, two for pictures )
}
}
}
}
};

Yes you can do this too like this.
Your model class would like:
using System.Collections.Generic;
using System.Xml.Serialization;
namespace QgeImagingXmlConnector.Domain
{
[XmlRoot(ElementName = "Root")]
public class InputXmlModel
{
[XmlElement("Article")]
public List<Article> Articles { get; set; }
}
public class Article
{
[XmlElement("Story")]
public List<Story> Stories { get; set; }
}
public class Story
{
public string Title { get; set; }
public string Author { get; set; }
public string Lead { get; set; }
[XmlElement("Item")]
public List<Item> Items { get; set; }
[XmlElement("Picture")]
public List<StoryPicture> Pictures { get; set; }
}
public class StoryPicture
{
public string ImageHref { get; set; }
public string Credit { get; set; }
public string Description { get; set; }
}
public class Item
{
public string ItemType { get; set; } // Possible: Body or Subtitle
public string ItemText { get; set; }
}
}
And your XML like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Root>
<Article>
<Story>
<Title>Some Title 1</Title>
<Author>John</Author>
<Lead>Some Lead 1</Lead>
<Subtitle>SubTitle 1-1</Subtitle>
<Body>body 1-1-1</Body>
<Body>body 1-1-2</Body>
<Body>body 1-1-3</Body>
<Body>body 1-1-4</Body>
<Subtitle>SubTitle 1-2</Subtitle>
<Body>body 1-2-1</Body>
<Body>body 1-2-2</Body>
<Subtitle>SubTitle 1-3</Subtitle>
<Body>body 1-3-1</Body>
<Body>body 1-3-2</Body>
<Body>body 1-3-3</Body>
</Story>
<Story>
<Title>Some Title 2</Title>
<Author>Adam</Author>
<Lead>Some Lead 2</Lead>
<Subtitle>SubTitle 2-1</Subtitle>
<Body>body 2-1-1</Body>
<Body>body 2-1-2</Body>
<Body>body 2-1-3</Body>
<Subtitle>SubTitle 2-2</Subtitle>
<Body>body 2-2-1</Body>
<Body>body 2-2-2</Body>
<Subtitle>SubTitle 2-3</Subtitle>
<Body>body 2-3-1</Body>
<Picture>
<Image href="someFile1.jpg"></Image>
<Credit>Credit 1</Credit>
<Description>Description Image 1</Description>
</Picture>
<Picture>
<Image href="someFile2.jpg"></Image>
<Credit>Credit 2</Credit>
</Picture>
</Story>
</Article>
</Root>
Is that what you're looking for?

Try following xml linq :
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication100
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XDocument doc = XDocument.Load(FILENAME);
Article article = doc.Descendants("Article").Select(x => new Article() { Stories = x.Elements("Story").Select(y => Story.ParseStory(y)).ToList() }).FirstOrDefault();
}
}
public class InputXmlModel
{
public List<Article> Articles { get; set; }
}
public class Article
{
public List<Story> Stories { get; set; }
}
public class Story
{
public string Title { get; set; }
public string Author { get; set; }
public string Lead { get; set; }
public List<Item> Items { get; set; }
public List<StoryPicture> Pictures { get; set; }
enum State
{
DEFAULT,
SUBTITLE,
}
public static Story ParseStory(XElement xStory)
{
Story story = new Story();
State state = State.DEFAULT;
Item newItem = null;
StoryPicture newPicture = null;
foreach (XElement child in xStory.Elements())
{
switch(state)
{
case State.DEFAULT :
switch (child.Name.LocalName)
{
case "Title" :
story.Title = (string)child;
break;
case "Author":
story.Author = (string)child;
break;
case "Lead":
story.Lead = (string)child;
break;
case "Subtitle":
newItem = new Item();
if (story.Items == null) story.Items = new List<Item>();
story.Items.Add(newItem);
state = State.SUBTITLE;
break;
case "Picture":
newPicture = new StoryPicture()
{
ImageHref = (string)child.Element("Image").Attribute("href"),
Credit = (string)child.Element("Credit"),
Description = (string)child.Element("Description")
};
if (story.Pictures == null) story.Pictures = new List<StoryPicture>();
story.Pictures.Add(newPicture);
break;
default:
Console.WriteLine("Error");
Console.ReadLine();
break;
}
break;
case State.SUBTITLE :
switch (child.Name.LocalName)
{
case "Body" :
newItem.ItemType = "SubTitle";
newItem.ItemText = (string)child;
break;
case "Subtitle":
newItem = new Item();
if (story.Items == null) story.Items = new List<Item>();
story.Items.Add(newItem);
break;
default:
Console.WriteLine("Error");
Console.ReadLine();
break;
}
break;
}
}
return story;
}
}
public class StoryPicture
{
public string ImageHref { get; set; }
public string Credit { get; set; }
public string Description { get; set; }
}
public class Item
{
public string ItemType { get; set; } // Possible: Body or Subtitle
public string ItemText { get; set; }
}
}

If you take out the <Root> tag in your XML and change your method for the deserialization to:
public InputXmlModel GetInputXmlModelByXmlFile(string filePath)
{
XmlSerializer serializer = new XmlSerializer(typeof(Article));
using (FileStream fileStream = new FileStream("<PathToFile>", FileMode.Open))
{
Article result = (Article)serializer.Deserialize(fileStream);
}
}
It should work.

Related

Search and Update XML using multiple condition using linq

<Students>
<Student Name="John">
<Subject SubId="123" Content="History minor subject" Enrolled="true" Percentage="0"/>
<Subject SubId="146" Content="Math major Subject" Enrolled="true" Percentage="0"/>
</Student>
<Student Name="Jim">
<Subject SubId="564" Content="physics medium subject" Enrolled="true" Percentage="0"/>
<Subject SubId="324" Content="Chem small subject" Enrolled="true" Percentage="0"/>
</Student>
<Students>
Problem 1 - I want to search if the person name content John and content has "major" -- > return the Xelememt , I am trying with below query but it is not working for me.
String studentToSearch = "John" and string contentToSearch = "major"
IEnumerable<XElement> student = from st in rootElement.Descendants("Students").Elements("Student")
where st.Attribute("Name").Value.ToString() == studentToSearch && st.Element("Subject").Attribute("Content").Value.ToString().Contains(contentToSearch)
select st;
Problem 2 - I want to search if the person name content John and content has "major", if the percentage for that find it "0"-- > then update it to "80" percentage. Trying with below query
rootElement.Elements("Students")
.Where(x=> x.Element("Student").Value == studentToSearch)
.Where(a => a.Element("Subject").Attributes("Content").ToString().Contains(contentToSearch) && a.Element("Subject").Attribute("Percentage").Value == "0").FirstOrDefault()
.SetAttributeValue("Percentage", 80);
Any suggestion will be helpful ?
Why not just deserialize the xml? You need to use SelectMany.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(FILENAME);
XmlSerializer serializer = new XmlSerializer(typeof(Students));
Students students = (Students)serializer.Deserialize(reader);
var johnMajor = students.Student.SelectMany(x => x.Subject.Where(y => y.Content.Contains("major")).Select(z => new { name = x.Name, Subject = z })).FirstOrDefault();
if (johnMajor.Subject.Percentage == 0) johnMajor.Subject.Percentage = 80;
}
}
public class Students
{
[XmlElement()]
public List<Student> Student { get; set; }
}
public class Student
{
[XmlAttribute()]
public string Name { get; set; }
[XmlElement]
public List<Subject> Subject { get; set; }
}
public class Subject
{
[XmlAttribute()]
public int SubId { get; set; }
[XmlAttribute()]
public string Content { get; set; }
[XmlAttribute()]
public Boolean Enrolled { get; set; }
[XmlAttribute()]
public int Percentage { get; set; }
}
}

XmlSerializer not correct format result

The output i want as below
<SOAP:Envelope xmlns:SOAP='http://schemas.xmlsoap.org/soap/envelope/' >
<SOAP:Body UserGUID = '{redacted}' >
<m:SaveOrder xmlns:m = 'http://www.e-courier.com/schemas/' >
<Order UserID = '1' Notes = 'Signature Requiered' CustomerID = '3' >
</Order >
</m:SaveOrder >
</SOAP:Body >
</SOAP:Envelope >
The output xml that i am getting as my result
<?xml version="1.0"?>
<SOAP:Envelope xmlns:m="http://www.e-courier.com/schemas/" xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP:Body UserGUID="">
<m:SaveOrder >
<m:Order UserID="" Notes="" CustomerID="" />
</m:SaveOrder>
</SOAP:Body>
</SOAP:Envelope>
My XML Class code:
[XmlRoot(ElementName="Order")]
public class Order {
[XmlAttribute(AttributeName="UserID")]
public string UserID { get; set; }
[XmlAttribute(AttributeName="Notes")]
public string Notes { get; set; }
[XmlAttribute(AttributeName="CustomerID")]
public string CustomerID { get; set; }
}
[XmlRoot(ElementName="SaveOrder", Namespace="http://www.e-courier.com/schemas/")]
public class SaveOrder {
[XmlElement(ElementName="Order")]
public Order Order { get; set; }
[XmlAttribute(AttributeName="m", Namespace="http://www.w3.org/2000/xmlns/")]
public string M { get; set; }
}
[XmlRoot(ElementName="Body", Namespace="http://schemas.xmlsoap.org/soap/envelope/")]
public class Body {
[XmlElement(ElementName="SaveOrder", Namespace="http://www.e-courier.com/schemas/")]
public SaveOrder SaveOrder { get; set; }
[XmlAttribute(AttributeName="UserGUID")]
public string UserGUID { get; set; }
}
[XmlRoot(ElementName="Envelope", Namespace="http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope {
[XmlElement(ElementName="Body", Namespace="http://schemas.xmlsoap.org/soap/envelope/")]
public Body Body { get; set; }
[XmlAttribute(AttributeName="SOAP", Namespace="http://www.w3.org/2000/xmlns/")]
public string SOAP { get; set; }
}
My Code where i am generating xml
var SaveOrder = new ECSaveOrderRequest.Envelope
{
Body = new ECSaveOrderRequest.Body
{
UserGUID = guid,
SaveOrder = new ECSaveOrderRequest.SaveOrder
{
Order = new ECSaveOrderRequest.Order
{
UserID = Uid,
Notes = "",
CustomerID=""
}
}
}
};
var ns = new XmlSerializerNamespaces();
ns.Add("SOAP", "http://schemas.xmlsoap.org/soap/envelope/");
ns.Add("m", "http://www.e-courier.com/schemas/");
var ser = new XmlSerializer(typeof(ECSaveOrderRequest.Envelope));
using (var ms = new MemoryStream())
{
// write the DTO to the MemoryStream
ser.Serialize(ms, SaveOrder, ns);
using (var wc = new WebClient())
{
wc.Encoding = System.Text.Encoding.UTF8;
ms.Position = 0;
StreamReader stream = new StreamReader(ms);
string requestString = stream.ReadToEnd();
var resp = wc.UploadData(ECUrl, ms.ToArray());
}
}
You need to explicitly clear the xml namespace on SaveOrder.Order or the serializer will default to SaveOrder's xml namespace.
Here you go:
using System;
using System.IO;
using System.Text;
using System.Xml.Serialization;
namespace ECSaveOrderRequest
{
/*
* <SOAP:Envelope xmlns:SOAP='http://schemas.xmlsoap.org/soap/envelope/' >
<SOAP:Body UserGUID = '{redacted}' >
<m:SaveOrder xmlns:m = 'http://www.e-courier.com/schemas/' >
<Order UserID = '1' Notes = 'Signature Requiered' CustomerID = '3' >
</Order >
</m:SaveOrder >
</SOAP:Body >
</SOAP:Envelope >*/
public class Order
{
[XmlAttribute(AttributeName = "UserID")]
public string UserID { get; set; }
[XmlAttribute(AttributeName = "Notes")]
public string Notes { get; set; }
[XmlAttribute(AttributeName = "CustomerID")]
public string CustomerID { get; set; }
}
public class SaveOrder
{
[XmlElement(ElementName = "Order", Namespace = "")]
public Order Order { get; set; }
}
public class Body
{
[XmlElement(ElementName = "SaveOrder", Namespace = "http://www.e-courier.com/schemas/")]
public SaveOrder SaveOrder { get; set; }
[XmlAttribute(AttributeName = "UserGUID")]
public string UserGUID { get; set; }
}
[XmlRoot(ElementName = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public class Envelope
{
[XmlElement(ElementName = "Body", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")]
public Body Body { get; set; }
[XmlAttribute(AttributeName = "SOAP", Namespace = "http://www.w3.org/2000/xmlns/")]
public string SOAP { get; set; }
}
class Program
{
static void Main(string[] args)
{
var SaveOrder = new ECSaveOrderRequest.Envelope
{
Body = new ECSaveOrderRequest.Body
{
UserGUID = "{redacted}",
SaveOrder = new ECSaveOrderRequest.SaveOrder
{
Order = new ECSaveOrderRequest.Order
{
UserID = "1",
Notes = "Signature Requiered",
CustomerID = "3"
}
}
}
};
var ns = new XmlSerializerNamespaces();
ns.Add("SOAP", "http://schemas.xmlsoap.org/soap/envelope/");
ns.Add("m", "http://www.e-courier.com/schemas/");
var ser = new XmlSerializer(typeof(ECSaveOrderRequest.Envelope));
var ms = new MemoryStream();
// write the DTO to the MemoryStream
ser.Serialize(ms, SaveOrder, ns);
ms.Position = 0;
var xml = Encoding.UTF8.GetString(ms.GetBuffer());
Console.WriteLine(xml);
Console.ReadKey();
}
}
}
outputs
<?xml version="1.0"?>
<SOAP:Envelope xmlns:m="http://www.e-courier.com/schemas/" xmlns:SOAP="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP:Body UserGUID="{redacted}">
<m:SaveOrder>
<Order UserID="1" Notes="Signature Requiered" CustomerID="3" />
</m:SaveOrder>
</SOAP:Body>
</SOAP:Envelope>
Which is a serialization of the same XML document as
<SOAP:Envelope xmlns:SOAP='http://schemas.xmlsoap.org/soap/envelope/' >
<SOAP:Body UserGUID = '{redacted}' >
<m:SaveOrder xmlns:m = 'http://www.e-courier.com/schemas/' >
<Order UserID = '1' Notes = 'Signature Requiered' CustomerID = '3' >
</Order >
</m:SaveOrder >
</SOAP:Body>
</SOAP:Envelope>
.

Multiple, identical elements in the same C# DTO

I am trying to create a WCF-service, which can return me an XML document looking something like this:
<alert>
<identifier>SecretID</identifier>
<info>
<valueName>Name1</valueName>
<value>Info1</value>
</info>
<info>
<valueName>Name2</valueName>
<value>Info2</value>
</info>
</alert>
The DTO of this file would look something like this:
[DataContract(Name = "alert", Namespace = "")]
public class Alert
{
[DataMember(Name = "identifier")]
public string identifier { get; set; }
[DataMember(Name = "info")]
public List<Info> Info { get; set; }
}
[DataContract(Name = "info", Namespace = "")]
public class Info
{
[DataMember(Name = "valueName")]
public string ValueName { get; set; }
[DataMember(Name = "value")]
public string Value { get; set; }
}
However, when I try with the following:
var alert = new Alert()
{
Identifier = "SecretID",
Info = new List<Info>
{
new Info() {ValueName = "Name1", Value = "Info1"},
new Info() {ValueName = "Name2", Value = "Info2"},
}
}
I get:
<alert>
<identifier>SecretID</identifier>
<info>
<info xmlns="">
<valueName>Name1</valueName>
<value>Info1</value>
</info>
<info xmlns="">
<valueName>Name2</valueName>
<value>Info2</value>
</info>
</info>
</alert>
I don't need the extra <info> tag, and the namespace xmlns="" would be nice to have removed too. What should I do to get rid of it?
You can use dictionary or key value pairs as mentioned below:
[DataContract(Name = "alert", Namespace = "")]
public class Alert
{
[DataMember(Name = "identifier")]
public string identifier { get; set; }
[DataMember(Name = "info")]
public KeyValuePair<string, string> Info { get; set; }
}
var alert = new Alert()
{
Identifier = "SecretID",
Info = new KeyValuePair<string, string>()
}

access sub XML values in sms web service that hasnt value in standard way

I have following xml :
in other standard xml like this question here we have no problem but in php web service :
http://sandoghche.com/WebService
for inbox check my inbox xml is this:
<?xml version=\"1.0\" encoding=\"UTF-8\" ?>
<Result>
<text_message>
<id>509</id>
<message><![CDATA[a]]></message>
<time>1323519941</time>
<message_phone>
<cellphone>09196070718</cellphone>
</message_phone>
</text_message>
<text_message>
<id>507</id>
<message>1</message>
<time>1323519803</time>
<message_phone>
<cellphone>09360437392</cellphone>
</message_phone>
</text_message>
<text_message>
<id>303</id>
<message><![CDATA[smsm text]]></message>
<time>1318343296</time>
<message_phone>
<cellphone>09354338365</cellphone>
</message_phone>
</text_message>
<text_message>
<id>219</id>
<message><![CDATA[my sms texts here]]></message>
<time>1316154042</time>
<message_phone>
<cellphone>09127930265</cellphone>
</message_phone>
</text_message>
<text_message>
<id>217</id>
<message>2</message>
<time>1316090189</time>
<message_phone>
<cellphone>09195533234</cellphone>
</message_phone>
</text_message>
</Result>
for this I wrote the following code
public class SMSData
{
public int id { set; get; }
public string message { set; get; }
public string cellphone { set; get; }
}
string data = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?><Result><text_message><id>509</id><message><![CDATA[a]]></message><time>1323519941</time><message_phone><cellphone>09196070718</cellphone></message_phone></text_message><text_message><id>507</id><message>1</message><time>1323519803</time><message_phone><cellphone>09360437392</cellphone></message_phone></text_message><text_message><id>303</id><message><![CDATA[ممنون.شما؟]]></message><time>1318343296</time><message_phone><cellphone>09354378365</cellphone></message_phone></text_message><text_message><id>219</id><message><![CDATA[سلام اقاي طباطبايي لينك مربوط به ورود اعضا به وبلاگ روي صفحه فيلتر مي رود با احترام احدي]]></message><time>1316154042</time><message_phone><cellphone>09127960265</cellphone></message_phone></text_message><text_message><id>217</id><message>2</message><time>1316090189</time><message_phone><cellphone>09195523234</cellphone></message_phone></text_message></Result>";
Stream s = GenerateStreamFromString(data);
XmlReader xr = XmlReader.Create(s);
while (xr.Read())
{
if ((xr.NodeType == XmlNodeType.Element) && (xr.Name == "text_message"))
{
if (xr.HasValue)
{
string id = xr.GetAttribute("id");
string message = xr.GetAttribute("message");
}
}
}
and this code
Dictionary<int, string> myDictionary = new Dictionary<int, string>();
XmlDocument xml = new XmlDocument();
xml.LoadXml(data);
XmlNodeList xnList = xml.SelectNodes("/Result");
foreach (XmlNode xn in xnList)
{
but can't catch values on this xml document.
Is there a clean way to do this?
It is easier to use the built-in Serializers for these kind of things, like the XmlSerializer or the DataContractSerializer. I used the latter and tested your XML with the following snippet.
First annotate your SMSData class and create a new class to hold the Message_phone elements in a new class:
[DataContract(Name="text_message",Namespace = "")]
public class SMSData
{
[DataMember(Order =1)]
public int id { set; get; }
[DataMember(Order = 2)]
public string message { set; get; }
[DataMember(Order = 3)]
public int time { set; get; }
[DataMember(Order = 4)]
public Message_phone message_phone { set; get; }
// for easy access to cellphone
public string cellphone {
get
{
return message_phone!=null?message_phone.cellphone:null;
}
}
}
[DataContract(Name="message_phone",Namespace = "")]
public class Message_phone
{
[DataMember]
public string cellphone { set; get; }
}
and then create an instance of the DataContractSerializer for your array of SMSData, and call ReadObject on it like so:
Stream s = GenerateStreamFromString(data);
var ds = new DataContractSerializer(
typeof(SMSData[]), // array of SMSdata
"Result", // top level element
"", // empty namespace
new List<Type> { typeof(SMSData[])} );
var smsdata = (SMSData[]) ds.ReadObject(XmlReader.Create(s));
// smsdata now holds the SMSData from the Xml file

c# XmlElment change order in derived class

I'm trying to serialize a XML. I want to add a new property in a derived class and place it between the other properties of the base class.
In the sample I want to place the 'SpecialInterests' between the 'Name' and the 'Age' of the base class.
XML
<!-- Output -->
<PersonenListe xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<PersonenArray>
<PersonObjekt>
<Name>Max Man</Name>
<Age>33</Age>
</PersonObjekt>
<PersonObjekt xsi:type="SpecialPerson">
<Name>Albert Einstein</Name>
<Age>36</Age>
<SpecialInterests>Physics</SpecialInterests>
</PersonObjekt>
</PersonenArray>
</PersonenListe>
<!-- Desire -->
<PersonenListe>
<PersonenArray>
<PersonObjekt>
<Name>Max Man</Name>
<Age>33</Age>
</PersonObjekt>
<PersonObjekt xsi:type="SpecialPerson">
<Name>Albert Einstein</Name>
<SpecialInterests>Physics</SpecialInterests>
<Age>36</Age>
</PersonObjekt>
</PersonenArray>
</PersonenListe>
c# - Main (Creating instances and serialization)
static void Main(string[] args)
{
PersonalList personen = new PersonalList();
Person normPerson = new Person { Name = "Max Man", Age = 33 };
SpecialPerson specPerson = new SpecialPerson
{ Name = "Albert Einstein", Interests = "Physics", Age = 36 };
personen.AddPerson(normPerson);
personen.AddPerson(specPerson);
Type[] personTypes = new Type[personen.Persons.Count];
for (int i = 0; i < personen.Persons.Count; i++)
{
personTypes[i] = personen.Persons[i].GetType();
}
XmlSerializer serializer = new XmlSerializer(typeof(PersonalList), personTypes);
FileStream fs = new FileStream("Personenliste.xml", FileMode.Create);
serializer.Serialize(fs, personen);
fs.Close();
personen = null;
// Deserialize
fs = new FileStream("Personenliste.xml", FileMode.Open);
personen = (PersonalList)serializer.Deserialize(fs);
serializer.Serialize(Console.Out, personen);
Console.ReadLine();
}
Models
[XmlRoot("PersonenListe")]
[XmlInclude(typeof(Person))]
public class PersonalList
{
[XmlArray("PersonenArray")]
[XmlArrayItem("PersonObjekt")]
public List<Person> Persons = new List<Person>();
public void AddPerson(Person person)
{
Persons.Add(person);
}
}
[XmlType("Person")]
public class Person
{
[XmlElement(ElementName = "Name", Order = 1)]
public virtual string Name { get; set; }
[XmlElement(ElementName = "Age", Order = 3)]
public virtual int Age { get; set; }
}
[XmlType("SpecialPerson")]
public class SpecialPerson : Person
{
[XmlElement(ElementName = "Name", Order = 1)]
public override string Name { get; set; }
[XmlElement(ElementName = "SpecialInterests", Order = 2)]
public string Interests { get; set; }
[XmlElement(ElementName = "Age", Order = 3)]
public override int Age { get; set; }
}
This question is essentially the same this other question. There is a good explanation of why this serialization behavior is the way it is and a few approaches for dealing with it.
.NET Serialization Ordering

Categories

Resources