I am new to Xml and have written the code whcih creates an Xml and Reads it back also.
But i want to have some modifications in the Xml structure.
What i don't want is ArrayOfMovie tag, which is coming as the root tab.
But when i am writing multiple objects into the Xml it shows an ArrayOfMovie tag. As i have to maintain the structure of the class, the upper tag as Movie, then its details and then other movie. Also please if you tell the code to modify the xml, tell the procedure to read the newly structured xml too.
Here is the code for the scenario:
// Movies class which contains the list of Movie objects
public class Movies
{
public List<Movie> movieList = new List<Movie>();
}
//Movie class
public class Movie
{
public string Title
{ get; set; }
public int Rating
{ get; set; }
public DateTime ReleaseDate
{ get; set; }
}
private void CreateXml_Click(object sender, EventArgs e)
{
string filePath = path + textBox_XmlFileName.Text+".xml";
Movie firstMov = new Movie();
firstMov.Title = "Shrek";
firstMov.Rating = 2;
firstMov.ReleaseDate = DateTime.Now;
Movie secondMov = new Movie();
secondMov.Title = "Spider Man";
secondMov.Rating = 4;
secondMov.ReleaseDate = DateTime.Now;
Movies moviesObj = new Movies();
moviesObj.movieList.Add(firstMov);
moviesObj.movieList.Add(secondMov);
List<Movie> movList = new List<Movie>() { firstMov,secondMov};
XmlHandler.SerializeToXml(moviesObj.movieList, filePath);
}
// The static class and funcion that creates the xml file
public static void SerializeToXml(List<Movie> movies ,string filePath)
{
XmlSerializer xls= new XmlSerializer(typeof(List<Movie>));
TextWriter tw = new StreamWriter(filePath);
xls.Serialize(tw, movies);
tw.Close();
}
// It Creates the following output
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfMovie xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Movie>
<Title>Shrek</Title>
<Rating>2</Rating>
<ReleaseDate>2014-05-25T22:55:17.2811063+05:00</ReleaseDate>
</Movie>
<Movie>
<Title>Spider Man</Title>
<Rating>4</Rating>
<ReleaseDate>2014-05-25T22:55:17.2811063+05:00</ReleaseDate>
</Movie>
</ArrayOfMovie>
// The code for reading the file into objects
public static List<Movie> DeserializeFromXml(string filePath)
{
XmlSerializer deserializer = new XmlSerializer(typeof(List<Movie>));
TextReader tr = new StreamReader(#filePath);
List<Movie> movie;
movie = (List<Movie>)deserializer.Deserialize(tr);
tr.Close();
return movie;
}
you may use the XmlRootAttribute if you want to name your root
XmlSerializer deserializer = new XmlSerializer(typeof(List<Movie>),
new XmlRootAttribute("YourRoot"));
Related
I searched and tried some attributes but none of them worked for my below scenario:
public class ObjSer
{
[XmlElement("Name")]
public string Name
{
get; set;
}
}
//Code to serialize
var obj = new ObjSer();
obj.Name = "<tag1>Value</tag1>";
var stringwriter = new System.IO.StringWriter();
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
serializer.Serialize(stringwriter, obj);
Output would be as follows:
<ObjSer><Name><tag1>Value</tag1></Name></ObjSer>
But I need output as:
<ObjSer><Name><tag1>Value</tag1></Name></ObjSer>
Scenario 2: In some cases I need to set:
obj.Name = "Value";
Is there any attribute or method I can override to make it possible?
You can't with default serializer. XmlSerializer does encoding of all values during serialization.
If you want your member to hold xml value, it must be XmlElement. Here is how you can accomplish it
public class ObjSer
{
[XmlElement("Name")]
public XmlElement Name
{
get; set;
}
}
var obj = new ObjSer();
// <-- load xml
var doc = new XmlDocument();
doc.LoadXml("<tag1>Value</tag1>");
obj.Name = doc.DocumentElement;
// --> assign the element
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
serializer.Serialize(Console.Out, obj);
Output:
<?xml version="1.0" encoding="IBM437"?>
<ObjSer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>
<tag1>Value</tag1>
</Name>
</ObjSer>
UPDATE:
In case if you want to use XElement instead of XmlElement, here is sample on how to do it
public class ObjSer
{
[XmlElement("Name")]
public XElement Name
{
get; set;
}
}
static void Main(string[] args)
{
//Code to serialize
var obj = new ObjSer();
obj.Name = XDocument.Parse("<tag1>Value</tag1>").Document.FirstNode as XElement;
System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
serializer.Serialize(Console.Out, obj);
}
No, you can't. It is the natural and usual behaviour of the xml serializer. The serializer doesn't have to handle within the XML strings. So, it escapes the xml as expected.
You should decode the escaped string again while deserializing it.
If you want to add dynamically elements in the XML I suggest you to use Linq to XML and you can create tag1 or another kind of elements easily.
I would suggest serializing to an XDocument then converting that to a string and manually unescaping the desired part and writing it to a file. I would say this would give you the least headache it shouldn't be more than a couple lines of code. If you need it I can provide some code example if needed.
I found one more way of changing the type
public class NameNode
{
public string tag1
{
get; set;
}
[XmlText]
public string Value
{
get; set;
}
}
public class ObjSer
{
[XmlElement("Name")]
public NameNode Name
{
get; set;
}
}
To set value of Name:
var obj = new ObjSer();
var valueToSet = "<tag1>Value</tag1>";
//or var valueToSet = "Value";
//With XML tag:
if (valueToSet.Contains("</"))
{
var doc = new XmlDocument();
doc.LoadXml(valueToSet);
obj.Name.tag1 = doc.InnerText;
}
else //Without XML Tags
{
obj.Name.Value = senderRecipient.Name;
}
This solution will work in both cases, but has limitation. It will work only for predefined tags (ex. tag1)
Been looking around alot to find answers to my problem. I found a great way to convert my List to an xml file, but I also want to get it back to a list.
My current xml file looks like this:
<Commands>
<Command command="!command1" response="response1" author="niccon500" count="1237"/>
<Command command="!command2" response="response2" author="niccon500" count="1337"/>
<Command command="!command3" response="response3" author="niccon500" count="1437"/>
</Commands>
Generated with:
var xml = new XElement("Commands", commands.Select(x =>
new XElement("Command",
new XAttribute("command", x.command),
new XAttribute("response", x.response),
new XAttribute("author", x.author),
new XAttribute("count", x.count))));
File.WriteAllText(file_path, xml.ToString());
So, how would I get the info back from the xml file?
You can use the following piece of code:
XDocument doc = XDocument.Load(#"myfile.xml");
to load the XML file into an XDocument object.
Then you can use .Descendants("Commands").Elements() to access all elements contained inside the <Commands> element and add them to a list:
List<Command> lstCommands = new List<Command>();
foreach(XElement elm in doc.Descendants("Commands").Elements())
{
lstCommands.Add(new Command
{
command = elm.Attribute("command").Value,
response = elm.Attribute("response").Value,
author = elm.Attribute("author").Value,
count = int.Parse(elm.Attribute("count").Value)
});
}
When using xml for persistent storage, start with defining POC classes and decorate them with proper attributes - like
[XmlType("Command")]
public class CommandXml
{
[XmlAttribute("command")]
public string Command { get; set; }
[XmlAttribute("response")]
public string Response { get; set; }
[XmlAttribute("author")]
public string Author { get; set; }
[XmlAttribute("count")]
public int Count { get; set; }
}
[XmlRoot("Commands")]
public class CommandListXml : List<CommandXml>
{
}
And then de-serialization is simple as:
var txt = #"<Commands>
<Command command=""!command1"" response=""response1"" author=""niccon500"" count=""1237""/>
<Command command=""!command2"" response=""response2"" author=""niccon500"" count=""1337""/>
<Command command=""!command3"" response=""response3"" author=""niccon500"" count=""1437""/>
</Commands>";
CommandListXml commands;
using (var reader = new StringReader(txt))
{
var serializer = new XmlSerializer(typeof(CommandListXml));
commands = (CommandListXml)serializer.Deserialize(reader);
}
You can use XDocument.Load method to load the document and then create command list using LINQ to XML syntax :
XDocument doc = XDocument.Load(file_path);
var commands = doc.Root.Elements("Commands").Select(e =>
new Command()
{
command = e.Attribute("command").Value,
response = e.Attribute("response").Value,
author = e.Attribute("author").Value,
count= int.Parse(e.Attribute("count").Value)
}).ToList();
I need to deserialize the xml below. I want to use xmlserializer because I am (more) familiar with it.
I believe this xml is not constructed correctly however I cannot change it.
The below represents a list of category objects. When I try to deserialize using
xmlserializer(typeof(List<Category>))
I get this error: "categories xmlns='' is not expected"
<?xml version="1.0" encoding="utf-8" ?>
<categories>
<category id="16" name="Exports" parent_id="13"/>
<category id="17" name="Imports" parent_id="13"/>
<category id="3000" name="Income Payments & Receipts" parent_id="13"/>
<category id="125" name="Trade Balance" parent_id="13"/>
<category id="127" name="U.S. International Finance" parent_id="13"/>
</categories>
I don't mind making some kind of dummy class to deserilize these if that is what I have to do.
Here is my Category Class
[XmlType("category")]
public class Category
{
[XmlAttribute("id")]
public int ID { get; set; }
[XmlAttribute("parent_id")]
public int ParentID { get; set; }
[XmlAttribute("name")]
public string Name { get; set; }
}
My code:
XmlSerializer serializer = new XmlSerializer(typeof(List<Category>));
StringReader reader = new StringReader(xml);
List<Category> obj = null;
using (System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(reader))
{
obj = (List<Category>)serializer.Deserialize(xmlReader);
}
return obj;
You can just pass in the XmlRootAttribute into the serializer for the "categories" part.
BUT... you must remove the "&" from your xml because its not valid
XmlSerializer serializer = new XmlSerializer(typeof(List<Category>), new XmlRootAttribute("categories"));
using (FileStream fileStream = new FileStream(#"C:\Test.xml", FileMode.Open, FileAccess.Read, FileShare.Read))
{
var test = serializer.Deserialize(fileStream);
}
Here is your method working with a String.Replace to sort out the "&"
private List<Category> GetCategories(string xmlData)
{
List<Category> obj = null;
XmlSerializer serializer = new XmlSerializer(typeof(List<Category>), new XmlRootAttribute("categories"));
StringReader reader = new StringReader(xmlData.Replace("&","&"));
using (System.Xml.XmlReader xmlReader = System.Xml.XmlReader.Create(reader))
{
obj = (List<Category>)serializer.Deserialize(xmlReader);
}
return obj;
}
Try to make a categories class that will contain your List<Category> like this:
[XmlRoot("categories")]
public class Categories
{
public Categories()
{
Items = new List<User>();
}
[XmlElement("category")]
public List<Category> Items {get;set;}
}
You can than create a serializer like this:
XmlSerializer serializer = new XmlSerializer(typeof(Categories));
Do you have an XSD that this XML should conform to? If so, you can generate the required code using:
"xsd your.xsd /classes"
My problem is, my program isn't taking data from my XML file and putting it into a list
I can save data just fine but I can't load it back.
Here is my Save function
public void Save_Data_Click(object sender, EventArgs e)
{
XmlSerializer PSR = new XmlSerializer(typeof(Pickup));
XmlSerializer DSR = new XmlSerializer(typeof(Delivery));
TextWriter PickupStream = new StreamWriter(#"Pickup Save Data.xml");
TextWriter DeliveryStream = new StreamWriter(#"Delivery Save Data.xml");
PSR.Serialize(PickupStream, thePickup);
DSR.Serialize(DeliveryStream, theDelivery);
DeliveryStream.Close();
PickupStream.Close();
MessageBox.Show("All data saved!");
}
Here is my xml load code
XmlSerializer SerializerObj = new XmlSerializer(typeof(Pickup));
FileStream ReadFileStream = new FileStream(#"Pickup Save Data.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
Pickup LoadedObj = (Pickup)SerializerObj.Deserialize(ReadFileStream);
ReadFileStream.Close();
Here is my Pickup Class
namespace Vans
{
[Serializable]
public class Pickup
{
public List<Pickups> Pickups = new List<Pickups>();
public void addPickup(Pickups Pic)
{
Pickups.Add(Pic);
}
public List<String> listPickups()
{
List<String> listPickups = new List<string>();
foreach (Pickups pick in Pickups)
{
String pickupString = pick.ToString();
listPickups.Add(pickupString);
}
return listPickups;
}
public Pickups getPickup(int i)
{
int c = 0;
foreach (Pickups Pic in Pickups)
{
if (i == c)
return Pic;
c++;
}
return null;
}
}
}
My Delivery class is the same as the Pickup class.
Edit
<?xml version="1.0" encoding="utf-8"?>
<Pickup xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Pickups>
<Pickups>
<pickupfirstname>dsf</pickupfirstname>
<pickuplastname>sdf</pickuplastname>
<pickupdeliveryaddress>sd</pickupdeliveryaddress>
<pickuptime>dsf</pickuptime>
</Pickups>
</Pickups>
</Pickup>
this is some sample XML code
In this example, every field, that should be (de-)serialized, has an annotation [XmlElement], maybe thats the reason...
Make sure your Pickups class is as follows to deserialize it correctly:
public class Pickups
{
public string pickupfirstname;
public string pickuplastname;
public string pickupdeliveryaddress;
public string pickuptime;
}
Note: I have tested your code locally with the inclusion of this class and it is working perfectly fine.
Does anyone know how I (or if it's possible to) reverse the XML I'm creating below
[Serializable()]
public class CustomDictionary
{
public string Key { get; set; }
public string Value { get; set; }
}
public class OtherClass
{
protected void BtnSaveClick(object sender, EventArgs e)
{
var analysisList = new List<CustomDictionary>();
// Here i fill the analysisList with some data
// ...
// This renders the xml posted below
string myXML = Serialize(analysisList).ToString();
xmlLiteral.Text = myXML;
}
public static StringWriter Serialize(object o)
{
var xs = new XmlSerializer(o.GetType());
var xml = new StringWriter();
xs.Serialize(xml, o);
return xml;
}
}
The xml rendered
<?xml version="1.0" encoding="utf-16"?>
<ArrayOfCustomDictionary xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<CustomDictionary>
<Key>Gender</Key>
<Value>0</Value>
</CustomDictionary>
<CustomDictionary>
<Key>Height</Key>
<Value>4</Value>
</CustomDictionary>
<CustomDictionary>
<Key>Age</Key>
<Value>2</Value>
</CustomDictionary>
</ArrayOfCustomDictionary>
Now, after a few hours of Googling and trying I'm stuck (most likely my brain have some vacation already). Can anyone help me how to reverse this xml back to a List?
Thanks
Just deserialize it:
public static T Deserialize<T>(string xml) {
var xs = new XmlSerializer(typeof(T));
return (T)xs.Deserialize(new StringReader(xml));
}
Use it like this:
var deserializedDictionaries = Deserialize<List<CustomDictionary>>(myXML);
XmlSerializer.Deserialize