In a nutshell:
I have a list with items named Categories. For each of those items in the list Categories I have a xml file:
System.IO.File.Create(Categories[listPicker.SelectedIndex] + ".xml");
The created item is serialized into a xml file with the name of the selected index.
The problem:
The problem is that for each item in categories an xml file needs to be deserialized to a list, because each object of categories must be another list because it also contains items.
But there does not exist a list for deserialization of the xml file:
Deserialization:
Serialize.Deserialize(Variable list name , Categories[1]+".xml");
So how do i dynamically create lists or can you provide a better solution to this problem?
Even if each list has a different name, the structure of the content is the same. Text/Description and Value.
I would create a class for the Item. Something like
public class ComboItem{
public string Value {get; set;}
public string Text {get; set;}
}
Then I would create another class for the List of ComboItem that each XML File would have
public class ComboItemList
{
public ComboItemList()
{
ComboItems = new List<ComboItem>();
}
[XmlArray("ComboItems"), XmlArrayItem("ComboItem")]
public List<ComboItem> ComboItems { get; set; }
}
I have a Serialize/Deserialize Helper. Something like
#region static T DeserializeObject( string xml, Encoding encoding )
/// <summary>
/// Deserialize an Xml String to an [object]
/// </summary>
/// <typeparam name="T">Object Type to Deserialize</typeparam>
/// <param name="xml">Xml String to Deserialize</param>
/// <param name="encoding">System.Text.Encoding Type</param>
/// <returns>Default if Exception, Deserialize object if successful</returns>
/// <example>
/// // UTF-16 Deserialize
/// [object] = SerializationHelper<ObjectType>DeserializeObject( xml, Encoding.Unicode )
/// </example>
/// <example>
/// // UTF-8 Deserialize
/// [object] = SerializationHelper<ObjectType>DeserializeObject( xml, Encoding.UTF8 )
/// </example>
public static T DeserializeObject(string xml, Encoding encoding)
{
if (string.IsNullOrEmpty(xml)) { return default(T); }
try
{
XmlSerializer xmlSerializer = new XmlSerializer(typeof(T));
using (MemoryStream memoryStream = new MemoryStream(encoding.GetBytes(xml)))
{
// No settings need modifying here
XmlReaderSettings xmlReaderSettings = new XmlReaderSettings();
using (XmlReader xmlReader = XmlReader.Create(memoryStream, xmlReaderSettings))
{
return (T)xmlSerializer.Deserialize(xmlReader);
}
}
}
catch
{
return default(T);
}
}
#endregion
/// <summary>
/// Deserialize an Xml String to an [object] with UTF8 as Encoding
/// </summary>
/// <param name="xml">Xml String to Deserialize</param>
/// <returns>Default if Exception, Deserialize object if successful</returns>
/// <example>
/// [object] = SerializationHelper<ObjectType>DeserializeObject( xml )
/// </example>
public static T DeserializeObjectFromFile(string filePath)
{
if (!File.Exists(filePath))
{
throw new FileNotFoundException(string.Format("The file {0}, don't exist.", filePath));
}
StreamReader sr = File.OpenText(filePath);
string xml = sr.ReadToEnd();
return DeserializeObject(xml, Encoding.UTF8);
}
that I would call like this
string filePath01 = "PATH TO FILE 01";
List<ComboItem> List01 = SerializationHelper<ComboItem>.DeserializeObjectFromFile(filePath01);
string filePath02 = "PATH TO FILE 02";
List<ComboItem> List02 = SerializationHelper<ComboItem>.DeserializeObjectFromFile(filePath02);
List01 and List02 would have the contents of File01 and File02. Repeat for every file you have.
With a better architecture, you could make some properties in base class, that could be singleton, and would only load each file, only once, increasing the performance.
Related
I am having real trouble trying to deserialize some XML and was hoping someone can offer some assistance. I have read a lot of similar posts but I am unable to resolve this.
XML I am attempting to deserialize
<register-account success="false">
<user-name>xxxxx</user-name>
<password>fghgh</password>
<email>test#example.com</email>
<error>
<errorcode>120</errorcode>
<errormessage>The password is invalid</errormessage>
</error>
</register-account>
Class I am trying to deserialize to:
[Serializable, XmlRoot(ElementName = "register-account", Namespace = "MyNamespace")]
[XmlType("register-account")]
public class RegisterAccountResponse
{
[XmlAttribute("success")]
public bool Success { get; set; }
/// <summary>
/// Gets or sets the Tennant email address
/// </summary>
[XmlElement("email")]
public string Email { get; set; }
/// <summary>
/// Gets or sets the tennant password
/// </summary>
[XmlElement("password")]
public string Password { get; set; }
/// <summary>
/// Gets or sets the Tennant username
/// </summary>
[XmlElement("user-name")]
public string Username { get; set; }
/// <summary>
/// A Tenant Portal error relating to the RegisterAccountRequest
/// </summary>
[XmlElement("error")]
public QubeError Error;
}
Deserialization Method
public static T Deserialize<T>(string data) where T : class
{
if (data == null)
{
return null;
}
if (data.Trim().Length == 0)
{
return null;
}
var ser = new XmlSerializer(typeof(T));
using (var sr = new StringReader(data))
{
return (T)ser.Deserialize(sr);
}
}
Deserialization Method Call
var data = Helper.Deserialize<RegisterAccountResponse>(xml);
Exception:
There is an error in XML document (1,
2). --->
System.InvalidOperationException: was
not expected. at
Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderData.Read5_data()
Inner Exception as follows:
<register-account xmlns=''> was not expected.
Simply take off the Namespace =:
[XmlRoot("register-account"), XmlType("register-account")]
public class RegisterAccountResponse {...}
since your xml doesn't seem to be in an xml-namespace. Also, [Serializable] isn't used by XmlSerializer.
If your xml was using a namespace it would have an xmlns at the root.
Also, to help with callers you could add where T : class, new() (the , new() being the addition) to your Deserialize method, since XmlSerializer demands a public parameterless constructor.
Nothing worked here for me
What worked is to MAKE SURE that the C# Class (main class) you are trying to map/deserialize the xml string to HAS AN XmlRootAttribute that matches the root element of the response.
Check my full answer with an exmaple https://stackoverflow.com/a/61525536/1594274
I found doing the following fixed this for me
if (elem.Attribute(XNamespace.Xmlns + "xsi") == null) {
elem.Add(new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"));
}
if (elem.Attribute(XNamespace.Xmlns + "xsd") == null) {
elem.Add(new XAttribute(XNamespace.Xmlns + "xsd", "http://www.w3.org/2001/XMLSchema"));
}
When serializing my object with Newtonsoft's Json.net I get:
{"status":"1",
"message":"test",
"records":"[{\"id\":\"1\", \"name\":\"file1\"},
{\"id\":\"2\", \"name\":\"file2\"},
{\"id\":\"3\", \"name\":\"file3\"}]" // I want to get rid of the extra quotes for the array
}
I want to have:
{"status":"1",
"message":"test",
"records":[{"id":"1", "name":"file1"},
{"id":"2", "name":"file2"},
{"id":"3", "name":"file3"}] // NOTE: this is an Array of records
}
This is the simplified code I use to serialize:
QHttpResponse tempResponse = new QHttpResponse() { StatusCode = (int)HttpStatusCode.OK, Message = "File found." };
JObject jo = JObject.FromObject(tempResponse);
jo.Add("records",JsonConvert.SerializeObject(jo));
This is the QHttpResponse class:
public class QHttpResponse
{
#region Feilds
/// <summary>
/// Status code of the http response (e.g.:400 = bad request.)
/// </summary>
[JsonProperty("status_code")]
public int StatusCode { get; set; }
/// <summary>
/// Message (Content) of the response.
/// </summary>
[JsonProperty("message")]
public string Message { get; set; }
#endregion
}
Your problem is here:
jo.Add("records",JsonConvert.SerializeObject(jo));
You serialize the array adding it to the "records" property, then you serialized the whole thing thus you get a double serialization, which is why you have the escaped \".
try:
jo["records"] = arrayData;
Then later when you serialize this should come out as you expect.
Im new to stackoverflow but thought I should give its a try...
So what I'm trying to do is to save variables in a file which other programs can access... For example, I have a set-up application that takes care of all the setup data (ex. database information, strings, numbers, or booleans). What I thought was to save them to a file like Properties file or text file where another program could read them and modify that settings file. Could anyone please point me off in a proper direction?
Thanks
waco001
If you are working with C#, I would suggesting putting all your settings in a separate class and then use XmlSerialization to save it, that way you'll have functionality working with minimal amount of code, and you'll have your data saved in format easy to read by other applications.
There are multiple samples available how to do it, for example:
http://www.jonasjohn.de/snippets/csharp/xmlserializer-example.htm
Try to use App.config supported in visual studio project.
Create a settings class and serialize/deserialize it, also if you encapsulate your configuration in a different object this have the added benefit of managing it using a property gird, I usually do this with my configuration files, this is a little example:
using System;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace Generate.Test
{
/// <summary>
/// The configuration class.
/// </summary>
[Serializable, XmlRoot("generate-configuration")]
public class Configuration : ISerializable
{
#region Fields
private string inputPath = string.Empty;
private string outputPath = string.Empty;
private int maxCount = 0;
#endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="Configuration" /> class.
/// </summary>
public Configuration()
{
}
#endregion
#region Properties
/// <summary>
/// Gets or sets the output path.
/// </summary>
/// <value>
/// The output path.
/// </value>
[XmlElement("output-path")]
public string OutputPath
{
get { return this.outputPath; }
set { this.outputPath = value; }
}
/// <summary>
/// Gets or sets the input path.
/// </summary>
/// <value>
/// The input path.
/// </value>
[XmlElement("input-path")]
public string InputPath
{
get { return this.inputPath; }
set { this.inputPath = value; }
}
/// <summary>
/// Gets or sets the max count.
/// </summary>
/// <value>
/// The max count.
/// </value>
[XmlElement("max-count")]
public int MaxCount
{
get { return this.maxCount; }
set { this.maxCount = value; }
}
#endregion
#region ISerializable Members
/// <summary>
/// Gets the object data.
/// </summary>
/// <param name="info">The info.</param>
/// <param name="context">The context.</param>
/// <exception cref="System.ArgumentNullException">thrown when the info parameter is empty.</exception>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
if (info == null)
throw new System.ArgumentNullException("info");
info.AddValue("output-path", this.OutputPath);
info.AddValue("input-path", this.InputPath);
info.AddValue("max-count", this.MaxCount);
}
#endregion
}
}
So to deserialize (_configurationPath is the path of the xml where the config is stored):
if (File.Exists(_configurationPath))
{
try
{
XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
Stream stream = new FileStream(_configurationPath, FileMode.Open, FileAccess.Read);
Configuration config = (Configuration)serializer.Deserialize(stream);
_inputPath = config.InputPath;
_outputPath = config.OutputPath;
_maxCount = config.MaxCount;
}
catch (Exception exception)
{
Console.WriteLine("Error cargando el archivo de configuraciĆ³n '{0}':\n{1}", _configurationPath, exception);
}
}
And to serialize:
Configuration configuration = new Configuration(); // Create the object
// Set the values
configuration.InputPath = #".\input";
configuration.OutputPath = #".\output";
configuration.MaxCount = 1000;
// Serialize
XmlSerializer serializer = new XmlSerializer(typeof(Configuration));
Stream stream = new FileStream(_configurationPath, FileMode.Open, FileAccess.Write);
serializer.Serialize(stream, configuration);
Hope it helps.
The typical method would be to create an XmlDocument, fill it with aptly named nodes and attributes and write it out via Save(). This has the advantage, that most other environments are able to read XML and parse it.
Another "lingua franca" is JSON, which can easily be written via JSON.NET and is "understood" by most other environments.
If all you want is share data between applications, you should look into WCF.
Or you can use existing .NET API for XML to both create and parse data. Then use system IO to store it into hard drive.
I am having real trouble trying to deserialize some XML and was hoping someone can offer some assistance. I have read a lot of similar posts but I am unable to resolve this.
XML I am attempting to deserialize
<register-account success="false">
<user-name>xxxxx</user-name>
<password>fghgh</password>
<email>test#example.com</email>
<error>
<errorcode>120</errorcode>
<errormessage>The password is invalid</errormessage>
</error>
</register-account>
Class I am trying to deserialize to:
[Serializable, XmlRoot(ElementName = "register-account", Namespace = "MyNamespace")]
[XmlType("register-account")]
public class RegisterAccountResponse
{
[XmlAttribute("success")]
public bool Success { get; set; }
/// <summary>
/// Gets or sets the Tennant email address
/// </summary>
[XmlElement("email")]
public string Email { get; set; }
/// <summary>
/// Gets or sets the tennant password
/// </summary>
[XmlElement("password")]
public string Password { get; set; }
/// <summary>
/// Gets or sets the Tennant username
/// </summary>
[XmlElement("user-name")]
public string Username { get; set; }
/// <summary>
/// A Tenant Portal error relating to the RegisterAccountRequest
/// </summary>
[XmlElement("error")]
public QubeError Error;
}
Deserialization Method
public static T Deserialize<T>(string data) where T : class
{
if (data == null)
{
return null;
}
if (data.Trim().Length == 0)
{
return null;
}
var ser = new XmlSerializer(typeof(T));
using (var sr = new StringReader(data))
{
return (T)ser.Deserialize(sr);
}
}
Deserialization Method Call
var data = Helper.Deserialize<RegisterAccountResponse>(xml);
Exception:
There is an error in XML document (1,
2). --->
System.InvalidOperationException: was
not expected. at
Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderData.Read5_data()
Inner Exception as follows:
<register-account xmlns=''> was not expected.
Simply take off the Namespace =:
[XmlRoot("register-account"), XmlType("register-account")]
public class RegisterAccountResponse {...}
since your xml doesn't seem to be in an xml-namespace. Also, [Serializable] isn't used by XmlSerializer.
If your xml was using a namespace it would have an xmlns at the root.
Also, to help with callers you could add where T : class, new() (the , new() being the addition) to your Deserialize method, since XmlSerializer demands a public parameterless constructor.
Nothing worked here for me
What worked is to MAKE SURE that the C# Class (main class) you are trying to map/deserialize the xml string to HAS AN XmlRootAttribute that matches the root element of the response.
Check my full answer with an exmaple https://stackoverflow.com/a/61525536/1594274
I found doing the following fixed this for me
if (elem.Attribute(XNamespace.Xmlns + "xsi") == null) {
elem.Add(new XAttribute(XNamespace.Xmlns + "xsi", "http://www.w3.org/2001/XMLSchema-instance"));
}
if (elem.Attribute(XNamespace.Xmlns + "xsd") == null) {
elem.Add(new XAttribute(XNamespace.Xmlns + "xsd", "http://www.w3.org/2001/XMLSchema"));
}
My app is split up into a configuration tool which writes the configuration and a viewer which just reads and uses settings from the configuration.
What techniques for storing the properties would would be recommended in this scenario? Would XML for the different categories be a good idea?
The apps are developing in C#, on .NET 3.5 and using WinForms.
I would have a shared assembly, which contains your settings class. You can then serialize/deserialize this class to a common place on the hard drive:
[XmlRoot()]
public class Settings
{
private static Settings instance = new Settings();
private Settings() {}
/// <summary>
/// Access the Singleton instance
/// </summary>
[XmlElement]
public static Settings Instance
{
get
{
return instance;
}
}
/// <summary>
/// Gets or sets the height.
/// </summary>
/// <value>The height.</value>
[XmlAttribute]
public int Height { get; set; }
/// <summary>
/// Main window status (Maximized or not)
/// </summary>
[XmlAttribute]
public FormWindowState WindowState
{
get;
set;
}
/// <summary>
/// Gets or sets a value indicating whether this <see cref="Settings"/> is offline.
/// </summary>
/// <value><c>true</c> if offline; otherwise, <c>false</c>.</value>
[XmlAttribute]
public bool IsSomething
{
get;
set;
}
/// <summary>
/// Save setting into file
/// </summary>
public static void Serialize()
{
// Create the directory
if (!Directory.Exists(AppTmpFolder))
{
Directory.CreateDirectory(AppTmpFolder);
}
using (TextWriter writer = new StreamWriter(SettingsFilePath))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
serializer.Serialize(writer, Settings.Instance);
}
}
/// <summary>
/// Load setting from file
/// </summary>
public static void Deserialize()
{
if (!File.Exists(SettingsFilePath))
{
// Can't find saved settings, using default vales
SetDefaults();
return;
}
try
{
using (XmlReader reader = XmlReader.Create(SettingsFilePath))
{
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
if (serializer.CanDeserialize(reader))
{
Settings.instance = serializer.Deserialize(reader) as Settings;
}
}
}
catch (System.Exception)
{
// Failed to load some data, leave the settings to default
SetDefaults();
}
}
}
Your xml file will then look like this:
<?xml version="1.0" encoding="utf-8"?>
<Settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" Height="738" WindowState="Maximized" IsSomething="false" >
</Settings>
XML would seem the ideal choice for this.
In WinForms user settings are persisted via XML so you have all the classes and helper methods you need.