Convert xml string to C# object - c#

Below is my XML code.
<programs>
<program>
<ProgrameName>Test</ProgrameName>
<deviceTypes>
<DeviceType>POS</DeviceType>
<deviceTargets>
<DeviceNames>
<DeviceName>POS0001</DeviceName>
<DeviceName>POS0001</DeviceName>
<DeviceName>POS0001</DeviceName>
</DeviceNames>
<AttemptToIstall>True</AttemptToIstall>
<Mandetory>False</Mandetory>
<SkipIfOffline>False</SkipIfOffline>
</deviceTargets>
<AttemptToIstall>True</AttemptToIstall>
<Mandatory>False</Mandatory>
<SkipIfOffline>False</SkipIfOffline>
</deviceTypes>
</program>
please help me to write C# code using XmlSerializer.I want to create an object and serialize those object according to above XML.
below are my C# class.
public class ProgramP
{
public string ProgrameName { get; set; }
[XmlRoot("")]
public class DeviceTypes
{
public string DeviceType { get; set; }
[XmlRoot("")]
public class DeviceTargets
{
public string DeviceNames { get; set; }
public string AttemptToIstall { get; set; }
public string Mandetory { get; set; }
public string SkipIfOffline { get; set; }
}
[XmlElement("DeviceTargets")]
public DeviceTargets[] ArDeviceTargets { get; set; }
public string AttemptToIstall { get; set; }
public string Mandetory { get; set; }
public string SkipIfOffline { get; set; }
}
[XmlElement("DeviceTypes")]
public DeviceTypes[] ArDeviceType { get; set; }
}
Below is my C# code.can any body please correct me or suggest me where i have to add more class or how can i arrange my class so that i can get above XML as output.
public void ExportClass(string strFilePathExportedXML)
{
ProgramP ProgramP = new ProgramP
{
ProgrameName = "Test",
ArDeviceType = new ProgramP.DeviceTypes[] {
new ProgramP.DeviceTypes {
DeviceType = "POS1",
AttemptToIstall="True",
Mandetory="True",
SkipIfOffline="True",
ArDeviceTargets = new ProgramP.DeviceTypes.DeviceTargets[] {
new ProgramP.DeviceTypes.DeviceTargets {
DeviceNames="POS01",
AttemptToIstall="True",
Mandetory="True",
SkipIfOffline="True"
},
new ProgramP.DeviceTypes.DeviceTargets {
DeviceNames="POS02",
AttemptToIstall="True",
Mandetory="True",
SkipIfOffline="True"
}
}
};
TextWriter writer = new StreamWriter(strFilePathExportedXML);
XmlSerializer serializerOut = new XmlSerializer(typeof(ProgramP));
serializerOut.Serialize(writer, ProgramP);
writer.Close();

After mapping, you can use this:
public static YourClass LoadFromXMLString(string xmlText)
{
var stringReader = new System.IO.StringReader(xmlText);
var serializer = new XmlSerializer(typeof(YourClass ));
return serializer.Deserialize(stringReader) as YourClass ;
}
From this topic: Convert Xml to Object

Related

Deserialize XML classes to one class for writing to database

I am trying to deserialize XML and save the results to a database using entity framework.
The first section of code is just to get the needed xml file from an API.
Please see below:
public static void Main()
{
Program semoAPI = new Program();
using (WebClient webClient = new WebClient())
{
WebClient n = new WebClient();
//Bid Ask Curves
var bidAskCurves = n.DownloadString("https://reports.semopx.com/api/v1/documents/static-reports?" +
"page=1&page_size=1&order_by=ASC&ReportName=Bid/Ask%20Curves&Group=Market%20Data");
semoReports = JsonConvert.DeserializeObject<SemoReports>(bidAskCurves);
Console.WriteLine("Bid Ask Curves Report: ");
Console.WriteLine(semoReports.ResourceBaseUri + "/" + semoReports.Items[0].ResourceName);
string bidAskCurvesXML = semoReports.ResourceBaseUri + "/" + semoReports.Items[0].ResourceName;
XDocument bacDoc = XDocument.Load(bidAskCurvesXML);
//Execute DeserializeBidAskCurves
semoAPI.DeserializeBidAskCurves(bidAskCurvesXML);
}
}
Below is how my class is setup which contains the XML Elements I need:
namespace SEMO_app
{
[XmlRoot("BidAskCurves")]
public class BidAskCurves
{
[Key]
public int ReportID { get; set; }
[XmlElement("MarketArea")]
public MarketArea[] MarketAreas{ get; set; }
}
public class MarketArea
{
public string MarketAreaName { get; set; }
[XmlElement("DeliveryDay")]
public DeliveryDay[] DeliveryDays { get; set; }
}
public class DeliveryDay
{
public string Day { get; set; }
[XmlElement("TimeStep")]
public TimeStep[] TimeSteps{ get; set; }
}
public class TimeStep
{
public string TimeStepID { get; set; }
[XmlElement("Purchase")]
public Purchase[] Purchases { get; set; }
}
public class Purchase
{
public string Price { get; set; }
public string Volume { get; set; }
}
}
From here i would like to deserialize the XML and save the information to a database, below is the code I have so far which deserialize's the XML and gives the results back fine in the console.writesection.
However I am unable to save these values to the database table. The code complies and executes fine and a the database table updates, however the table only contains a report id column. Where I would like it to contain the items listed in the console.write section.
private void DeserializeBidAskCurves(string filename)
{
//Visual only not needed
Console.WriteLine("\n" + "Reading BidAskCurves XML File");
Console.WriteLine("===========================================================");
// Create an instance of the XmlSerializer.
XmlSerializer serializer = new XmlSerializer(typeof(BidAskCurves));
// Declare an object variable of the type to be deserialized.
BidAskCurves item;
using (XmlReader reader = XmlReader.Create(filename))
{
// Call the Deserialize method to restore the object's state.
item = (BidAskCurves)serializer.Deserialize(reader);
//Write out the properties of the object. (Visual Only, not needed)
Console.Write(
item.MarketAreas[0].MarketAreaName + "\t" +
item.MarketAreas[0].DeliveryDays[0].Day + "\t" +
item.MarketAreas[0].DeliveryDays[0].TimeSteps[0].TimeStepID + "\t" +
item.MarketAreas[0].DeliveryDays[0].TimeSteps[0].Purchases[0].Price + "\t" +
item.MarketAreas[0].DeliveryDays[0].TimeSteps[0].Purchases[0].Volume);
//write the properties to the db
using (SEMOContext context = new SEMOContext())
{
context.BidAskCurvesReports.Add(item);
context.SaveChanges();
}
}
}
Link to xml file: https://reports.semopx.com/documents/BidAskCurves_NI-IDA3_20190401_20190401161933.xml
Thanks for any help in advance.
Initially, it's hard to know what's the problem actually is?
But after visiting URI generated by
string bidAskCurvesXML = semoReports.ResourceBaseUri + "/" + semoReports.Items[0].ResourceName;
And that is https://reports.semopx.com/documents/BidAskCurves_NI-IDA3_20190401_20190401161933.xml
So, The class structure that you are using is different than xml generated by URI.
You need to use below class structure for your xml
[XmlRoot("Purchase")]
public class Purchase
{
[XmlElement("Price")]
public string Price { get; set; }
[XmlElement("Volume")]
public string Volume { get; set; }
}
[XmlRoot("Sell")]
public class Sell
{
[XmlElement("Price")]
public string Price { get; set; }
[XmlElement("Volume")]
public string Volume { get; set; }
}
[XmlRoot("TimeStep")]
public class TimeStep
{
[XmlElement("TimeStepID")]
public string TimeStepID { get; set; }
[XmlElement("Purchase")]
public List<Purchase> Purchase { get; set; }
[XmlElement("Sell")]
public List<Sell> Sell { get; set; }
}
[XmlRoot("DeliveryDay")]
public class DeliveryDay
{
[XmlElement("Day")]
public string Day { get; set; }
[XmlElement("TimeStep")]
public List<TimeStep> TimeStep { get; set; }
}
[XmlRoot("MarketArea")]
public class MarketArea
{
[XmlElement("MarketAreaName")]
public string MarketAreaName { get; set; }
[XmlElement("DeliveryDay")]
public DeliveryDay DeliveryDay { get; set; }
}
[XmlRoot("BidAskCurves")]
public class BidAskCurves
{
[XmlElement("MarketArea")]
public MarketArea MarketArea { get; set; }
}
And after using above class structure with XmlSerializer there are total 12 timestamp available
Usage:
XmlSerializer serializer = new XmlSerializer(typeof(BidAskCurves));
BidAskCurves item;
using (XmlReader reader = XmlReader.Create("https://reports.semopx.com/documents/BidAskCurves_NI-IDA3_20190401_20190401161933.xml"))
{
item = (BidAskCurves)serializer.Deserialize(reader);
//Your code to add above parsed data into database.
}
Output: (From Debugger)
Edit1:
To add first purchase's volume and price and sell's volume and price then,
...
item = (BidAskCurves)serializer.Deserialize(reader);
foreach (var ts in item.MarketArea.DeliveryDay.TimeStep)
{
BidAskCurvesData bidAskCurvesData = new BidAskCurvesData
{
ReportID = 123,
MarketAreaName = item.MarketArea.MarketAreaName,
Day = item.MarketArea.DeliveryDay.Day,
TimeSetID = ts.TimeStepID,
PurchasePrice = ts.Purchase[0].Price,
PurchaseVolume = ts.Purchase[0].Volume,
SellPrice = ts.Sell[0].Price,
SellVolume = ts.Sell[0].Volume
};
using (SEMOContext context = new SEMOContext())
{
context.BidAskCurvesReports.Add(item);
context.SaveChanges();
}
}
static void Main(string[] args)
{
using (WebClient webClient = new WebClient())
{
//Bid Ask Curves
var bidAskCurves = webClient.DownloadString("https://reports.semopx.com/documents/BidAskCurves_NI-IDA3_20190401_20190401161933.xml");
var serializer = new XmlSerializer(typeof(BidAskCurves));
BidAskCurves result;
using (TextReader reader = new StringReader(bidAskCurves))
{
// here it is
result = (BidAskCurves)serializer.Deserialize(reader);
}
}
Console.ReadKey();
}
and xml objects:
[XmlRoot(ElementName = "Purchase")]
public class Purchase
{
[XmlElement(ElementName = "Price")]
public string Price { get; set; }
[XmlElement(ElementName = "Volume")]
public string Volume { get; set; }
}
[XmlRoot(ElementName = "Sell")]
public class Sell
{
[XmlElement(ElementName = "Price")]
public string Price { get; set; }
[XmlElement(ElementName = "Volume")]
public string Volume { get; set; }
}
[XmlRoot(ElementName = "TimeStep")]
public class TimeStep
{
[XmlElement(ElementName = "TimeStepID")]
public string TimeStepID { get; set; }
[XmlElement(ElementName = "Purchase")]
public List<Purchase> Purchase { get; set; }
[XmlElement(ElementName = "Sell")]
public List<Sell> Sell { get; set; }
}
[XmlRoot(ElementName = "DeliveryDay")]
public class DeliveryDay
{
[XmlElement(ElementName = "Day")]
public string Day { get; set; }
[XmlElement(ElementName = "TimeStep")]
public List<TimeStep> TimeStep { get; set; }
}
[XmlRoot(ElementName = "MarketArea")]
public class MarketArea
{
[XmlElement(ElementName = "MarketAreaName")]
public string MarketAreaName { get; set; }
[XmlElement(ElementName = "DeliveryDay")]
public DeliveryDay DeliveryDays { get; set; }
}
[XmlRoot(ElementName = "BidAskCurves")]
public class BidAskCurves
{
[XmlElement(ElementName = "MarketArea")]
public MarketArea MarketAreas { get; set; }
}
EDIT
loop over the result:
foreach (var item in deliveryDays.TimeStep)
{
// var day = deliveryDays.Day
var timeStep_Purchase = item.Purchase;
var timeStep_Sell = item.Sell;
var timeStep_Id = item.TimeStepID;
}

Why an XML string cannot be deserialized due to prefixes in root elements?

I have the XML below:
<y:input xmlns:y='http://www.blahblah.com/engine/42'>
<y:datas>
<y:instance yclass='ReportPeriod' yid="report">
<language yid='en'/>
<threshold>0.6</threshold>
<typePeriod>predefinedPeriod</typePeriod>
<interval>month</interval>
<valuePeriod>April</valuePeriod>
<fund yclass="Fund">
<name>K</name>
<indexName>CAC40</indexName>
</fund>
</y:instance>
</y:datas>
</y:input>
That I am trying to deserialize to
[XmlRoot(ElementName="fund")]
public class Fund
{
[XmlElement(ElementName="name")]
public string Name { get; set; }
[XmlElement(ElementName="indexName")]
public string IndexName { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
}
[XmlRoot(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public class Instance
{
[XmlElement(ElementName="language")]
public Language Language { get; set; }
[XmlElement(ElementName="threshold")]
public string Threshold { get; set; }
[XmlElement(ElementName="typePeriod")]
public string TypePeriod { get; set; }
[XmlElement(ElementName="interval")]
public string Interval { get; set; }
[XmlElement(ElementName="valuePeriod")]
public string ValuePeriod { get; set; }
[XmlElement(ElementName="fund")]
public Fund Fund { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
[XmlRoot(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public class Datas
{
[XmlElement(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public Instance Instance { get; set; }
}
[XmlRoot(ElementName="input", Namespace="http://www.blahblah.com/engine/42")]
public class Input
{
[XmlElement(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public Datas Datas { get; set; }
[XmlAttribute(AttributeName="y", Namespace="http://www.blahblah.com/engine/42", Form = XmlSchemaForm.Qualified)]
public string Y { get; set; }
}
However, when deserializing the XML above:
public static class Program
{
public static void Main(params string[] args)
{
var serializer = new XmlSerializer(typeof(Input));
using (var stringReader = new StringReader(File.ReadAllText("file.xml")))
{
using(var xmlReader = XmlReader.Create(stringReader))
{
var instance = (Input)serializer.Deserialize(stringReader);
}
}
}
}
I get an error due to the y prefix...
There is an error in XML document (1, 1). ---> System.Xml.XmlException: Data at the root level is invalid. Line 1, position 1.
Reading some posts like that one: https://stackoverflow.com/a/36163079/4636721 it seems that there is maybe a bug with the XmlSerializer.
The cause of the exception is that you are passing stringReader rather than xmlReader to serializer.Deserialize(). You should be passing the XML reader instead:
Input instance = null;
var serializer = new XmlSerializer(typeof(Input));
using (var stringReader = new StreamReader("file.xml"))
{
using(var xmlReader = XmlReader.Create(stringReader))
{
instance = (Input)serializer.Deserialize(xmlReader);
}
}
(Apparently XmlReader.Create(stringReader) advances the text reader a bit, so if you later attempt to read from the stringReader directly, it has been moved past the root element.)
You also have some errors in your data model. It should look like:
[XmlRoot(ElementName="fund")]
public class Fund
{
[XmlElement(ElementName="name")]
public string Name { get; set; }
[XmlElement(ElementName="indexName")]
public string IndexName { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
}
[XmlRoot(ElementName="instance")]
[XmlType(Namespace = "")] // Add this
public class Instance
{
[XmlElement(ElementName="language")]
public Language Language { get; set; }
[XmlElement(ElementName="threshold")]
public string Threshold { get; set; }
[XmlElement(ElementName="typePeriod")]
public string TypePeriod { get; set; }
[XmlElement(ElementName="interval")]
public string Interval { get; set; }
[XmlElement(ElementName="valuePeriod")]
public string ValuePeriod { get; set; }
[XmlElement(ElementName="fund")]
public Fund Fund { get; set; }
[XmlAttribute(AttributeName="yclass")]
public string Yclass { get; set; }
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
[XmlRoot(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public class Datas
{
[XmlElement(ElementName="instance", Namespace="http://www.blahblah.com/engine/42")]
public Instance Instance { get; set; }
}
[XmlRoot(ElementName="input", Namespace="http://www.blahblah.com/engine/42")]
public class Input
{
[XmlElement(ElementName="datas", Namespace="http://www.blahblah.com/engine/42")]
public Datas Datas { get; set; }
//Remove This
//[XmlAttribute(AttributeName="y", Namespace="http://www.blahblah.com/engine/42", Form = XmlSchemaForm.Qualified)]
//public string Y { get; set; }
}
// Add this
[XmlRoot(ElementName="language")]
public class Language
{
[XmlAttribute(AttributeName="yid")]
public string Yid { get; set; }
}
Notes:
xmlns:y='http://www.blahblah.com/engine/42' is an XML namespace declaration and thus should not be mapped to a member in the data model.
The child elements of <y:instance ...> are not in any namespace. Unless the namespace of the child elements is specified by attributes somehow, XmlSerializer will assume that they should be in the same namespace as the containing element, here http://www.blahblah.com/engine/42".
Thus it is necessary to add [XmlType(Namespace = "")] to Instance to indicate the correct namespace for all child elements created from Instance. (Another option would be to add [XmlElement(Form = XmlSchemaForm.Unqualified)] to each member, but I think it is easier to set a single attribute on the type.)
A definition for Language is not included in your question, so I included one.
It will be more efficient to deserialize directly from your file using a StreamReader than to read first into a string, then deserialize from the string using a StringReader.
Working sample fiddle here.

Adding new members in subclass in C#

namespace ClassesRa.Classes
{
public class FicheLine
{
public int ItemRef { get; set; }
public double Amount { get; set; }
public string UnitCode { get; set; }
}
public class Fiche
{
public List<FicheLine> FicheLines { get; set; }
public Fiche()
{
FicheLines = new List<FicheLine>();
}
public string ClientCode { get; set; }
}
public class SalesFicheLine : FicheLine
{
public decimal Price { get; set; }
}
public class SalesFiche : Fiche
{
public List<SalesFicheLine> FicheLines { get; set; }
public SalesFiche()
{
FicheLines = new List<SalesFicheLine>();
}
public string PayCode { get; set; }
}
}
I want to derive SalesFiche from Fiche and add new members.
I want to derive SalesFicheLine from FicheLine and add new members.
I want to see SalesFicheLine in SalesFiche as FicheLine.
Is there a mistake or a defect in the above example?
namespace ClassesRa
{
public partial class fMain : Form
{
public fMain()
{
InitializeComponent();
}
private void fMain_Load(object sender, EventArgs e)
{
SalesFiche f = new SalesFiche();
f.ClientCode = "120.001";
f.PayCode = "30";
f.FicheLines.Add(new SalesFicheLine() { ItemRef = 1, Amount = 10, UnitCode = "PK", Price = 100 });
string xmlString = SerializeToString(f);
}
public string SerializeToString(object obj)
{
string str = "";
XmlSerializer serializer = new XmlSerializer(obj.GetType());
using (StringWriter writer = new StringWriter())
{
serializer.Serialize(writer, obj);
str = writer.ToString();
}
return str;
}
}
}
When I try to convert it to XML with the SerializeToString function, it gives the following error :
{"There was an error reflecting property 'FicheLines'."}
Thanks..
You have to rename the property "FicheLines" in your SalesFiche class. I tested it with "SalesFicheLines". This will fix the crash.
I also recommend that you change your SaleFiche class to this
public class SalesFiche : Fiche
{
public SalesFiche()
:base()
{
}
public string PayCode { get; set; }
}
You already have access to FicheLines's FicheLines property, so there's really no need to create another FicheLines property in SalesFiche.

Deserialize multiple XML tags to single C# object

I have class structure as follows
public class Common
{
public int price { get; set; }
public string color { get; set; }
}
public class SampleProduct:Common
{
public string sample1 { get; set; }
public string sample2 { get; set; }
public string sample3 { get; set; }
}
I have XML file as follows
<ConfigData>
<Common>
<price>1234</price>
<color>pink</color>
</Common>
<SampleProduct>
<sample1>new</sample1>
<sample2>new</sample2>
<sample3>new123</sample3>
</SampleProduct>
</ConfigData>
Now I wanted to deserialize full XML data to SampleProduct object (single object).I can deserialize XML data to different object but not in a single object. Please help.
If you create the XML yourself Just do it like this:
<ConfigData>
<SampleProduct>
<price>1234</price>
<color>pink</color>
<sample1>new</sample1>
<sample2>new</sample2>
<sample3>new123</sample3>
</SampleProduct>
</ConfigData>
Otherwise, if you get the XML from other sources, do what Kayani suggested in his comment:
public class ConfigData
{
public Common { get; set; }
public SampleProduct { get; set; }
}
But don't forget that the SampleProduct created in this manner don't have "price" and "color" properties and these should be set using created Common instance
Here is the complete solution using the provided XML from you.
public static void Main(string[] args)
{
DeserializeXml(#"C:\sample.xml");
}
public static void DeserializeXml(string xmlPath)
{
try
{
var xmlSerializer = new XmlSerializer(typeof(ConfigData));
using (var xmlFile = new FileStream(xmlPath, FileMode.Open))
{
var configDataOSinglebject = (ConfigData)xmlSerializer.Deserialize(xmlFile);
xmlFile.Close();
}
}
catch (Exception e)
{
throw new ArgumentException("Something went wrong while interpreting the xml file: " + e.Message);
}
}
[XmlRoot("ConfigData")]
public class ConfigData
{
[XmlElement("Common")]
public Common Common { get; set; }
[XmlElement("SampleProduct")]
public SampleProduct XSampleProduct { get; set; }
}
public class Common
{
[XmlElement("price")]
public string Price { get; set; }
[XmlElement("color")]
public string Color { get; set; }
}
public class SampleProduct
{
[XmlElement("sample1")]
public string Sample1 { get; set; }
[XmlElement("sample2")]
public string Sample2 { get; set; }
[XmlElement("sample3")]
public string Sample3 { get; set; }
}
This will give you a single Object with all the elements you need.

How to populate list as class object?

How do you populate a list as a class object? For example, this does not work:
[DataContract]
public class JsonReviewFormFields
{
[DataMember]
public PersonalDevelopmentPlan personalDevelopmentPlan { get; set; }
}
public class PersonalDevelopmentPlan
{
public List<ShortTerm> shortTerm { get; set; }
public List<LongTerm> longTerm { get; set; }
}
public class ShortTerm
{
public string workRelated { get; set; }
public string structured { get; set; }
public string informal { get; set; }
public string reviewDate { get; set; }
}
public class LongTerm
{
public string workRelated { get; set; }
public string structured { get; set; }
public string informal { get; set; }
public string reviewDate { get; set; }
}
This is controller action:
public JsonReviewFormFields GetReviewForm()
{
PersonalDevelopmentPlan personalDevelopmentPlan = new PersonalDevelopmentPlan();
List<ShortTerm> _itemsShort = new List<ShortTerm>();
_itemsShort.Add(new ShortTerm { workRelated = "workRelated text", structured = "structured text", informal = "informal text", reviewDate = "reviewDate" });
jsonReviewFormFields.personalDevelopmentPlan.shortTerm = _itemsShort;
List<LongTerm> _itemsLong = new List<LongTerm>();
_itemsLong.Add(new LongTerm { workRelated = "workRelated text", structured = "structured text", informal = "informal text", reviewDate = "reviewDate" });
jsonReviewFormFields.personalDevelopmentPlan.longTerm = _itemsLong;
return jsonReviewFormFields;
}
The code crashes at
jsonReviewFormFields.personalDevelopmentPlan.shortTerm = _itemsShort;
It's probably a basic object orientated error. How do you populate the list?
You are not instantiating it, you have to instantiated the type first:
jsonReviewFormFields.personalDevelopmentPlan = new PersonalDevelopmentPlan();
and then set property of it:
jsonReviewFormFields.personalDevelopmentPlan.shortTerm = _itemsShort
before that you also have to instantiate main class which i don't see in your controller action anywhere :
JsonReviewFormFields jsonReviewFormFields = new JsonReviewFormFields();

Categories

Resources