I would like to deserialize part of xml, I tried this, but it does not work.
class Program
{
static void Main(string[] args)
{
var serializer = new XmlSerializer(typeof(Test), new XmlRootAttribute("Test"));
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("<Root1><Root2><Test><Id>5</Id></Test></Root2></Root1>")))
{
var test = serializer.Deserialize(stream);
}
}
}
public class Test
{
public int Id;
}
How can I say to XmlSerializer to start serialization from <Test>?
Move to desired node with XmlReader.
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes("<Root1><Root2><Test><Id>5</Id></Test></Root2></Root1>")))
using (var reader = XmlReader.Create(stream))
{
reader.ReadToFollowing("Test");
var test = (Test)serializer.Deserialize(reader);
}
Related
When using XML serialization in C#, I use code like this:
public MyObject LoadData()
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(MyObject));
using (TextReader reader = new StreamReader(settingsFileName))
{
return (MyObject)xmlSerializer.Deserialize(reader);
}
}
(and similar code for deserialization).
It requires casting and is not really nice. Is there a way, directly in .NET Framework, to use generics with serialization? That is to say to write something like:
public MyObject LoadData()
{
// Generics here.
XmlSerializer<MyObject> xmlSerializer = new XmlSerializer();
using (TextReader reader = new StreamReader(settingsFileName))
{
// No casts nevermore.
return xmlSerializer.Deserialize(reader);
}
}
An addition to #Oded, you can make the method Generic aswell:
public T ConvertXml<T>(string xml)
{
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(new StringReader(xml));
}
This way you don't need to make the whole class generic and you can use it like this:
var result = ConvertXml<MyObject>(source);
Make your serialization class/method generic:
public T LoadData<T>()
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (TextReader reader = new StreamReader(settingsFileName))
{
return (T)xmlSerializer.Deserialize(reader);
}
}
A simple generic wrapper:
public class GenericSerializer<T> : XmlSerializer
{
public GenericSerializer(): base(typeof(T)) { }
}
This will serialize your object to the bin/debug folder:
static void Main(string[] args)
{
Person p = new Person { Name = "HelloWorld" };
GenericSerializer<Person> ser = new GenericSerializer<Person>();
ser.Serialize(new StreamWriter("person.xml"), p);
}
Try this.
public class SerializeConfig<T> where T : class
{
public static void Serialize(string path, T type)
{
var serializer = new XmlSerializer(type.GetType());
using (var writer = new FileStream(path, FileMode.Create))
{
serializer.Serialize(writer, type);
}
}
public static T DeSerialize(string path)
{
T type;
var serializer = new XmlSerializer(typeof(T));
using (var reader = XmlReader.Create(path))
{
type = serializer.Deserialize(reader) as T;
}
return type;
}
}
always work's for me
public static string ObjectToXmlSerialize<T>(T dataToSerialize)
{
try
{
var stringwriter = new System.IO.StringWriter();
var serializer = new XmlSerializer(typeof(T));
serializer.Serialize(stringwriter, dataToSerialize);
return stringwriter.ToString();
}
catch (Exception ex)
{
}
return null;
}
and this is for Deserialize:
public static T XmlDeserializeToObject<T>(string xmlText)
{
try
{
var stringReader = new System.IO.StringReader(xmlText);
var serializer = new XmlSerializer(typeof(T));
return (T)serializer.Deserialize(stringReader);
}
catch (Exception ex)
{
}
return default(T);
}
I'm trying to deserialize a bunch of data that was serialized by an old version of the code. When the data was serialized the classes had a different structure from the current class structure. To keep this data working in my new code, I hade to add the old classes structure to the code just for import this serialized data. I'm calling this classes as 'class'_oldVersions. To deserialize, I'm using this code:
className_oldVersions temp_className = new className_oldVersions();
XmlSerializer testSerializer = new XmlSerializer(typeof(className_oldVersions),
new XmlRootAttribute { ElementName = "className" });
temp_className = (ObservedData_OldVersions)testSerializer.Deserialize(ms_MemoryStream);
This code works fine, and I can deserialize the data using a diffent class name from the original. My problem is when I try to use this same procedure to deserialize an observable collection.
I created a code that reproduce my problem. In this code I serialize an observable collection of class OptimizationVariables and I would like to deserialize to an observable collection of class OptimizationVariablies_NewClass that has similar structure from the original one.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Xml.Serialization;
using System.Collections.ObjectModel;
public class OptimizationVariables
{
public string VariableName { get; set; }
}
public class OptimizationVariables_NewClass
{
public string VariableName { get; set; }
}
public class ModelsCollection
{
private ModelsCollection()
{
}
private ObservableCollection<OptimizationVariables> m_optimizationVariables =
new ObservableCollection<OptimizationVariables>();
public ObservableCollection<OptimizationVariables> OptimizationVariables
{
get { return m_optimizationVariables; }
set { m_optimizationVariables = value; }
}
private ObservableCollection<OptimizationVariables_NewClass> m_optimizationVariables_NewClass =
new ObservableCollection<OptimizationVariables_NewClass>();
public ObservableCollection<OptimizationVariables_NewClass> OptimizationVariables_NewClass
{
get { return m_optimizationVariables_NewClass; }
set { m_optimizationVariables_NewClass = value; }
}
}
class Program
{
static void Main(string[] args)
{
//Here I serialize an ObservableCollection of 2 OptimizationVariables instances
Serialize();
//Here I deserialize for the same class and works fine
Deserialize();
//Here I try to deserialize to a new class with same structure, but different name. I a have an error.
Deserialize2NewClass();
}
static void Serialize()
{
MemoryStream ms;
ObservableCollection<OptimizationVariables> OptimizationVariables2Serialize = new ObservableCollection<OptimizationVariables>();
OptimizationVariables opt_var1 = new OptimizationVariables();
opt_var1.VariableName = "Variable Name 1";
OptimizationVariables2Serialize.Add(opt_var1);
OptimizationVariables opt_var2 = new OptimizationVariables();
opt_var1.VariableName = "Variable Name 2";
OptimizationVariables2Serialize.Add(opt_var1);
ms = new MemoryStream();
XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables>));
serializer.Serialize(ms, OptimizationVariables2Serialize);
TextWriter sw = new StreamWriter("XML_File_x64.bin");
sw.WriteLine(Convert.ToBase64String(ms.ToArray()));
sw.Close();
}
static void Deserialize()
{
byte[] memoryData;
MemoryStream ms;
TextReader sw = new StreamReader("XML_File_x64.bin");
memoryData = Convert.FromBase64String(sw.ReadLine());
ms = new MemoryStream(memoryData);
ObservableCollection<OptimizationVariables> OptimizationVariablesDeserialized = new ObservableCollection<OptimizationVariables>();
XmlSerializer deserializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables>));
OptimizationVariablesDeserialized = (ObservableCollection<OptimizationVariables>)deserializer.Deserialize(ms);
Console.Write(OptimizationVariablesDeserialized.Count());
sw.Close();
}
static void Deserialize2NewClass()
{
byte[] memoryData;
MemoryStream ms;
TextReader sw = new StreamReader("XML_File_x64.bin");
memoryData = Convert.FromBase64String(sw.ReadLine());
ms = new MemoryStream(memoryData);
ObservableCollection<OptimizationVariables_NewClass> OptimizationVariablesDeserialized = new ObservableCollection<OptimizationVariables_NewClass>();
XmlSerializer deserializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables_NewClass>));
OptimizationVariablesDeserialized = (ObservableCollection<OptimizationVariables_NewClass>)deserializer.Deserialize(ms);
Console.Write(OptimizationVariablesDeserialized.Count());
sw.Close();
}
}
The problem in your code is that the class OptimizationVariables name is saved in the xml data when serializing. but for deserialization it expects a OptimizationVariables_NewClass name which is not within the xml file.
consider the fact that not only the variable names, but also the class names will be used when serializing a class or struct...
So, just changed your code to make it save the data in readable xml file, then replacing "OptimizationVariables" with "OptimizationVariables_NewClass" solved the error:
using System;
using System.Linq;
using System.IO;
using System.Xml.Serialization;
using System.Collections.ObjectModel;
public class OptimizationVariables
{
public string VariableName { get; set; }
}
public class OptimizationVariables_NewClass
{
public string VariableName { get; set; }
}
public class ModelsCollection
{
private ModelsCollection()
{
}
private ObservableCollection<OptimizationVariables> m_optimizationVariables =
new ObservableCollection<OptimizationVariables>();
public ObservableCollection<OptimizationVariables> OptimizationVariables
{
get { return m_optimizationVariables; }
set { m_optimizationVariables = value; }
}
private ObservableCollection<OptimizationVariables_NewClass> m_optimizationVariables_NewClass =
new ObservableCollection<OptimizationVariables_NewClass>();
public ObservableCollection<OptimizationVariables_NewClass> OptimizationVariables_NewClass
{
get { return m_optimizationVariables_NewClass; }
set { m_optimizationVariables_NewClass = value; }
}
}
class Program
{
static void Main(string[] args)
{
Serialize();
Deserialize();
Deserialize2NewClass();
}
static void Serialize()
{
ObservableCollection<OptimizationVariables> OptimizationVariables2Serialize = new ObservableCollection<OptimizationVariables>();
OptimizationVariables opt_var1 = new OptimizationVariables();
opt_var1.VariableName = "Variable Name 1";
OptimizationVariables2Serialize.Add(opt_var1);
OptimizationVariables opt_var2 = new OptimizationVariables();
opt_var1.VariableName = "Variable Name 2";
OptimizationVariables2Serialize.Add(opt_var1);
TextWriter writer = new StreamWriter("XML_File.xml");
XmlSerializer serializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables>));
serializer.Serialize(writer, OptimizationVariables2Serialize);
writer.Close();
}
static void Deserialize()
{
TextReader sw = new StreamReader("XML_File.xml");
ObservableCollection<OptimizationVariables> OptimizationVariablesDeserialized = new ObservableCollection<OptimizationVariables>();
XmlSerializer deserializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables>));
OptimizationVariablesDeserialized = (ObservableCollection<OptimizationVariables>)deserializer.Deserialize(sw);
Console.Write(OptimizationVariablesDeserialized.Count());
sw.Close();
}
static void Deserialize2NewClass()
{
TextReader sw = new StreamReader("XML_File.xml");
var str = sw.ReadToEnd();
sw.Close();
str = str.Replace("OptimizationVariables", "OptimizationVariables_NewClass");
var stream = new StringReader(str);
ObservableCollection<OptimizationVariables_NewClass> OptimizationVariablesDeserialized = new ObservableCollection<OptimizationVariables_NewClass>();
XmlSerializer deserializer = new XmlSerializer(typeof(ObservableCollection<OptimizationVariables_NewClass>));
OptimizationVariablesDeserialized = (ObservableCollection<OptimizationVariables_NewClass>)deserializer.Deserialize(stream);
Console.Write(OptimizationVariablesDeserialized.Count());
}
}
now it works fine!
How do I serialize an XML-serializable object to an XML fragment (no XML declaration nor namespace references in the root element)?
Here is a hack-ish way to do it without having to load the entire output string into an XmlDocument:
using System;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
public class Example
{
public String Name { get; set; }
static void Main()
{
Example example = new Example { Name = "Foo" };
XmlSerializer serializer = new XmlSerializer(typeof(Example));
XmlSerializerNamespaces emptyNamespace = new XmlSerializerNamespaces();
emptyNamespace.Add(String.Empty, String.Empty);
StringBuilder output = new StringBuilder();
XmlWriter writer = XmlWriter.Create(output,
new XmlWriterSettings { OmitXmlDeclaration = true });
serializer.Serialize(writer, example, emptyNamespace);
Console.WriteLine(output.ToString());
}
}
You should be able to just serialize like you usually do, and then use the Root property from the resulting document.
You may need to clear the attributes of the element first.
By the way this is awesome.
I implemented this code to make it easy to work with xml fragments as classes quickly and then you can just replace the node when finished. This makes the transition between code and xml ultra-easy.
First create some extension methods.
public static class SerializableFragmentExtensions
{
public static XElement ToElement(this ISerializableFragment iSerializableFragment)
{
var serializer = new XmlSerializer(iSerializableFragment.GetType());
var emptyNamespace = new XmlSerializerNamespaces();
emptyNamespace.Add(String.Empty, String.Empty);
var output = new StringBuilder();
var writer = XmlWriter.Create(output,
new XmlWriterSettings { OmitXmlDeclaration = true });
serializer.Serialize(writer, iSerializableFragment, emptyNamespace);
return XElement.Parse(output.ToString(), LoadOptions.None);
}
public static T ToObject<T>(this XElement xElement)
{
var serializer = new XmlSerializer(typeof (T));
var reader = xElement.CreateReader();
var obj = (T) serializer.Deserialize(reader);
return obj;
}
}
Next Implement the required interface (marker interface--I know you are not supposed to but I think this is the perfect reason to it.)
public interface ISerializableFragment
{
}
Now all you have to do is decorate any Serializable class, you want to convert to an XElement Fragment, with the interface.
[Serializable]
public class SomeSerializableClass : ISerializableFragment
{
[XmlAttribute]
public string SomeData { get; set; }
}
Finally test the code.
static void Main(string[] args)
{
var someSerializableClassObj = new SomeSerializableClass() {SomeData = "Testing"};
var element = someSerializableClass.ToElement();
var backToSomeSerializableClassObj = element.ToObject<SomeSerializableClass>();
}
Thanks again for this amazingly useful code.
I can serialize a list really easy:
List<String> fieldsToNotCopy =new List<String> {"Iteration Path","Iteration ID"};
fieldsToNotCopy.SerializeObject("FieldsToNotMove.xml");
Now I need a method like this:
List<String> loadedList = new List<String();
loadedList.DeserializeObject("FieldsToNotMove.xml");
Is there such a method? Or am I going to need to create an XML reader and load it in that way?
EDIT: Turns out there is no built in SerialzeObject. I had made one earlier in my project and forgot about it. When I found it I thought it was built in. In case you are curious this is the SerializeObject that I made:
// Save an object out to the disk
public static void SerializeObject<T>(this T toSerialize, String filename)
{
XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
TextWriter textWriter = new StreamWriter(filename);
xmlSerializer.Serialize(textWriter, toSerialize);
textWriter.Close();
}
There is no such builtin method as SerializeObject but it's not terribly difficult to code one up.
public void SerializeObject(this List<string> list, string fileName) {
var serializer = new XmlSerializer(typeof(List<string>));
using ( var stream = File.OpenWrite(fileName)) {
serializer.Serialize(stream, list);
}
}
And Deserialize
public void Deserialize(this List<string> list, string fileName) {
var serializer = new XmlSerializer(typeof(List<string>));
using ( var stream = File.OpenRead(fileName) ){
var other = (List<string>)(serializer.Deserialize(stream));
list.Clear();
list.AddRange(other);
}
}
These are my serialize/deserialize extension methods that work quite well
public static class SerializationExtensions
{
public static XElement Serialize(this object source)
{
try
{
var serializer = XmlSerializerFactory.GetSerializerFor(source.GetType());
var xdoc = new XDocument();
using (var writer = xdoc.CreateWriter())
{
serializer.Serialize(writer, source, new XmlSerializerNamespaces(new[] { new XmlQualifiedName("", "") }));
}
return (xdoc.Document != null) ? xdoc.Document.Root : new XElement("Error", "Document Missing");
}
catch (Exception x)
{
return new XElement("Error", x.ToString());
}
}
public static T Deserialize<T>(this XElement source) where T : class
{
try
{
var serializer = XmlSerializerFactory.GetSerializerFor(typeof(T));
return (T)serializer.Deserialize(source.CreateReader());
}
catch //(Exception x)
{
return null;
}
}
}
public static class XmlSerializerFactory
{
private static Dictionary<Type, XmlSerializer> serializers = new Dictionary<Type, XmlSerializer>();
public static XmlSerializer GetSerializerFor(Type typeOfT)
{
if (!serializers.ContainsKey(typeOfT))
{
System.Diagnostics.Debug.WriteLine(string.Format("XmlSerializerFactory.GetSerializerFor(typeof({0}));", typeOfT));
var newSerializer = new XmlSerializer(typeOfT);
serializers.Add(typeOfT, newSerializer);
}
return serializers[typeOfT];
}
}
You just need to define a type for your list and use it instead
public class StringList : List<String> { }
Oh, and you don't NEED the XmlSerializerFactory, it's just there since creating a serializer is slow, and if you use the same one over and over this speeds up your app.
I'm not sure whether this will help you but I have dome something which I believe to be similar to you.
//A list that holds my data
private List<Location> locationCollection = new List<Location>();
public bool Load()
{
//For debug purposes
Console.WriteLine("Loading Data");
XmlSerializer serializer = new XmlSerializer(typeof(List<Location>));
FileStream fs = new FileStream("CurrencyData.xml", FileMode.Open);
locationCollection = (List<Location>)serializer.Deserialize(fs);
fs.Close();
Console.WriteLine("Data Loaded");
return true;
}
This allows me to deserialise all my data back into a List<> but i'd advise putting it in a try - catch block for safety. In fact just looking at this now is going to make me rewrite this in a "using" block too.
I hope this helps.
EDIT:
Apologies, just noticed you're trying to do it a different way but i'll leave my answer there anyway.
I was getting error while deserializing to object. The error was "There is an error in XML document (0, 0)". I have modified the Deserialize function originally written by #JaredPar to resolve this error. It may be useful to someone:
public static void Deserialize(this List<string> list, string fileName)
{
XmlRootAttribute xmlRoot = new XmlRootAttribute();
xmlRoot.ElementName = "YourRootElementName";
xmlRoot.IsNullable = true;
var serializer = new XmlSerializer(typeof(List<string>), xmlRoot);
using (var stream = File.OpenRead(fileName))
{
var other = (List<string>)(serializer.Deserialize(stream));
list.Clear();
list.AddRange(other);
}
}
Create a list of products be serialized
List<string> Products = new List<string>
{
new string("Product 1"),
new string("Product 2"),
new string("Product 3"),
new string("Product 4")
};
Serialization
using (FileStream fs = new FileStream(#"C:\products.txt", FileMode.Create))
{
BinaryFormatter bf = new BinaryFormatter();
bf.Serialize(fs, Products);
}
Deserialization
using (FileStream fs = new FileStream(#"C:\products.txt", FileMode.Open))
{
BinaryFormatter bf = new BinaryFormatter();
var productList = (List<string>)bf.Deserialize(fs);
}
If I create a class in C#, how can I serialize/deserialize it to a file? Is this somethat that can be done using built in functionality or is it custom code?
XmlSerializer; note that the exact xml names can be controlled through various attributes, but all you really need is:
a public type
with a default constructor
and public read/write members (ideally properties)
Example:
using System;
using System.Xml;
using System.Xml.Serialization;
public class Person {
public string Name { get; set; }
}
static class Program {
static void Main() {
Person person = new Person { Name = "Fred"};
XmlSerializer ser = new XmlSerializer(typeof(Person));
// write
using (XmlWriter xw = XmlWriter.Create("file.xml")) {
ser.Serialize(xw, person);
}
// read
using (XmlReader xr = XmlReader.Create("file.xml")) {
Person clone = (Person) ser.Deserialize(xr);
Console.WriteLine(clone.Name);
}
}
}
You need to use class XmlSerializer. Main methods are Serialize and Deserialize. They accept streams, text readers\writers and other classes.
Code sample:
public class Program
{
public class MyClass
{
public string Name { get; set; }
}
static void Main(string[] args)
{
var myObj = new MyClass { Name = "My name" };
var fileName = "data.xml";
var serializer = new XmlSerializer(typeof(MyClass));
using (var output = new XmlTextWriter(fileName, Encoding.UTF8))
serializer.Serialize(output, myObj);
using (var input = new StreamReader(fileName))
{
var deserialized = (MyClass)serializer.Deserialize(input);
Console.WriteLine(deserialized.Name);
}
Console.WriteLine("Press ENTER to finish");
Console.ReadLine();
}
}