How to parse through XML and create object in C# [duplicate] - c#

This question already has answers here:
How do I read and parse an XML file in C#?
(12 answers)
Closed 3 years ago.
I want to create list of whitelist objects from the below XML.
Created a class WhiteList
class WhiteList
{
public string ID { get; set; }
public string From { get; set; }
public string To { get; set; }
}
I need to create list of objects out of the XML
<Response>
<list>
<whitelist>
<id>1234</id>
<from>sdfkmsfk#wfgtitleco.com</from>
<to>dsfgsdf#loansdfglosers.com</to>
</whitelist>
<whitelist>
<id>1452</id>
<from>mdsfgaursdfgdfmimi#gmail.com</from>
<to>dfsgdscew#loansdfglosers.com</to>
</whitelist>
<whitelist>
<id>9483</id>
<from>prvs=17958ac559=dmcclain#wfgtitleco.com</from>
<to>status#loansdfglosers.com</to>
</whitelist>
<whitelist>
<id>5654</id>
<from>ewrgre#loansdfglosers</from>
<to>werferw#loansdfglosers.com</to>
</whitelist>
</list>
</Response>

Here is a straightforward example using your XML document:
public static List<WhiteList> CreateObjects(XDocument xmldoc)
{
var query = from data in xmldoc.Descendants("whitelist")
select new WhiteList
{
ID = (string)data.Element("id"),
From = (string)data.Element("from"),
To = (string)data.Element("to"),
};
var list = query.ToList();
List<WhiteList> result = new List<WhiteList>();
// now create the desierd list
foreach (var x in list)
{
WhiteList ws = new WhiteList();
ws.ID = x.ID;
ws.From = x.From;
ws.To = x.To;
result.Add(ws);
}
return result;
}

A generic class that I have created for serializing and de-serializing XML to .net object and vice versa.
You need to add a helper class as below. Just change the namespace as your project.
using System.IO;
using System.Xml.Serialization;
namespace YourProject
{
public class XMLParser<T> where T : class
{
public static T Deserialize(string path)
{
T item;
try
{
var serializer = new XmlSerializer(typeof(T));
using (var reader = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read))
{
item = (T)serializer.Deserialize(reader);
reader.Dispose();
}
}
catch (System.Exception)
{
throw;
}
return item;
}
public static void Serialize(object item, string path)
{
var serializer = new XmlSerializer(typeof(T));
using (var fs = new FileStream(path, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
{
using (var writer = new StreamWriter(fs))
{
serializer.Serialize(writer, item);
writer.Close();
writer.Dispose();
}
}
}
}
}
Now your class is not complaint with XML so you need to change your class a bit.
class Response{
public List<WhiteList> list{get; set;}
}
class WhiteList{
public string ID {get;set;}
public string From {get;set;}
public string To {get;set;}
}
Now you can call XMLParser class to serialize or deserialize XML or .net object.
Below is the call
Just provide the path to XML
Response response = XMLParser<Response>.Deserialize([path of XML]);

Related

How to deserialize XML to get the data from tags?

I have below XML stored in a string RequestPassengerXML. How can I deserialize it so that I can get the tags information which I can assign it to my class members.
<?xml version="1.0" encoding="utf-16"?>
<Passenger xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>John Vaz</Name>
<Email>john#gmail.com</Email>
<cardNumber>CB2390VT</cardNumber>
</Passenger>
I have created a class with below details
public class PassengerDetails
{
public PassengerDetails();
public string Name { get; set; }
public string Email { get; set; }
public string CardNumber{ get; set; }
}
public static XElement ToXElement<T>(this object obj)
{
using (var memoryStream = new MemoryStream())
{
using (TextWriter streamWriter = new StreamWriter(memoryStream))
{
var xmlSerializer = new XmlSerializer(typeof(T));
xmlSerializer.Serialize(streamWriter, obj);
return XElement.Parse(Encoding.ASCII.GetString(memoryStream.ToArray()));
}
}
}
public static T FromXElement<T>(this XElement xElement)
{
var xmlSerializer = new XmlSerializer(typeof(T));
return (T)xmlSerializer.Deserialize(xElement.CreateReader());
}
Usage:
XElement element = PassengerDetails.ToXElement<PassengerDetails>();
var newMyClass = element.FromXElement<PassengerDetails>();

How to Serialize Object to Xml

The class I want to store:
[Serializable]
public class Storagee
{
int tabCount;
List<string> tabNames;
List<EachItemListHolder> eachItemsHolder;
public void PreSetting(int count, List<string> strings, List<EachItemListHolder> items)
{
tabCount = count;
tabNames = strings;
eachItemsHolder = items;
}
public void PreSetting(int count ) //debug purpose
{
tabCount = count;
}
public int GetTabCount() { return tabCount; }
public List<string> GetTabNames() { return tabNames; }
public List<EachItemListHolder> GetListEachItemListHolder() { return eachItemsHolder; }
}
Serializing class:
namespace Book
{
class SaveAndLoad
{
public void SaveAll(Storagee str)
{
var path = #"C:\Temp\myserializationtest.xml";
using (FileStream fs = new FileStream(path, FileMode.Create))
{
XmlSerializer xSer = new XmlSerializer(typeof(Storagee));
xSer.Serialize(fs, str);
}
}
public Storagee LoadAll()
{
var path = #"C:\Temp\myserializationtest.xml";
using (FileStream fs = new FileStream(path, FileMode.Open)) //double
{
XmlSerializer _xSer = new XmlSerializer(typeof(Storagee));
var myObject = _xSer.Deserialize(fs);
return (Storagee)myObject;
}
}
}
}
Main method (Window form):
class Book
{
List<EachTab> eachTabs;
Storagee storagee;
SaveAndLoad saveAndLoad;
eachTabs = new List<EachTab>();
storagee = new Storagee();
saveAndLoad = new SaveAndLoad();
void Saving()
{
int count = UserTab.TabCount; // tab counts
storagee.PreSetting(count);
saveAndLoad.SaveAll(storagee);
}
}
It makes xml file but doesn't save data.
I tried the serializing code in different project and it worked.
but it doesn't in this solution
since I'm kind of new to coding I don't know what the problem is
especially serializing part.
serializing codes are copied and pasted with little tweak
It makes xml file but doesn't save data.
It doesn't save any data because your class does not provide any data that it can serialize. XmlSerializer only serializes public fields and properties and the Storagee class doesn't have any.
You could, for example, change your public getter methods to public properties:
public int TabCount { get; set; }
public List<string> TabNames { get; set; }
public List<string> EachItemsHolder { get; set; }
Alternatively, if using public properties is not an option, you could also look into using custom serialization by implementing IXmlSerializable.

De-/serialization with a list of objects

I try to save and read multiple objects in one XML-File.
The function Serialize is not working with my existing List, but i dont know why. I already tried to compile it but i get an error wich says, that the methode needs an object refference.
Program.cs:
class Program
{
static void Main(string[] args)
{
List<Cocktail> lstCocktails = new List<Cocktail>();
listCocktails.AddRange(new Cocktail[]
{
new Cocktail(1,"Test",true,true,
new Cocktail(1, "Test4", true, true, 0)
});
Serialize(lstCocktails);
}
public void Serialize(List<Cocktail> list)
{
XmlSerializer serializer = new XmlSerializer(typeof(List<Cocktail>));
using (TextWriter writer = new StreamWriter(#"C:\Users\user\Desktop\MapSample\bin\Debug\ListCocktail.xml"))
{
serializer.Serialize(writer, list);
}
}
private void DiserializeFunc()
{
var myDeserializer = new XmlSerializer(typeof(List<Cocktail>));
using (var myFileStream = new FileStream(#"C:\Users\user\Desktop\MapSample\bin\Debug\ListCocktail.xml", FileMode.Open))
{
ListCocktails = (List<Cocktail>)myDeserializer.Deserialize(myFileStream);
}
}
Cocktail.cs:
[Serializable()]
[XmlRoot("locations")]
public class Cocktail
{
[XmlElement("id")]
public int CocktailID { get; set; }
[XmlElement("name")]
public string CocktailName { get; set; }
[XmlElement("alc")]
public bool alcohol { get; set; }
[XmlElement("visible")]
public bool is_visible { get; set; }
[XmlElement("counter")]
public int counter { get; set; }
private XmlSerializer ser;
public Cocktail() {
ser = new XmlSerializer(this.GetType());
}
public Cocktail(int id, string name, bool alc,bool vis,int count)
{
this.CocktailID = id;
this.CocktailName = name;
this.alcohol = alc;
this.is_visible = vis;
this.counter = count;
}
}
}
Ii also think I messed something up with the DiserializeFunc().
You are very close to implementing the Cocktail class correctly, but I think you're confused about how to serialize Lists. Your implementation of a Cocktail object class is completely fine, just get rid of the list related functions.
using System;
using System.Xml.Serialization;
namespace Serialization_Help
{
[Serializable()]
[XmlRoot("locations")]
public class Cocktail
{
[XmlElement("id")]
public int CocktailID { get; set; }
[XmlElement("name")]
public string CocktailName { get; set; }
[XmlElement("alc")]
public bool alcohol { get; set; }
[XmlElement("visible")]
public bool is_visible { get; set; }
[XmlElement("counter")]
public int counter { get; set; }
public Cocktail() {
}
public Cocktail(int id, string name, bool alc, bool vis, int count)
{
this.CocktailID = id;
this.CocktailName = name;
this.alcohol = alc;
this.is_visible = vis;
this.counter = count;
}
}
}
Now in your new function you want to serialize the list directly.
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
namespace Serialization_Help
{
class Program {
static void Main(string[] args) {
List<Cocktail> list = new List<Cocktail> {
new Cocktail(01, "rum and coke", true, true, 5),
new Cocktail(02, "water on the rocks", false, true, 3)
};
Serialize(list);
List<Cocktail> deserialized = DiserializeFunc();
}
public static void Serialize(List<Cocktail> list) {
XmlSerializer serializer = new XmlSerializer(typeof(List<Cocktail>));
using (TextWriter writer = new StreamWriter(Directory.GetCurrentDirectory() + #"\ListCocktail.xml")) serializer.Serialize(writer, list);
}
private static List<Cocktail> DiserializeFunc() {
var myDeserializer = new XmlSerializer(typeof(List<Cocktail>));
using (var myFileStream = new FileStream(Directory.GetCurrentDirectory() + #"\ListCocktail.xml", FileMode.Open)) return (List<Cocktail>)myDeserializer.Deserialize(myFileStream);
}
}
}
Doing so should correctly print out the following .xml output:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfCocktail xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Cocktail>
<id>1</id>
<name>rum and coke</name>
<alc>true</alc>
<visible>true</visible>
<counter>5</counter>
</Cocktail>
<Cocktail>
<id>2</id>
<name>water on the rocks</name>
<alc>false</alc>
<visible>true</visible>
<counter>3</counter>
</Cocktail>
</ArrayOfCocktail>
Keep in mind that I have not provided implementation of any of the standard safety or null checks for the file. You'll have to check if the file exists yourself by using File.Exists(...) (see here for File.Exists implementation) and implement the correct try and catch cases and what your code will chose to do if it runs into serialization or input/outut errors.
You'd better use ExtendedXmlSerializer to serialize and deserialize.
Instalation
You can install ExtendedXmlSerializer from nuget or run the following command:
Install-Package ExtendedXmlSerializer
Serialization:
ExtendedXmlSerializer serializer = new ExtendedXmlSerializer();
var list = new List<Cocktail>();
var xml = serializer.Serialize(list);
Deserialization
var list = serializer.Deserialize<List<Cocktail>>(xml);
Standard XML Serializer in .NET is very limited.
Does not support serialization of class with circular reference or class with interface property,
Does not support Dictionaries,
There is no mechanism for reading the old version of XML,
If you want create custom serializer, your class must inherit from IXmlSerializable. This means that your class will not be a POCO class,
Does not support IoC.
ExtendedXmlSerializer can do this and much more.
ExtendedXmlSerializer support .NET 4.5 or higher and .NET Core. You can integrate it with WebApi and AspCore.

Unable to convert XML to C# Object List

I'm trying to convert the XML data to an object list, but it throws an error.
XML
<?xml version="1.0" encoding="utf-8" ?>
<Servers>
<Server>
<ServerName>STAGING</ServerName>
<ServerIP>XXX.XXX.XX.X</ServerIP>
</Server>
</Servers>
C#
public class ServerDetails
{
public string ServerName { get; set; }
public string ServerIP { get; set; }
}
private void GetXMLData()
{
XmlSerializer serializer = new XmlSerializer(typeof(List<ServerDetails>));
using (FileStream stream = File.OpenRead("D:\\Resource.xml"))
{
List<ServerDetails> list = (List<ServerDetails>)serializer.Deserialize(stream);
//Exception here
}
}
ERROR
Inner Exception : <Servers xmlns=''> was not expected.
There is an error in XML document (2,2)
I tried adding the [Serializabe] and [XMLElement] attributes to the class,
and also xmlns="http://www.example.com/xsd/ServerDetails" in the XML
but that did not help.
You have ServerDetails as your class name and in the xml the tag name is different, Try something like this.
public class ServerDetails
{
public string ServerName { get; set; }
public string ServerIP { get; set; }
}
public class ServerList
{
[XmlArray("Servers")]
[XmlArrayItem("Server", Type = typeof(ServerDetails))]
public ServerDetails[] Servers { get;set;}
}
private void GetXMLData()
{
XmlSerializer serializer = new XmlSerializer(typeof(ServerList));
using (FileStream stream = File.OpenRead("D:\\Resource.xml"))
{
var list = (ServerList)serializer.Deserialize(stream);
//Exception here
}
}
I used to use XmlSerializer a lot, but I totally stopped using it because you are forced to create your object structure fitting the xml structure. That makes it hard to maintain. Also XmlSerializer has some serious memory leaks.
If you don't mind, I would suggest to switch to XElement
public IEnumerable<ServerDetails> GetServers(string file)
{
using (var stream = File.Open(file, FileMode.Open, FileAccess.Read))
return GetServers(stream);
}
public IEnumerable<ServerDetails> GetServers(Stream stream)
{
var root = XElement.Load(stream);
return GetServers(root);
}
public IEnumerable<ServerDetails> GetServers(XElement root)
{
foreach (var server in root.Elements("Server"))
{
yield return new ServerDetails
{
ServerName = (string)server.Element("ServerName"),
ServerIP = (string)server.Element("ServerIP"),
};
}
}
Please note that you have to reference System.Xml.Linq
For your convenience here is a test case.
[TestMethod]
public void CanReadServers()
{
var xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + #"
<Servers>
<Server>
<ServerName>STAGING</ServerName>
<ServerIP>XXX.XXX.XX.X</ServerIP>
</Server>
</Servers>";
IEnumerable<ServerDetails> servers;
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(xml)))
servers = GetServers(stream).ToList();
Assert.AreEqual(1, servers.Count());
Assert.AreEqual("STAGING", servers.ElementAt(0).ServerName);
Assert.AreEqual("XXX.XXX.XX.X", servers.ElementAt(0).ServerIP);
}
Use XmlElement Notation to specify the element name.
public class Servers
{
[XmlElement("Server")]
public ServerDetails[] ServersDetails { get; set; }
}
public class ServerDetails
{
public string ServerName { get; set; }
public string ServerIP { get; set; }
}
private void GetXMLData()
{
XmlSerializer serializer = new XmlSerializer(typeof(Servers));
using (FileStream stream = File.OpenRead("D:\\Resource.xml"))
{
Servers list = (Servers)serializer.Deserialize(stream);
//Exception here
}
}

XmlSerializer/Deserialize in C#

I created this class where it'll append to the XML called Email Alerts h1, body and ids. However, im having trouble running this file from the start (when i call LoadFromFile), when the file does not exist - so we'll have to create a file and start logging it.
public class EMailAlert
{
public string h1 { get; set; }
public string body { get; set; }
public string idList { get; set; }
public void Save(string fileName)
{
using (var stream = new FileStream(fileName, FileMode.Create))
{
var XML = new XmlSerializer(typeof(EMailAlert));
XML.Serialize(stream, this);
}
}
public static EMailAlert LoadFromFile(string fileName)
{
if (!File.Exists(fileName))
{
var file = new FileInfo(fileName);
file.Directory.Create();
var xmlFile = new XDocument(
new XDeclaration("1.0", "utf-8", "yes"),
new XComment("Email Logger"));
xmlFile.Add(new XElement("EmailAlerts"));
xmlFile.Save(fileName);
}
using (var stream = new FileStream(fileName, FileMode.Open))
{
var XML = new XmlSerializer(typeof(EMailAlert));
return (EMailAlert)XML.Deserialize(stream);
}
}
}
When i run this code (there are no xml file - so it creates an XML file and then it throws this error {"<EmailAlerts xmlns=''> was not expected."}
Here is how the xml file looks like
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<!--Email Logger-->
<EmailAlerts />
Not sure why its not sending back an empty EmailAlert when i call LoadFromFile.
You need a collectiontype for your all your EMailAlerts to be serialized as valid xml.
The following code does that. By creating a static helper class that holds a static List of all our EmailAlerts. It also has the Load and Save methods which reads and writes the file and use the property Alerts to get or store the EmailAlerts.
You can use attributes on your EmailAlert class if you want to control serialization. See this answer how you could do that.
public static class EMailAlerts
{
static XmlSerializer XML = new XmlSerializer(typeof(List<EMailAlert>));
public static List<EMailAlert> Alerts { get; private set; }
public static void Save(string fileName)
{
using (var stream = new FileStream(fileName, FileMode.Create))
{
XML.Serialize(stream, Alerts);
}
}
public static void LoadFromFile(string fileName)
{
if (!File.Exists(fileName))
{
Alerts = new List<EMailAlert>();
}
else
{
using (var stream = new FileStream(fileName, FileMode.Open))
{
Alerts = (List<EMailAlert>)XML.Deserialize(stream);
}
}
}
}
public class EMailAlert
{
public string h1 { get; set; }
public string body { get; set; }
public string idList { get; set; }
}
class Program
{
static void Main(string[] args)
{
EMailAlerts.LoadFromFile("tmp.xml");
EMailAlerts.Alerts.Add(new EMailAlert{ body="foo"});
EMailAlerts.Save("tmp.xml");
}
}

Categories

Resources