XML Deserialization - c#

I have an xml file which is in this format
"<rundate>
<rundateItem>
<LeaveCreditingMonth>2</LeaveCreditingMonth>
<LeaveCreditingYear>2010</LeaveCreditingYear>
<IncludeNoTimesheet>True</IncludeNoTimesheet>
</rundateItem>
</rundate>"
in case i want to deserialize this xml file, what should be the format of the class or the target object of my deserialization?
Currently my class looks like this:
public class rundate
{
string _leaveCreditingMonth;
string _leaveCreditingYear;
string _includeNoTimesheet;
public string LeaveCreditingMonth {get{return _leaveCreditingMonth;}set{ _leaveCreditingMonth = value;}}
public string LeaveCreditingYear {get{return _leaveCreditingYear;}set{ _leaveCreditingYear = value;}}
public string IncludeNoTimesheet {get{return _includeNoTimesheet;}set{ _includeNoTimesheet = value;}}
}

Your class can stay as is (obviously you should change the data types to be appropriate though) - since you have rundate nested in your XML (which implies there can be more than one) I would suggest adding a collection class as follows:
[XmlRoot("rundate")]
public class RundateCollection
{
[XmlElement("rundateItem")]
public List<rundate> Rundates { get; set; }
}
You can test serializing/deserializing your class with your XML as follows:
XmlSerializer serializer = new XmlSerializer(typeof(RundateCollection));
StringWriter sw = new StringWriter();
rundate myRunDate = new rundate() { LeaveCreditingMonth = "A", IncludeNoTimesheet = "B", LeaveCreditingYear = "C" };
RundateCollection ra = new RundateCollection() { Rundates = new List<rundate>() { myRunDate } };
serializer.Serialize(sw, ra);
string xmlSerialized = sw.GetStringBuilder().ToString();
string xml = File.ReadAllText(#"test.xml");
StringReader sr = new StringReader(xml);
var rundateCollection = serializer.Deserialize(sr);
You will see that the collection class is successfully deserialized from your XML and contains one list item of type runlist.

I would design the class like so:
public class Rundate
{
public int LeaveCreditingMonth { get; set;}
public int LeaveCreditingYear { get; set; }
public bool IncludeNoTimesheet { get; set; }
}
Then you can deserialize it like this:
var serializer = new XmlSerializer(typeof(List<Rundate>));
using (var fs = new FileStream("yourfile.xml", FileMode.Open))
{
using (var reader = new XmlTextReader(fs))
{
var rundates = (List<Rundate>)serializer.Deserialize(reader);
}
}

Related

file xml inside multiple xml in one line

I have a file .xml inside multiple xml in one line.
How can I read this file and convert to object?
I tried with this code it works if there is only one.
Please help and thank you all
[XmlRoot(ElementName = "DepartmentMaster")]
public class DepartmentMaster
{
[XmlElement(ElementName = "DepartmentId")]
public int DepartmentId { get; set; }
[XmlElement(ElementName = "Name")]
public string Name { get; set; }
[XmlElement(ElementName = "Description")]
public string Description { get; set; }
[XmlElement(ElementName = "test")]
public int Test { get; set; }
}
//string xml = "<DepartmentMaster><DepartmentId>267854</DepartmentId><Name>Purchase</Name><Description>Purchase Department</Description><test>1</test></DepartmentMaster>";
string xml = "<DepartmentMaster><DepartmentId>267854</DepartmentId><Name>Purchase</Name><Description>Purchase Department</Description><test>1</test></DepartmentMaster><DepartmentMaster><DepartmentId>267855</DepartmentId><Name>Purchase5</Name><Description>Purchase Department5</Description><test>5</test></DepartmentMaster>";
using (TextReader reader = new StringReader(xml))
{
System.Xml.Serialization.XmlSerializer deserializer = new System.Xml.Serialization.XmlSerializer(typeof(DepartmentMaster));
var model = (DepartmentMaster)deserializer.Deserialize(reader);
}
image from the database
image from the database
Here it is two approaches below.
The first is using setting to accept XML data with multiple root elements (ConformanceLevel.Fragment).
private static IList<DepartmentMaster> DeserializeFragment(string xml)
{
var settings = new XmlReaderSettings
{
ConformanceLevel = ConformanceLevel.Fragment
};
XmlReader reader = XmlReader.Create(new MemoryStream(Encoding.ASCII.GetBytes(xml)), settings);
var serializer = new XmlSerializer(typeof(DepartmentMaster));
var list = new List<DepartmentMaster>();
while (serializer.Deserialize(reader) is DepartmentMaster element)
{
list.Add(element);
}
return list;
}
And the second by adding a root element to deserialize a well-formed XML document.
public class DepartmentMasters
{
[XmlElement("DepartmentMaster")]
public List<DepartmentMaster> Items;
}
private static DepartmentMasters DeserializeWellFormedXML(string xml)
{
var text = #"<?xml version=""1.0""?><DepartmentMasters>" + xml + "</DepartmentMasters>";
var serializer = new XmlSerializer(typeof(DepartmentMasters));
return (DepartmentMasters)serializer.Deserialize(new StringReader(text));
}

Creating a XML file from a database with a model C#

So I need to create a method that makes an XML file from a database, I have already written the stored procedures that get the information from a database for the XML now I only need to write the part where I convert my database to a XML file using the properties of another class that I have written as nodes.
public string CreateXML(Object YourClassObject){
XmlDocument xmlDoc =new XmlDocument(); //Represents an XML document,
// Initializes a new instance of the XmlDocument class.
XmlSerializer xmlSerializer = new XmlSerializer(YourClassObject.GetType());
// Creates a stream whose backing store is memory.
using (MemoryStream xmlStream =new MemoryStream())
{
xmlSerializer.Serialize(xmlStream, YourClassObject);
xmlStream.Position = 0;
//Loads the XML document from the specified string.
xmlDoc.Load(xmlStream);
return xmlDoc.InnerXml;
}
}
This is some code I found online I think I can use for serializing my model, but i'm accessing the database over an event that I created (I'll provide the code tomorrow when I get to work). Anyway I'm accesing the database in the event like the following e.DataTable. Any ideas anybody?
My model looks like the following:
public class DataModel
{
string Sifra {get; set;}
public string Naziv {get; set;}
public string JM {get; set;}
public int Kolicina {get; set;}
public float Cena_x0020_vp {get; set;}
public float Cena_x0020_mp {get; set;}
public float Cena_x0020_bod {get; set;}
public string Slika {get; set;}
public string Grupa {get; set;}
}
This is a sample of how my generated XML should look like.
<?xml version="1.0" encoding="UTF-8"?>
<dataroot xmlns:od="urn:schemas-microsoft-com:officedata" generated="2019-04-17T19:13:54">
<row>
<Sifra>ADA110-100</Sifra>
<Naziv_x0020_artikla>Adapter 220/110VAC 100W</Naziv_x0020_artikla>
<JM>kom</JM>
<Kolicina>1</Kolicina>
<Cena_x0020_vp>2683.33</Cena_x0020_vp>
<Cena_x0020_mp>3220</Cena_x0020_mp>
<Cena_x0020_bod>28</Cena_x0020_bod>
<Slika1> ada110v.jpg</Slika1>
<Grupa>Adateri 110V AC</Grupa>
</row>
Problem solved:
private void CreateXML(DataTable dataTable)
{
var list = new List<Row>();
XmlSerializer writer = new XmlSerializer(typeof(List<Row>));
var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\ExportZaWeb.xml";
FileStream file = File.Create(path);
foreach (DataRow row in dataTable.Rows)
{
Row r = new Row();
r.Naziv = row["Naziv Artikla"].ToString();
r.JM = row["JM"].ToString();
r.Kolicina = row["Kolicina"].ToString();
r.Cena_x0020_vp = row["Cena vp"].ToString();
r.Cena_x0020_mp = row["Cena mp"].ToString();
r.Cena_x0020_bod = row["Cena bod"].ToString();
r.Slika = row["Slika1"].ToString();
r.Grupa = row["Grupa"].ToString();
list.Add(r);
}
writer.Serialize(file, list);
file.Close();
}
Why not let the stored procedure return the xml for you. The query in the stored procedure would lool something like this:
SELECT Sifra, Naziv, JM, Kolicina, Cena_x0020_vp, Cena_x0020_mp, Cena_x0020_bod, Slika, Grupa
FROM DataModel
FOR XML AUTO
Create a method which takes in a list or IEnumerable object of the Models and returns a string containing the XML (untested, but should get you started), this is assuming you already have the database data in usable objects:
public string GetXmlForModels(IEnumerable<DataModel> dataModels)
{
//Assume a list of DataModels is in dataModels of type IEnumerable<DataModel>
var doc = new XmlDocument();
foreach (var model in dataModels)
{
var row = (XmlElement)doc.AppendChild(doc.CreateElement("row"));
row.SetAttribute("xmlns:od", "urn:schemas-microsoft-com:officedat");
row.SetAttribute("generated", DateTime.Now.ToString("yy-MM-ddTHH:mm:ss"));
var sifraElement = doc.CreateElement("Sifra");
sifraElement.InnerText = model.Sifra;
row.AppendChild(sifraElement);
//Repeat top 3 lines for each element ...
doc.AppendChild(row);
}
return doc.OuterXml;
}
Use XML Serializer :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication110
{
class Program
{
const string INPUT_FILENAME = #"c:\temp\test.xml";
const string OUTPUT_FILENAME = #"c:\temp\test1.xml";
static void Main(string[] args)
{
XmlReader reader = XmlReader.Create(INPUT_FILENAME);
string xml = reader.ToString();
XmlSerializer serializer = new XmlSerializer(typeof(DataRoot));
DataRoot root = (DataRoot)serializer.Deserialize(reader);
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
XmlWriter writer = XmlWriter.Create(OUTPUT_FILENAME,settings);
serializer.Serialize(writer, root);
}
}
[XmlRoot(ElementName = "dataroot", Namespace = "")]
public class DataRoot
{
[XmlElement(ElementName = "row", Namespace = "")]
public List<DataModel> rows { get; set; }
}
[XmlRoot(ElementName = "row", Namespace = "")]
public class DataModel
{
string Sifra { get; set; }
public string Naziv { get; set; }
public string JM { get; set; }
public int Kolicina { get; set; }
public float Cena_x0020_vp { get; set; }
public float Cena_x0020_mp { get; set; }
public float Cena_x0020_bod { get; set; }
public string Slika { get; set; }
public string Grupa { get; set; }
}
}

Deserialising XML with different element name in c#

XML:
<?xml version="1.0" encoding="UTF-8"?>
<Images>
<I0>
<Path>123.com</Path>
<I0>
<I1>
<Path>123.com</Path>
<I1>
<I2>
<Path>123.com</Path>
<I2>
</Images>
Can serializer.Deserialize() be used to get tags with different names into a collection?
currently, in my object I have:
C#:
public class rootObject
{
[XmlElement(ElementName = "I0")]
public I0 I0 { get; set; }
[XmlElement(ElementName = "I1")]
public I1 I1 { get; set; }
[XmlElement(ElementName = "I2")]
public I2 I2 { get; set; }
}
But I would like to have (Because Images can have more or fewer elements):
public class rootObject
{
public List<I> Is { get; set; }
}
You can do what you are suggesting you just merely need to pass in the type argument in your class doing the generic. The key point to remember when you do a deserialization routine is that the routine needs to know the sub reference. So if I was to say string.Deserialize it would bomb. It would need to know a reference string.Deserialize> where Sub could be the class object that may change.
Say I have a base class and I want 'T' to be a type I can change for extensible abilities later.
[Serializable]
public class Test<T> where T : class
{
public Test() { }
public int TestId { get; set; }
public string Name { get; set; }
public List<T> Shipments { get; set; }
}
I want to test this with two classes I just make up that have different properties slightly
[Serializable]
public class Sub1
{
public int Id { get; set; }
public string Desc { get; set; }
}
[Serializable]
public class Sub2
{
public int IdWhatever { get; set; }
public string DescWhatever { get; set; }
}
Now let's do a main program and test serialization.
class Program
{
static void Main(string[] args)
{
var serializeTest = new Test<Sub1> { TestId = 1, Name = "Test", Shipments = new List<Sub1> { new Sub1 { Id = 1, Desc = "Test" }, new Sub1 { Id = 2, Desc = "Test2" } } };
var serializeTest2 = new Test<Sub2> { TestId = 1, Name = "Test", Shipments = new List<Sub2> { new Sub2 { IdWhatever = 1, DescWhatever = "Test" }, new Sub2 { IdWhatever = 2, DescWhatever = "Test2" } } };
var serialized = serializeTest.SerializeToXml();
var serialized2 = serializeTest2.SerializeToXml();
var deserialized = serialized.DeserializeXml<Test<Sub1>>();
var deserialized2 = serialized2.DeserializeXml<Test<Sub2>>();
Console.WriteLine(serialized);
Console.WriteLine();
Console.WriteLine(serialized2);
Console.ReadLine();
}
}
And my Serialize and DeSerialize extension methods:
public static string SerializeToXml<T>(this T valueToSerialize, string namespaceUsed = null)
{
var ns = new XmlSerializerNamespaces(new XmlQualifiedName[] { new XmlQualifiedName(string.Empty, (namespaceUsed != null) ? namespaceUsed : string.Empty) });
using (var sw = new StringWriter())
{
using (XmlWriter writer = XmlWriter.Create(sw, new XmlWriterSettings { OmitXmlDeclaration = true }))
{
dynamic xmler = new XmlSerializer(typeof(T));
xmler.Serialize(writer, valueToSerialize, ns);
}
return sw.ToString();
}
}
public static T DeserializeXml<T>(this string xmlToDeserialize)
{
dynamic serializer = new XmlSerializer(typeof(T));
using (TextReader reader = new StringReader(xmlToDeserialize))
{
return (T)serializer.Deserialize(reader);
}
}
You don't need to specify the XmlElement name when the properties match the XML. A few solutions, some kinda hacky :).
HACKY: use regex string replace to replace <I#> and </I#> to
just <I> and </I>
SOMEWHAT HACKY: This might work for you:
How to deserialize an XML array containing multiple types of elements in C#,
but you'd have to add an attribute for i0, i1 ... i100, etc.
BEST: Is that your entire XML? I'd honestly just use LINQToXml and
do a Descendants("Path") and get an array of strings back with 1 line of code. Serialization is not really the best solution for this.

Serialization Fail on list of lists using DataContractSerializer

I have some class that has a property of type List<object> I need to serialize that class to XML file using DataContractSerializer.
The serialization fails on ArgumentException when the object is a List<T>/IEnumerator<T>exception message:
Invalid name character in
'System.Collections.Generic.List`1[[MyProj.Result, MyProj,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'.
Here is the code sample that fails
The Class that takes the List<object>
[DataContract(IsReference = true)]
public class RecoveryMethodData
{
[DataMember]
public List<object> Parameters { get; set; }
public RecoveryMethodData()
{
Parameters = new List<object>();
}
public static void SerializeToFile(RecoveryMethodData recoveryMethodData, string fileName)
{
var encoding = Encoding.UTF8;
using (var fileWriter = new XmlTextWriter(fileName, encoding))
{
fileWriter.Formatting = Formatting.Indented;
// use SharedTypeResolver for deserializing assistance.
var serializer = new DataContractSerializer(typeof(RecoveryMethodData), null, int.MaxValue, false, true, null, new SharedTypeResolver());
serializer.WriteObject(fileWriter, recoveryMethodData);
}
}
}
Here is the usage:
private void TestSerialization()
{
var methodData = new RecoveryMethodData();
var result = new Result() {Message = "wow", Pass = true, FileName = "somefile "};
methodData.Parameters.Add(result);
methodData.Parameters.Add(true);
var list1 = new List<Result>();
list1.Add(new Result(){FileName = "in list1", Message = "in l 1"});
list1.Add(new Result(){FileName = "in list2", Message = "in l 2"});
methodData.Parameters.Add(list1);
RecoveryMethodData.SerializeToFile(methodData,#"C:\serialization_result.xml");
}
public class Result
{
public string Message { get; set; }
public string FileName { get; set; }
}
If I do not add list1 into the methodData.Parameters there is no problem serializing the methodDatad object.
One big limitation is that I can't know in advance which kind of objects will be added to the Parameters property (that is why it is a list of objects)
In order to DataContractSerializer to serialize an object, it shall know the types of all datamembers. In your case, you do not define a specific type but an object type. Try changing the definition of
public List<object> Parameters { get; set; }
to something like:
public List<IMyObject> Parameters { get; set; }
Note that, all of your objects which you are trying to add to the parameters list shall inherit IMyObject interface.
Update: I refactored your code up to some point (still in a bad shape) and it seems working, please have a try;
public class Tester
{
public Tester()
{
this.TestSerialization();
}
public void SerializeToFile(RecoveryMethodData recoveryMetaData,string fileName)
{
var encoding = Encoding.UTF8;
using (var fileWriter = new XmlTextWriter(fileName, encoding))
{
fileWriter.Formatting = Formatting.Indented;
// use SharedTypeResolver for deserializing assistance.
var serializer = new DataContractSerializer(typeof(RecoveryMethodData),new List<Type>(){typeof(bool),typeof(Result),typeof(List<Result>)});
serializer.WriteObject(fileWriter,recoveryMetaData);
}
}
private void TestSerialization()
{
var methodData = new RecoveryMethodData();
var result = new Result() { Message = "wow", Pass = true, FileName = "somefile " };
methodData.Add(result);
methodData.Add(true);
var list1 = new List<Result>();
list1.Add(new Result() { FileName = "in list1", Message = "in l 1" });
list1.Add(new Result() { FileName = "in list2", Message = "in l 2" });
methodData.Add(list1);
SerializeToFile(methodData, #"C:\serialization_result.xml");
}
}
public class Result
{
public string Message { get; set; }
public string FileName { get; set; }
public bool Pass { get; set; }
}
public class RecoveryMethodData : List<object>
{
}

xml output from class

I'm trying to generate xml output (based on a class) that looks like this:
<cdsXMLEnvelope>
<TestValue1>x1</TestValue1>
<inner>
<eTestValue1>e1</eTestValue1>
</inner>
<inner>
<eTestValue1>e1</eTestValue1>
</inner>
<inner>
<eTestValue1>e1</eTestValue1>
</inner>
</cdsXMLEnvelope>
[System.Xml.Serialization.XmlRootAttribute("cdsXMLEnvelope", Namespace = "", IsNullable = false)]
[XmlTypeAttribute(Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
//public class cdsXMLEnvelope : cdsXMLinfo
public class cdsXMLEnvelope
{
[XmlElementAttribute(ElementName = "eTestValue1")]
public string eTestValue1 { get; set; }
[System.Xml.Serialization.XmlArrayItem("inner")]
public cdsXMLinfo[] cdsXMLinfo { get; set; }
}
//[XmlTypeAttribute(Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public class cdsXMLinfo
{
[XmlElementAttribute(ElementName = "TestValue1")]
public string TestValue1 { get; set; }
[System.Xml.Serialization.XmlAttributeAttribute()]
public string TestValue3 { get; set; }
}
please help me hook this code up, change the class etc-- I keep trying a variety of ways & I get object not found & misc errors when trying to serialize it to xml
also can I avoid using an array for the inner elements? do I use lists?
I'll try to refine this question as we go, I know people hate these long ?'s
Thanks!!
{
cdsXMLEnvelope x = new cdsXMLEnvelope();
x.eTestValue1 = "x1";
x.cdsXMLinfo = new cdsXMLinfo[1];
x.cdsXMLinfo[0].TestValue1 = "xi1";
//x.cdsXMLinner[0].TestValue1 = "xi2";
XmlSerializer writer = new XmlSerializer(x.GetType());
StreamWriter file = new StreamWriter("x.xml");
writer.Serialize(file, x);
file.Close();
}
I think this gives what you want, however your example was not quite consistent:
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace Serialize
{
class Program
{
static void Main( string[] args )
{
var envelope = new CdsXmlEnvelope
{
TestValue1 = "x1",
InnerList = new List<CdsXmlInfo>
{
new CdsXmlInfo {TestValue1 = "e1"},
new CdsXmlInfo {TestValue1 = "e1"},
new CdsXmlInfo {TestValue1 = "e1"},
}
};
var ns = new XmlSerializerNamespaces();
ns.Add( string.Empty, string.Empty );
var serializer = new XmlSerializer( typeof( CdsXmlEnvelope ) );
using( var stream = new MemoryStream() )
{
var settings = new XmlWriterSettings();
settings.OmitXmlDeclaration = true;
settings.Indent = true;
var writer = XmlWriter.Create( stream, settings );
serializer.Serialize( writer, envelope, ns );
stream.Position = 0;
Console.WriteLine( new StreamReader( stream ).ReadToEnd() );
}
Console.ReadLine();
}
}
[XmlRoot( "cdsXMLEnvelope" )]
public class CdsXmlEnvelope
{
[XmlElement( "TestValue1" )]
public string TestValue1 { get; set; }
[XmlElement( "inner" )]
public List<CdsXmlInfo> InnerList { get; set; }
}
public class CdsXmlInfo
{
[XmlElement( "TestValue1" )]
public string TestValue1 { get; set; }
[XmlAttribute]
public string TestValue3 { get; set; }
}
}
giving output:
<cdsXMLEnvelope>
<TestValue1>x1</TestValue1>
<inner>
<TestValue1>e1</TestValue1>
</inner>
<inner>
<TestValue1>e1</TestValue1>
</inner>
<inner>
<TestValue1>e1</TestValue1>
</inner>
</cdsXMLEnvelope>
If you have the schema, you could try using Xsd.exe to generate the C# classes for you.

Categories

Resources