How to customize serialization of List<string> in C# - c#

This is killing me. I've read these:
http://msdn.microsoft.com/en-us/library/athddy89(v=VS.80).aspx
http://msdn.microsoft.com/en-us/library/2baksw0z(v=VS.80).aspx
But I don't see how to apply them to what I'm trying to do. I want to customize the way the following list serializes...
[Serializable]
public class FinalConcentrations : List<string> { }
so that when I pass it as the "objectToSerialze" to this...
public void serializeObject(object objectToSerialize, Stream outputStream)
{
// removes the default added namespaces
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
XmlSerializer serial = new XmlSerializer(objectToSerialize.GetType());
MemoryStream ms = new MemoryStream();
serial.Serialize(ms, objectToSerialize, ns);
StreamReader reader = new StreamReader(ms);
ms.Position = 0;
ms.WriteTo(outputStream);
}
...it writes this to the output stream:
<FinalConcentrations>
<FinalConcentration>string value 1</FinalConcentration>
<FinalConcentration>string value 2</FinalConcentration>
<FinalConcentration>string value 3</FinalConcentration>
</FinalConcentration>
...instead of this
<FinalConcentrations>
<string>string value 1</string>
<string>string value 2</string>
<string>string value 3</string>
</FinalConcentration>
My serializeObject method is used to serialize a wide variety of objects, so I'm looking for a way to do this in my FinalConcentrations definition rather than within that method.
Please, help.

The easiest way to fix that is to pass in a wrapper object instead of the list itself, i.e.
public class FinalConcentrations {
private readonly List<string> items = new List<string>();
[XmlElement("FinalConcentration")]
public List<string> Items {get {return items;}}
}
that do?

Well, when I ran your example I actually got
<?xml version="1.0"?>
<ArrayOfString>
<string>Red</string>
<string>Green</string>
<string>Blue</string>
</ArrayOfString>
but by changing
[Serializable, XmlRoot( ElementName= "FinalConcentrations")]
public class FinalConcentrations : List<string> { }
I got
<?xml version="1.0"?>
<FinalConcentrations>
<string>Red</string>
<string>Green</string>
<string>Blue</string>
</FinalConcentrations>
QED?
There are a whole bunch of XML decorator attributes that can change the serialisation, eg. XmlElement. Worth having a look at.
Best of luck.

Related

Serialization value without create object C#

I have work with a MainWindow.xaml class and I want to save some values of my class in my case: private static int bestrecord = 0;
How can I save this value and restore it without a created class just for it?
Because with Serialization you can save only an object and I just want to save this variable.
Thank you.
You can use Application Settings functionality, which is pretty much designed for saving simple variables which are part of the application state, and need to be restored in future sessions.
The documentation is here.
Once you've creating a setting using the designer in the IDE, you can load settings like this:
var mySetting = Properties.Settings.Default.MySettingName;
You can edit your variable normally and save it like this
Properties.Settings.Default.MySettingName = mySetting ;
Properties.Settings.Default.Save();
I have found a very good way for save my score in xml file.
I'm based on Examples of XML Serialization.
For do that i have create 2 function:
private void SerializeElement()
{
XmlSerializer ser = new XmlSerializer(typeof(XmlElement));
XmlElement myElement = new XmlDocument().CreateElement("bestRecord");
myElement.InnerText = bestRecord.ToString();
TextWriter writer = new StreamWriter("text.xml");
ser.Serialize(writer, myElement);
writer.Close();
}
and
private static int deserialize()
{
XmlSerializer ser = new XmlSerializer(typeof(XmlElement));
StreamReader lecteur = new StreamReader("text.xml");
XmlDocument myElement = new XmlDocument();
XmlElement p = (XmlElement) ser.Deserialize(lecteur);
lecteur.Close();
return int.Parse(p.InnerText);
}
the xml file look like:
<?xml version="1.0" encoding="utf-8"?>
<bestRecord>8</bestRecord>

List XML Serialization Doubling Elements

I'm trying to serialize an object as XML and have been using a little tester to experiment with different object behaviors when serializing as XML. I know binary serializers are deep and that XML is shallow. However, it does seem that it tries to serialize a List composed within another object when using XML.
My issue is that I get copied data when I serialize a List. Code and output follow:
class Program
{
static void Main(string[] args)
{
TestSerializer original = new TestSerializer();
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(original.GetType());
x.Serialize(Console.Out, original);
Console.WriteLine("\n\n\n");
using (MemoryStream stream = new MemoryStream())
{
x.Serialize(stream, original);
stream.Seek(0, SeekOrigin.Begin);
TestSerializer copy = x.Deserialize(stream) as TestSerializer;
x.Serialize(Console.Out, copy);
}
Console.ReadLine();
}
}
public class TestSerializer
{
public List<string> words = new List<string>();
public TestSerializer()
{
words.Add("word");
words.Add("anotherword");
}
}
And the corresponding output:
<?xml version="1.0" encoding="IBM437"?>
<TestSerializer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd=
"http://www.w3.org/2001/XMLSchema">
<words>
<string>word</string>
<string>anotherword</string>
</words>
</TestSerializer>
<?xml version="1.0" encoding="IBM437"?>
<TestSerializer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd=
"http://www.w3.org/2001/XMLSchema">
<words>
<string>word</string>
<string>anotherword</string>
<string>word</string>
<string>anotherword</string>
</words>
</TestSerializer>
As you can see, the list content is doubled up when "original" is serialized, then deserialized to "copy". Is there something I am missing as far this is concerned? It seems like there should not be duplicated data.
Put a breakpoint on the constructor of TestSerializer class. You will notice that it is called e.g. on the following line:
TestSerializer copy = x.Deserialize(stream) as TestSerializer;
So when you deserialize the object following happens
First instance of TestSerializer is created (populates the two values in the list) and it executes the default constructor
Dezerialization adds the items from the stream to the created object (now you have 4 items)

How create a serializable C# class from XML file

I am fairly new to XML in .net. As part of my task i need to create the class which can be serialized to XML. I have an sample XML file with all the tags(the class should produce XML similar to the sample XML file ). what would be best approach to create the class from XML file?
Thank you in advance!!
You can use XSD.exe to create a .cs file from .xml.
http://msdn.microsoft.com/en-us/library/x6c1kb0s%28VS.71%29.aspx
At the command line:
xsd myFile.xml
xsd myFile.xsd
The first line will generate a schema definition file (xsd), the second file should generate a .cs file. I'm not sure if the syntax is exact, but it should get you started.
Working backwards might help -- create your class first, then serialize and see what you get.
For the simplest classes it's actually quite easy. You can use XmlSerializer to serialize, like:
namespace ConsoleApplication1
{
public class MyClass
{
public string SomeProperty
{
get;
set;
}
}
class Program
{
static void Main(string[] args)
{
XmlSerializer serializer = new XmlSerializer(typeof(MyClass));
TextWriter writer = new StreamWriter(#"c:\temp\class.xml");
MyClass firstInstance = new MyClass();
firstInstance.SomeProperty = "foo"; // etc
serializer.Serialize(writer, firstInstance);
writer.Close();
FileStream reader = new FileStream(#"c:\temp\class.xml", FileMode.Open);
MyClass secondInstance = (MyClass)serializer.Deserialize(reader);
reader.Close();
}
}
}
This will write a serialized representation of your class in XML to "c:\temp\class.xml". You could take a look and see what you get. In reverse, you can use serializer.Deserialize to instantiate the class from "c:\temp\class.xml".
You can modify the behaviour of he serialization, and deal with unexpected nodes, etc -- take a look at the XmlSerializer MSDN page for example.
here's a good example how to serialize/deserialize an object. http://sharpertutorials.com/serialization/

Serialize Object to XML in with specific format

Im trying to Serialize an object( a class in this case) with an specific fomat.
I got something like this:
<ns:pay xmlns:ns="http://example.uri.here">
<ns:Payment>
<ns:customerKeyValue>5555</ns:customerKeyValue>
<ns:bankCode>BBBB</ns:bankCode>
<ns:paymentAmount>456</ns:paymentAmount>
<ns:paymentCategory>KD</ns:paymentCategory>
<ns:paymentMode>AC</ns:paymentMode>
<ns:referenceNumber>123A</ns:referenceNumber>
<ns:userID>Test2</ns:userID>
<ns:invoiceNumber>61</ns:invoiceNumber>
</ns:Payment>
</ns:pay>
I have the class that have each element but when i serialize it it convert its to this format:
<?xml version="1.0"?>
<ns_x003A_pay xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://example.uri.here">
<CustomerKeyValue>5555</CustomerKeyValue>
<BankCode>BBBB</BankCode>
<PaymentAmount>456</PaymentAmount>
<PaymentCategory>KD</PaymentCategory>
<PaymentMode>AC</PaymentMode>
<ReferenceNumber>123A</ReferenceNumber>
<UserID>Test2</UserID>
<InvoiceNumber>61</InvoiceNumber>
</ns_x003A_pay>
So anyone can help me with that?
The method that im using to convert to xml is this:
public static string SerializeToXMLString(object ObjectToSerialize)
{
MemoryStream mem = new MemoryStream();
System.Xml.Serialization.XmlSerializer ser = new System.Xml.Serialization.XmlSerializer(ObjectToSerialize.GetType());
ser.Serialize(mem, ObjectToSerialize);
ASCIIEncoding ascii = new ASCIIEncoding();
return ascii.GetString(mem.ToArray());
}
note:
to specify the namespace and class name i'm using this:
[XmlRootAttribute( "ns:pay", Namespace = "http://example.uri.here")]
in the class
If you haven't noted every XML element start with
Thanks for you help.
Ok guys I just found the answer here to my questions and i'm writing here to help people with this problem:
public static string SerializeToXMLString(object ObjectToSerialize)
{
//
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("ns", "http://example.uri.here");
//
//
XmlSerializer serializer = new XmlSerializer(ObjectToSerialize.GetType());
XmlWriterSettings writerSettings = new XmlWriterSettings();
writerSettings.OmitXmlDeclaration = true;
StringWriter stringWriter = new StringWriter();
using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, writerSettings))
{
serializer.Serialize(xmlWriter, ObjectToSerialize,ns);
}
return stringWriter.ToString();
}
To solve the prefix :
I created a XmlSerializerNamespaces object and added the prefix that I wanted and the namespace.
To solve the ns:pay ns:payment
I created two classes: Payment and Pay.
In the pay class i added this:
[XmlRoot("pay", Namespace = "http://example.uri.here")]
In the Payment Class i added this:
[XmlRoot("pay")]
Pay Class has a property of type payment. That create the xml in this style:
<ns:pay>
<ns:payment
element here
</ns:payemnt>
</ns:pay>
Thank you guys. Sorry that I ask and found the question almost 30 minutes after asking.
There is also LINQtoXSD (not XmlSerializer, sure :-)

How do I create an XmlNode from a call to XmlSerializer.Serialize?

I am using a class library which represents some of its configuration in .xml. The configuration is read in using the XmlSerializer. Fortunately, the classes which represent the .xml use the XmlAnyElement attribute at which allows me to extend the configuration data for my own purposes without modifying the original class library.
<?xml version="1.0" encoding="utf-8"?>
<Config>
<data>This is some data</data>
<MyConfig>
<data>This is my data</data>
</MyConfig>
</Config>
This works well for deserialization. I am able to allow the class library to deserialize the .xml as normal and the I can use my own XmlSerializer instances with a XmlNodeReader against the internal XmlNode.
public class Config
{
[XmlElement]
public string data;
[XmlAnyElement]
public XmlNode element;
}
public class MyConfig
{
[XmlElement]
public string data;
}
class Program
{
static void Main(string[] args)
{
using (Stream fs = new FileStream(#"c:\temp\xmltest.xml", FileMode.Open))
{
XmlSerializer xser1 = new XmlSerializer(typeof(Config));
Config config = (Config)xser1.Deserialize(fs);
if (config.element != null)
{
XmlSerializer xser2 = new XmlSerializer(typeof(MyConfig));
MyConfig myConfig = (MyConfig)xser2.Deserialize(new XmlNodeReader(config.element));
}
}
}
I need to create a utility which will allow the user to generate a new configuration file that includes both the class library configuration as well my own configuration, so new objects will be created which were not read from the .xml file. The question is how can I serialize the data back into .xml?
I realize that I have to initially call XmlSerializer.Serialize on my data before calling the same method on the class library configuration. However, this requires that my data is represented by an XmlNode after calling Serialize. What is the best way to serialize an object into an XmlNode using the XmlSerializer?
Thanks,
-kevin
btw-- It looks like an XmlNodeWriter class written by Chris Lovett was available at one time from Microsoft, but the links are now broken. Does anyone know of an alternative location to get this class?
So you need to have your class contain custom configuration information, then serialize that class to XML, then make that serialized XML into an XML node: is that right?
Could you just take the string created by the XMLSerializer and wrap that in it's own XML tags?
XmlSerializer xs = new XmlSerializer(typeof(MyConfig));
StringWriter xout = new StringWriter();
xs.Serialize(xout, myConfig);
XmlDocument x = new XmlDocument();
x.LoadXml("<myConfig>" + xout.ToString() + "</myConfig>");
Now x is an XmlDocument containing one element, "<myconfig>", which has your serialized custom configuration in it.
Is that at all what you're looking for?
It took a bit of work, but the XPathNavigator route does work... just remember to call .Close on the XmlWriter, .Flush() doesn't do anything:
//DataContractSerializer serializer = new DataContractSerializer(typeof(foo));
XmlSerializer serializer = new XmlSerializer(typeof(foo));
XmlDocument doc = new XmlDocument();
XPathNavigator nav = doc.CreateNavigator();
XmlWriter writer = nav.AppendChild();
writer.WriteStartDocument();
//serializer.WriteObject(writer, new foo { bar = 42 });
serializer.Serialize(writer, new foo { bar = 42 });
writer.WriteEndDocument();
writer.Flush();
writer.Close();
Console.WriteLine(doc.OuterXml);
One solution is to serialize the inner object to a string and then load the string into a XmlDocument where you can find the XmlNode representing your data and attach it to the outer object.
XmlSerializer xser1 = new XmlSerializer(typeof(Config));
XmlSerializer xser2 = new XmlSerializer(typeof(MyConfig));
MyConfig myConfig = new MyConfig();
myConfig.data = "My special data";
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
XmlWriter xw = new XmlTextWriter(sw);
xser2.Serialize(xw, myConfig);
XmlDocument doc = new XmlDocument();
doc.LoadXml(sb.ToString());
Config config = new Config();
config.data = "some new info";
config.element = doc.LastChild;
xser1.Serialize(fs, config);
However, this solution is cumbersome and I would hope there is a better way, but it resolves my problem for now.
Now if I could just find the mythical XmlNodeWriter referred to on several blogs!
At least one resource points to this as an alternative to XmlNodeWriter: http://msdn.microsoft.com/en-us/library/5x8bxy86.aspx. Otherwise, you could write MS using that form they have on the new MSDN Code Library replacement for GotDotNet looking for XmlNodeWriter.

Categories