can somebody help with this problem. I have created class for deserialization data from XML. But when I programme compile VS shows me this exception InvalidOperationException: There is an error in XML document(2,2) so I guess that I defined attribute Month in class Store. I tried to type into int and without successfull please help me... Here is the code of problem:
<?xml version="1.0" encoding="utf-8" ?>
<Store>
<StoreS Month="2">
<Amount>159</Amount>
<Mod_date> 20.3.2014 18:19:18</Mod_date>
</StoreS>
<StoreS Month="2">
<Amount>270</Amount>
<Mod_date> 20.3.2014 18:19:40</Mod_date>
</StoreS>
</Store>
The class into which I wanna to deserialize data is written this way:
[XmlRoot("Store"),XmlType("Store")]
public class Store
{
[XmlElement("StoreS")]
public List<RecordStore> StoreS = new List<RecordStore>();
[XmlAttribute("Month")]
public string Month { get; set; }
}
public class RecordStore
{
[XmlElement("Amount")]
public int amount{get;set;}
[XmlElement("Mod_date")]
public DateTime mod_date { get; set; }
}
Thank you very much for your help.
Your xml has bad datetime format, it should be like 2014-03-21T00:00:00, for example
as you serialize in the same way you can de-serialize the object
public void Serialize<T>(T details)
{
XmlSerializer serializer = new XmlSerializer(typeof(T));
using (TextWriter writer = new StreamWriter("Xml.xml"))
{
serializer.Serialize(writer, details);
}
}
public void Deserialize<T>(out T obj)
{
XmlSerializer serializer = new XmlSerializer(typeof (T));
using (TextReader reader = new StreamReader("Xml.xml"))
{
obj = (T)serializer.Deserialize(reader);
}
}
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)
Question
Is it possible to skip invalid values up on de-serialization? For example if a user inserted a invalid value inside the xml file.
Class Definition
using Relink.Data.Enum;
using System;
using System.IO;
using System.Xml.Serialization;
using System.ComponentModel;
namespace Relink {
[Serializable]
public class Settings {
internal static XmlSerializer Serializer = new XmlSerializer(typeof(Settings));
public Difficulty Difficulty {
get;
set;
}
public Boolean CaptureMouse {
get;
set;
}
internal void loadDefaults() {
this.Difficulty = Difficulty.Normal;
this.CaptureMouse = false;
}
}
}
Serialization Method
// ...
if(!File.Exists(GameDir + SettingsFile)) {
Settings = new Settings();
Settings.loadDefaults();
TextWriter writer = new StreamWriter(GameDir + SettingsFile);
Settings.Serializer.Serialize(writer, Settings);
writer.Close();
writer.Dispose();
} else {
TextReader reader = new StreamReader(GameDir + SettingsFile);
Settings = (Settings)Settings.Serializer.Deserialize(reader);
}
// ...
XML Content (valid)
<?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">
<Difficulty>Normal</Difficulty>
<CaptureMouse>false</CaptureMouse>
</Settings>
XML Content (invalid)
<?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">
<Difficulty>Moo</Difficulty>
<CaptureMouse>false</CaptureMouse>
</Settings>
Remarks
I don't want to "reset" the users settings, i just want to skip the invalid stuff and use default values instead. Otherwise i would you a try/catch construct and just re-generate the xml file.
Unfortunately there is no way to suppress the exception inside XmlSerializer when an unknown enum value is encountered. Instead, you will need to create a string-valued property for this purpose, and serialize that instead of the enum-valued property:
[Serializable]
public class Settings
{
internal static XmlSerializer Serializer = new XmlSerializer(typeof(Settings));
[Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[XmlElement("Difficulty")]
public string XmlDifficulty
{
get
{
return Difficulty.ToString();
}
set
{
try
{
Difficulty = (Difficulty)Enum.Parse(typeof(Difficulty), value);
}
catch
{
Debug.WriteLine("Invalid difficulty found: " + value);
Difficulty = Difficulty.Normal;
}
}
}
[XmlIgnore]
public Difficulty Difficulty { get; set; }
public Boolean CaptureMouse { get; set; }
internal void loadDefaults()
{
this.Difficulty = Difficulty.Normal;
this.CaptureMouse = false;
}
}
Can some one help for a strange Serialization issue which I getting in a one environment and it working fine in all environments..but it failed a particular environment..so I specified as strange here
Code
public SomeType[] Deserialize(string xml)
{
XmlSerializer serializer = new XmlSerializer(typeof(SomeType[]));
StringReader stringReader = new StringReader(xml);
SomeType[] types = (SomeType[])serializer.Deserialize(stringReader);
stringReader.Close();
return types;
}
Serialized XML data:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfSomeType>
<SomeType>
<Field1>val</Field1>
<Field2>val</Field2>
<Field3>val</Field3>
</SomeType>
</ArrayOfSomeType>
And the exception is:
System.InvalidCastException: Unable to cast object of type 'SomeType[]' to type 'SomeType'.
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterSomeType.Write11_SomeType(Object o)
The error here is in the Serialize method that you don't show. Your Deserialize method works without error. The following Serialize method works fine:
static string Serialize(SomeType[] values)
{
using (var sw = new StringWriter())
{
var serializer = new XmlSerializer(typeof(SomeType[]));
serializer.Serialize(sw, values);
return sw.ToString();
}
}
If I had to guess, you have the following:
var serializer = new XmlSerializer(typeof(SomeType));
If you want the exact same output without unnecessary namespace alias declarations, change the method to include:
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("","");
serializer.Serialize(sw, values, ns);
Edit showing the current code working fine:
using System;
using System.IO;
using System.Xml.Serialization;
public class SomeType
{
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
}
public class MyTest
{
public static SomeType[] Deserialize(string xml)
{
XmlSerializer serializer = new XmlSerializer(typeof(SomeType[]));
StringReader stringReader = new StringReader(xml);
SomeType[] types = (SomeType[])serializer.Deserialize(stringReader);
stringReader.Close();
return types;
}
public static void Main()
{
string xml = #"<?xml version=""1.0"" encoding=""utf-8""?>
<ArrayOfSomeType>
<SomeType>
<Field1>val</Field1>
<Field2>val</Field2>
<Field3>val</Field3>
</SomeType>
</ArrayOfSomeType>";
var items = Deserialize(xml);
foreach (var item in items)
{
Console.WriteLine("{0}, {1}, {2}",
item.Field1, item.Field2, item.Field3);
}
}
}
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
How can I change XML-element name for field inherited from base class while doing serialization?
For example I have next base class:
public class One
{
public int OneField;
}
Serialization code:
static void Main()
{
One test = new One { OneField = 1 };
var serializer = new XmlSerializer(typeof (One));
TextWriter writer = new StreamWriter("Output.xml");
serializer.Serialize(writer, test);
writer.Close();
}
I get what I need:
<?xml version="1.0" encoding="utf-8"?>
<One xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<OneField>1</OneField>
</One>
Now I have created new class inherited from A with additional field and custom XML element name for it:
public class Two : One
{
[XmlElement("SecondField")]
public int TwoField;
}
Serialization code:
static void Main()
{
Two test = new Two { OneField = 1, TwoField = 2 };
var serializer = new XmlSerializer(typeof (Two));
TextWriter writer = new StreamWriter("Output.xml");
serializer.Serialize(writer, test);
writer.Close();
}
As a result I get next output:
<?xml version="1.0" encoding="utf-8"?>
<Two xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<OneField>1</OneField>
<SecondField>2</SecondField>
</Two>
The problem is that I want to change OneField in this output to FirstField without touching base class code (because I will use it too and the names must be original). How can I accomplish this?
Thank you.
Try this:
public class Two : One
{
private static XmlAttributeOverrides xmlOverrides;
public static XmlAttributeOverrides XmlOverrides
{
get
{
if (xmlOverrides == null)
{
xmlOverrides = new XmlAttributeOverrides();
var attr = new XmlAttributes();
attr.XmlElements.Add(new XmlElementAttribute("FirstField"));
xmlOverrides.Add(typeof(One), "OneField", attr);
}
return xmlOverrides;
}
}
[XmlElement("SecondField")]
public string TwoField;
}
And your serializer init is a lot easier:
var xmls = new System.Xml.Serialization.XmlSerializer(typeof(Two), Two.XmlOverrides);
Here's a workaround: Override the fields in the subclass and mark the overriden field with whatever name you need. For example,
class One
{
public int OneField { get; set; }
}
class Two : One
{
[XmlElement("FirstField")]
public new int OneField
{
get { return base.OneField; }
set { base.OneField = value; }
}
}