Deserialize using DataContractSerializer - c#

I am trying to Deserialize an xml file that looks like the following
<?xml version="1.0"?>
<Test xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/ConsoleApplication6">
<values>
<String>Value 1</String>
<String>Value 2</String>
</values>
</Test>
to an object that is this
[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/ConsoleApplication6")]
public class Test
{
[DataMember(Name = "values")]
public String[] values;
}
with
var ds = new DataContractSerializer(typeof(Test));
using (Stream stream1 = File.OpenRead(#"C:\Projects\test1.xml"))
{
Test rr = (Test)ds.ReadObject(stream1);
}
However none of the values are deserializing. I just see and empty array in Test rr. Could you please tell what I am doing wrong. Thanks in advance.

If you need fine control of the XML that is emitted when serializing, you should not use DataContractSerializer. It is has very limited flexibility. You would be better off using XmlSerializer, which has liimtitations as well, but is much more flexible than DataContractSerializer.
That being said, here is how you can do what you want with DataContractSerializer.
Change the default namespace on your xml to use the one that DataContractSerializeruses by default.
<?xml version="1.0"?>
<Test xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/">
<values>
<String>Value 1</String>
<String>Value 2</String>
</values>
</Test>
Instead of using string[] create your own custom type that derives from List<string>. This must be done solely for the purpose of having something to hang CollectionDataContractAttribute on. CollectionDataContractAttribute is what will let you specify the name of the elements inside <values>.
[DataContract]
public class Test
{
[DataMember(Name = "values")]
public TestValues values;
}
[CollectionDataContract(ItemName = "String")]
public class TestValues : List<string> { }

The DataContractSerializer has its own rules for XML and cannot support all XML forms. I suggest using the XmlSerializer.
Use this definition
[XmlClass(Namespace = "http://schemas.datacontract.org/2004/07/ConsoleApplication6")]
public class Test
{
[XmlArray("values")]
[XmlArrayItem("String")]
public String[] values;
}

Related

c# XmlSerializer List of typed objects

I have the problem that I got xml from a REST service and have to deserialize it to an object structure and there is a type="proglang" in it.
<listResult>
<listEntry xsi:type="proglang">
<id>0</id>
<name>C#</name>
</listEntry>
<listEntry xsi:type="proglang">
<id>0</id>
<name>C#</name>
</listEntry>
</listResult>
How should the object model with the xml attributes look like in c#?
My Code so far:
[XmlRoot("listResult")]
public class ListResult
{
[XmlElement("listEntry")]
//[XmlArrayItem(Type=typeof(proglang))]
public List<proglang> listEntry;
}
public class proglang
{
[XmlElement("code")]
public int id;
[XmlElement("label")]
public string name;
}
and the resulting XML from serializing:
<listResult xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<listEntry>
<code>1</code>
<label>C#</label>
</listEntry>
<listEntry>
<code>1</code>
<label>C++</label>
</listEntry>
</listResult>

Adding a new field to a class to be serialized

To be able to serialize and deserialize a XML I had designed like this:
<?xml version="1.0" encoding="utf-8"?>
<DbConnections xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DbConnectionInfo>
<ServerName>SQLServer2k8</ServerName>
</DbConnectionInfo>
<DbConnectionInfo>
<ServerName>SQLServer2k8R2</ServerName>
</DbConnectionInfo>
</DbConnections>
I had written two classes like this below:
public class DbConnectionInfo
{
public string ServerName { get; set; }
}
and
[Serializable]
[XmlRoot("DbConnections")]
public class DbConnections: List<DbConnectionInfo>
{
//...
}
Now I want to expand my XML form and add one more field like this but is there is a way to design my class in a way that I don' have to REPEAT it in every XML tag? like this:
<?xml version="1.0" encoding="utf-8"?>
<DbConnections xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<DbConnectionInfo>
<ServerName>SQLServer2k8</ServerName>
</DbConnectionInfo>
<DbConnectionInfo>
<ServerName>SQLServer2k8R2</ServerName>
</DbConnectionInfo>
<UseWindowsAuthentication>Yes</UseWindowsAuthentication>
</DbConnections>
So I just really added that one line to previous XML:
But my question is how should I modify my classes to add this? And is it even possible or a correct design?
<UseWindowsAuthentication>Yes</UseWindowsAuthentication>
Maybe something like this
[Serializable]
[XmlRoot("DbConnections")]
public class DbConnections
{
List<DbConnectionInfo> DbConnectionInfos;
Boolean UseWindowsAuthentication;
}
Edited to add: if you do not want nested elements, decorate your class as so
public class DbConnections
{
[XmlElement("DbConnectionInfo")]
public List<DbConnectionInfo> DbConnectionInfos;
public Boolean UseWindowsAuthentication;
}
I tested this and the following xml was serialized
XmlSerializer serializer = new XmlSerializer(typeof(DbConnections));
string xml;
using (StringWriter textWriter = new StringWriter())
{
serializer.Serialize(textWriter, oDbConnections);
xml = textWriter.ToString();
}
<?xml version="1.0" encoding="utf-16"?>
<DbConnections xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<DbConnectionInfo>
<ServerName>test</ServerName>
</DbConnectionInfo>
<DbConnectionInfo>
<ServerName>test 2</ServerName>
</DbConnectionInfo>
<UseWindowsAuthentication>true</UseWindowsAuthentication>
</DbConnections>
Here is a link to more info on decorating for xml serialization

C# Changing the element names of items in a list when serializing/deserializing XML

I have a class defined as below:
[XmlRoot("ClassName")]
public class ClassName_0
{
//stuff...
}
I then create a list of ClassName_0 like such:
var myListInstance= new List<ClassName_0>();
This is the code I use to serialize:
var ser = new XmlSerializer(typeof(List<ClassName_0>));
ser.Serialize(aWriterStream, myListInstance);
This is the code I use to deserialize:
var ser = new XmlSerializer(typeof(List<ClassName_0>));
var wrapper = ser.Deserialize(new StringReader(xml));
If I serialize it to xml, the resulting xml looks like below:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfClassName_0 xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ClassName_0>
<stuff></stuff>
</ClassName_0>
<ClassName_0>
<stuff></stuff>
</ClassName_0>
</ArrayOfClassName_0>
Is there a way to serialize and be able to deserialize the below from/to a list of ClassName_0?
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfClassName xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ClassName>
<stuff></stuff>
</ClassName>
<ClassName>
<stuff></stuff>
</ClassName>
</ArrayOfClassName>
Thanks!
In your example ClassName isn't the real root.
The real root is your list. So you have to mark the list as the root element.
Your class is just an XmlElement.
try this :
XmlType(TypeName="ClassName")]
public class ClassName_0
{
//stuff...
}
Worked it out, finally, with the help of Jan Peter. XmlRoot was the wrong attribute to put on the class. It was supposed to be XmlType. With XmlType the desired effect is achieved.
You make a root of document tree and this root will contain list of any object.
[XmlRootAttribute("myDocument")]
public class myDocument
{
[XmlArrayAttribute]
publict ClassName[] ArrayOfClassName {get;set;}
}
[XmlType(TypeName="ClassName")]
public class ClassName
{
public string stuff {get;set;}
}

XmlSerializer differs between .NET 3.5 & CF.NET 3.5

I've a library that turns under CF.NET & .NET but serialization differs between both. As a result, a XML file generated under CF.NET isn't readable under .NET, and that is a big problem for me !
Here the code sample :
[Serializable, XmlRoot("config")]
public sealed class RemoteHost : IEquatable<RemoteHost>
{
// ...
}
public class Program
{
public static void Main()
{
RemoteHost host = new RemoteHost("A");
List<RemoteHost> hosts = new List<RemoteHost>();
hosts.Add(host);
XmlSerializer ser = new XmlSerializer(typeof(List<RemoteHost>));
ser.Serialize(Console.Out, hosts);
}
}
CF.NET xml :
<?xml version="1.0"?>
<ArrayOfConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<config Name="A">
</config>
</ArrayOfConfig>
.NET xml
<?xml version="1.0" encoding="ibm850"?>
<ArrayOfRemoteHost xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<RemoteHost Name="A">
</RemoteHost>
</ArrayOfRemoteHost>
How can I modify my program in order to generate the same XML ?
It looks like a bug processing the root name, indeed. As a workaround: take control of the root manually:
[XmlRoot("foo")]
public class MyRoot {
[XmlElement("bar")]
public List<RemoteHost> Hosts {get;set;}
}
This should serialize as
<foo><bar>...</bar>...</foo>
on either platform. Substitute foo and bar for your preferred names.
(personally, I'd be using binary output, though ;p)

How can I Serialize Properly

If I have a class MovieClass as
[XmlRoot("MovieClass")]
public class Movie
{
[XmlElement("Novie")]
public string Title;
[XmlElement("Rating")]
public int rating;
}
How can I've an attribute "x:uid" in my "Movie" element, so that the output when XmlSerializer XmlSerializer s = new XmlSerializer(typeof(MovieClass)) was used
is like this:
<?xml version="1.0" encoding="utf-16"?>
<MovieClass>
<Movie x:uid="123">Armagedon</Movie>
</MovieClass>
and not like this
<?xml version="1.0" encoding="utf-16"?>
<MovieClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Movie x:uid="123" Title="Armagedon"/>
</MovieClass>
Note: I want the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" removed, if possible.
I answered this in your original post, but I think this one is worded better so I will post it here as well, if it gets closed as duplicate you can modify your original post to mirror this question.
I don't think this is possible without having Title be a custom type or explicitly implementing serialization methods.
You could do a custom class like so..
class MovieTitle
{
[XmlText]
public string Title { get; set; }
[XmlAttribute(Namespace="http://www.myxmlnamespace.com")]
public string uid { get; set; }
public override ToString() { return Title; }
}
[XmlRoot("MovieClass")]
public class Movie
{
[XmlElement("Movie")]
public MovieTitle Title;
}
which will produce:
<MovieClass xmlns:x="http://www.myxmlnamespace.com">
<Movie x:uid="movie_001">Armagedon</Movie>
</MovieClass>
Although the serializer will compensate for unknown namespaces with a result you probably won't expect.
You can avoid the wierd behavior by declaring your namespaces and providing the object to the serializer..
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("x", "http://www.myxmlnamespace.com");
It's not valid XML if you don't have x declared as a namespace prefix. Quintin's response tells you how to get valid XML.

Categories

Resources