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));
}
Related
I have been reading How To Parse XML In .NET Core There they show an example on parsing XML using XMLSerializer.
[XmlRoot("MyDocument", Namespace = "http://www.dotnetcoretutorials.com/namespace")]
public class MyDocument
{
public string MyProperty { get; set; }
public MyAttributeProperty MyAttributeProperty { get; set; }
[XmlArray]
[XmlArrayItem(ElementName = "MyListItem")]
public List MyList { get; set; }
}
public class MyAttributeProperty
{
[XmlAttribute("value")]
public int Value { get; set; }
}
and to read it:
using (var fileStream = File.Open("test.xml", FileMode.Open))
{
XmlSerializer serializer = new XmlSerializer(typeof(MyDocument));
var myDocument = (MyDocument)serializer.Deserialize(fileStream);
Console.WriteLine($"My Property : {myDocument.MyProperty}");
Console.WriteLine($"My Attribute : {myDocument.MyAttributeProperty.Value}");
foreach(var item in myDocument.MyList)
{
Console.WriteLine(item);
}
}
In the code above itreads the local xml file:
using (var fileStream = File.Open("test.xml", FileMode.Open)).
I want to read an XML file from URL, and make use of XmlSerializer, how would I accomplish this?
Since you already have your XML parsing logic in place, all you need is to swap out the file reading for an HTTP request.
using (var client = new HttpClient())
{
var content = await client.GetStreamAsync("http://...");
XmlSerializer serializer = new XmlSerializer(typeof(MyDocument));
var myDocument = (MyDocument)serializer.Deserialize(new MemoryStream(content));
Console.WriteLine($"My Property : {myDocument.MyProperty}");
Console.WriteLine($"My Attribute : {myDocument.MyAttributeProperty.Value}");
foreach(var item in myDocument.MyList)
{
Console.WriteLine(item);
}
}
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; }
}
}
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.
I am trying to convert a html list to xml format with a console application, but i did what i planned and now i dont know how to continue. I will share my code and explain a bit. What i dont know for now , and is confusing me is where the 'magic' happens. Ok i know i have to take that list from the page , read the list with all the tags inside, but what next, how can i transform that list into xml format? I am new to xml i know some basics so please help me.
Here is the application :
static void Main(string[] args)
{
string _url = "http://example.com/media";
int newsCounter = 0;
List<News> _newsList = new List<News>();
HtmlWeb web = new HtmlWeb();
HtmlDocument doc = web.Load(_url);
HtmlNode ulNode = doc.DocumentNode.SelectSingleNode("//ul[#class='content articles']");
HtmlNodeCollection liNode = ulNode.SelectNodes(".//li");
foreach (HtmlNode node in ulNode.SelectNodes(".//div[#class='article_box']"))
{
var news = new News();
news.Imgsrc = node.FirstChild.SelectSingleNode("//img").Attributes["src"].Value;
var nodes = doc.DocumentNode.FirstChild.SelectNodes("//img[#src]");
foreach (HtmlNode childNode in node.SelectNodes(".//div[#class='box_info']"))
{
// string src = node.SelectSingleNode("//img").Attributes["src"].Value;
foreach(HtmlNode _node in childNode.SelectNodes(".//h3"))
{
news.Link = "";
news.Title = _node.FirstChild.InnerText;
news.Date = _node.NextSibling.NextSibling.InnerText;
news.Text = _node.NextSibling.NextSibling.NextSibling.NextSibling.InnerText;
}
}
_newsList.Add(news);
newsCounter++;
}
and also the News class :
public class News
{
public string Imgsrc { get; set; }
public string Title { get; set; }
public string Link { get; set; }
public string Date { get; set; }
public string Text { get; set; }
}
these are all the parameters i have to read from the list.I am able to read them and return all of the news in my list , but what next , how to transform my list into xml format? Any suggestions are welcomed.
There are many way of creating xml. There are not a lot of items in your case so just using Xml linq is very simple. Putting it into a class may produce cleaner code or you can just use the code directly like Sledge suggested.
public class News
{
public string Imgsrc { get; set; }
public string Title { get; set; }
public string Link { get; set; }
public string Date { get; set; }
public string Text { get; set; }
public XElement ToXml()
{
return new XElement("news", new object[] {
new XElement("Imgscr", Imgsrc),
new XElement("Title", Title),
new XElement("Link", Link),
new XElement("Date", Date),
new XElement("Text", Text),
});
}
}
Thanks to everyone guys. I marked 'News' class as Serializable and with a few lines of code managed to generate the xml file. Here is the code, really simple :
XmlSerializer serializer = new XmlSerializer(typeof(List<News>));
using (TextWriter writer = new StreamWriter(#"D:\News.xml"))
{
serializer.Serialize(writer, _newsList);
}
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);
}
}