NULL-Values when deserializing XML - c#
I try to deserialize different XML docs which are build according to the same schema and yes, I'm a newby to this topic. I managed to retrieve some auto-generated Code from using xsd-files as “type definition language” (VS2013) and for me it looks ok and basically it’s working which means I can start the program. However, there is no output of my program and by debugging it I can see that the most important fields are not populated. Here is the situation (the original generated code and the XML are of course much longer but I cut to the classes which produce the problem):
XML:
<?xml version="1.0" encoding="UTF-8"?>
<mainDatas
xmlns="http://www.myNamespace.com/"
xmlns:ons="http://www.myOtherNamespace.com/"
xmlns:aan="http://www.andAnotherNamespace.com/">
<contains>
<ons:FeatureCollection aan:id="UHL">
<aan:boundedBy>999.9</aan:boundedBy>
<aan:featureMember>
<myClass1 aan:id="XXX0001">
</myClass1>
</aan:featureMember>
<myClass2 aan:id="XXX0002">
</myClass2>
</aan:featureMember>
<myClass1 aan:id="XXX0003">
</myClass1>
</aan:featureMember>
</ons:FeatureCollection>
</contains>
</mainDatas>
C# (auto-generated):
[System.CodeDom.Compiler.GeneratedCodeAttribute("MSBuild", "12.0.30723.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.myNamespace.com/")]
[System.Xml.Serialization.XmlRootAttribute("mainDatas", Namespace="http://www.myNamespace.com/", IsNullable=false)]
public partial class mainDatas
{
private mainDatasContains containField;
public mainDatasContains contain
{
get
{
return this.containField;
}
set
{
this.containField = value;
}
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("MSBuild", "12.0.30723.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true, Namespace="http://www.myNamespace.com/")]
public partial class mainDatasContains
{
private FeatureCollectionType1 featureCollectionField;
[System.Xml.Serialization.XmlElementAttribute(Namespace="http://www.myOtherNamespace.com/")]
public FeatureCollectionType1 FeatureCollection
{
get
{
return this.featureCollectionField;
}
set
{
this.featureCollectionField = value;
}
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("MSBuild", "12.0.30723.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(TypeName="FeatureCollectionType", Namespace="http://www.myOtherNamespace.de/")]
[System.Xml.Serialization.XmlRootAttribute("FeatureCollection", Namespace="http://www.myOtherNamespace.de/", IsNullable=false)]
public partial class FeatureCollectionType1
{
private string lockIdField;
private FeaturePropertyType[] featureMemberField;
[System.Xml.Serialization.XmlAttributeAttribute()]
public string lockId
{
get
{
return this.lockIdField;
}
set
{
this.lockIdField = value;
}
}
[System.Xml.Serialization.XmlElementAttribute("featureMember")]
public FeaturePropertyType[] featureMember
{
get
{
return this.featureMemberField;
}
set
{
this.featureMemberField = value;
}
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("MSBuild", "12.0.30723.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.andAnotherNamespace.com/")]
[System.Xml.Serialization.XmlRootAttribute("featureMember", Namespace="http://www.andAnotherNamespace.com/", IsNullable=false)]
public partial class FeaturePropertyType
{
private AbstractFeatureType itemField;
private bool ownsField;
public FeaturePropertyType()
{
this.ownsField = false;
}
[System.Xml.Serialization.XmlElementAttribute("DynamicFeature", typeof(DynamicFeatureType))]
[System.Xml.Serialization.XmlElementAttribute("FeatureCollection", typeof(FeatureCollectionType))]
[System.Xml.Serialization.XmlElementAttribute("Observation", typeof(ObservationType))]
public AbstractFeatureType Item
{
get
{
return this.itemField;
}
set
{
this.itemField = value;
}
}
[System.Xml.Serialization.XmlAttributeAttribute()]
[System.ComponentModel.DefaultValueAttribute(false)]
public bool owns
{
get
{
return this.ownsField;
}
set
{
this.ownsField = value;
}
}
}
[System.Xml.Serialization.XmlIncludeAttribute(typeof(myClass1))]
[System.Xml.Serialization.XmlIncludeAttribute(typeof(myClass2))]
[System.CodeDom.Compiler.GeneratedCodeAttribute("MSBuild", "12.0.30723.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://www.andAnotherNamespace.com/")]
[System.Xml.Serialization.XmlRootAttribute(Namespace="http://www.andAnotherNamespace.com/", IsNullable=true)]
public abstract partial class AbstractFeatureType
{
private BoundingShapeType boundedByField;
private LocationPropertyType itemField;
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true)]
public BoundingShapeType boundedBy
{
get
{
return this.boundedByField;
}
set
{
this.boundedByField = value;
}
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("MSBuild", "12.0.30723.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://myNamespace.com")]
[System.Xml.Serialization.XmlRootAttribute("myClass1", Namespace="http://www.myNamespace.com/", IsNullable=false)]
public partial class myClass1 : AbstractFeatureType
{
}
[System.CodeDom.Compiler.GeneratedCodeAttribute("MSBuild", "12.0.30723.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://myNamespace.com")]
[System.Xml.Serialization.XmlRootAttribute("myClass2", Namespace="http://www.myNamespace.com/", IsNullable=false)]
public partial class myClass2 : AbstractFeatureType
{
}
Sorry for posting that much auto-generated code. I tried to omitt as much as possible but since I'm quite clueless I'm not sure what is necessary and what not.
And now my piece of work:
XmlSerializer serializer = new XmlSerializer(typeof(mainDatas));
XmlTextReader reader = new XmlTextReader(#".\myData.xml");
mainDatas dataObject = (mainDatas)serializer.Deserialize(reader);
FeaturePropertyType[] allObjects = dataObject.contain.FeatureCollection.featureMember;
foreach(FeaturePropertyType feature in allObjects)
{
if (feature.Item != null && feature.Item.GetType() == typeof(myClass1))
{
this.doSomething((myClass1)feature.Item));
}
else
{
this.doSomethingElse();
}
}
While debugging it shows me that allObjects contains 3 items of type FeaturePropertyType (i.e. the number of myClass1 and myClass2 in the xml-sheet as suspected) but the property Item of these items is null.
When I searched in the Internet many people suggested that it might be a problem with the namespaces. So I experimented a little bit with it changing it back and forth but without success. And I don't think it's a good idea to change to much in the auto-generated code, anyways.
I would be glad if anyone could give me some suggestions about this issue.
Greetings
TM
EDIT:
I had to edit my code because I forgot to write the inheritance of AbstractFeatureType by myClass1 and myClass2.
Try this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace ConsoleApplication1
{
class Program
{
const string FILENAME = #"c:\temp\test.xml";
static void Main(string[] args)
{
MainDatas mainDatas = new MainDatas() {
contains = new MainDatasContains() {
featureCollection = new FeatureCollection(){
id = "UHL",
boundedBy = 999.9,
featureMembers = new List<FeatureMember>() {
new FeatureMember() {
myClass1 = new MyClass1() {
id = "XXX0001"
}
},
new FeatureMember() {
myClass2 = new MyClass2() {
id = "XXX0001"
}
},
new FeatureMember() {
myClass1 = new MyClass1() {
id = "XXX0003"
}
}
}
}
}
};
XmlSerializer serializer = new XmlSerializer(typeof(MainDatas));
StreamWriter writer = new StreamWriter(FILENAME);
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("aan", "http://www.andAnotherNamespace.com/");
ns.Add("ons", "http://www.myOtherNamespace.com/");
ns.Add("", "http://www.myNamespace.com/");
serializer.Serialize(writer, mainDatas, ns);
writer.Flush();
writer.Close();
writer.Dispose();
XmlSerializer xs = new XmlSerializer(typeof(MainDatas));
XmlTextReader reader = new XmlTextReader(FILENAME);
MainDatas newMainDatas = (MainDatas)xs.Deserialize(reader);
}
}
[XmlRoot("mainDatas", Namespace = "http://www.myNamespace.com/")]
public class MainDatas
{
[XmlElement("contains")]
public MainDatasContains contains { get; set; }
}
[XmlRoot("contains")]
public class MainDatasContains
{
[XmlElement("FeatureCollection", Namespace = "http://www.myOtherNamespace.com/")]
public FeatureCollection featureCollection { get; set; }
}
[XmlRoot(ElementName = "FeatureCollection")]
public class FeatureCollection
{
[XmlAttribute("id", Namespace = "http://www.andAnotherNamespace.com/")]
public string id { get; set; }
[XmlElement("boundedBy", Namespace = "http://www.andAnotherNamespace.com/")]
public double boundedBy { get; set; }
[XmlElement("featureMember", Namespace = "http://www.andAnotherNamespace.com/")]
public List<FeatureMember> featureMembers { get; set; }
}
[XmlRoot("featureMember")]
public class FeatureMember
{
[XmlElement("myClass1")]
public MyClass1 myClass1 { get; set; }
[XmlElement("myClass2")]
public MyClass2 myClass2 { get; set; }
}
[XmlRoot("myClass1")]
public class MyClass1
{
[XmlAttribute("id", Namespace = "http://www.andAnotherNamespace.com/")]
public string id { get; set; }
}
[XmlRoot("myClass2")]
public class MyClass2
{
[XmlAttribute("id")]
public string id { get; set; }
}
}
Related
Adding namescpace prefix to XML
I have a number of POCO classes that are generating the required XML structure for serializtion to be passed as return in a SOAP WS. In selected elements I need to add namespace prefix/ alais to the elements. Is this possible? If yes how please? POCO Classes public partial class ValueTable { private List<ValueTableColumn> headerField; private row[] rowField; /// <remarks/> [System.Xml.Serialization.XmlArrayItemAttribute("column", IsNullable = false)] public List<ValueTableColumn> header { get { return this.headerField; } set { this.headerField = value; } } /// <remarks/> [XmlElement] public row[] row { get { return this.rowField; } set { this.rowField = value; } } } [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class row { private rowField[] fieldField; /// <remarks/> [System.Xml.Serialization.XmlElementAttribute("field")] public rowField[] field { get { return this.fieldField; } set { this.fieldField = value; } } } [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] public partial class rowField { private string textField; /// <remarks/> public string text { get { return this.textField; } set { this.textField = value; } } } Sample XML with required namespace prefixes/alias <v21:row> <v21:field> <v21:text>ID-1005896</v21:text> </v21:field> <v21:field> <v21:text>Smith</v21:text> </v21:field> <v21:field> <v21:text>64AF6547DDSEE</v21:text> </v21:field> </v21:row> Currently it is being returned with out the prefixes/alias. I appreciate any help :)
something like this should work: using System.Xml; using System.Xml.Serialization; using System.Xml.XPath; XmlSerializer serializer = new XmlSerializer(typeof(ValueTable)); XmlDocument doc = new XmlDocument(); XPathNavigator xPathNavigator = doc.CreateNavigator(); var nameSpaces = new XmlSerializerNamespaces(); nameSpaces.Add("yourPrefix", "http://your.namespace.com"); using (var xmlWriter = xPathNavigator.AppendChild()) { serializer.Serialize(xmlWriter, valueTableObject, nameSpaces); }
XML-Deserialization of a nested List C#
I am trying to deserialize a Xml File using the XmlSerializer. A part of my file looks like this: <bla> <ListOfListOfTest> <ListOfTest> <Test> </Test> </ListOfTest> </ListOfListOfTest> </bla> I tried different ways but it does not work. My first try looked like: public class bla { public bla() { ListOfListOfTest = new List<List<Test>>(); } [...] public List<List<Test>> ListOfListOfTest{ get; set; } } -> does not work. Second try: public class bla { public bla() { ListOfListOfTest = new List<List<Test>>(); } [..] public List<List<Test>> ListOfListOfTest { get; set; } [XmlArrayItemAttribute] public List<List<Test>> listOfListOfTest { get { return ListOfListOfTest ; } } } -> failed as well Third try: public class bla { public bla() { ListOfListOfTest = new List<Foo>(); } [...] public List<Foo> ListOfListOfTest { get; set; } } public class Foo { public Foo() { ListOfTest = new List<Test>(); } public List<Test> ListOfTest { get; set; } } -> failed... Failed means that the XmlSerializer does not fill the List during serializer.Deserialize(). I´m always getting a List with zero Elements in it. What am i doing wrong? thanks for your effort
To get to grips with how the XML will look when correctly deserialized, copy your XML: <bla> <ListOfListOfTest> <ListOfTest> <Test> </Test> </ListOfTest> </ListOfListOfTest> </bla> Create a class in C#. Click "Edit" at the top, then "Paste Special" then "Paste XML As Classes" while your cursor is inside the class. Visual Studio will correctly deserialize the XML for you and create the necessary classes. Use this to compare what you thought you needed, and what you actually need, in order to clarify for yourself how deserialization should work.
Something like this? using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml.Serialization; class Program { static void Main() { var xml = #"<bla> <ListOfListOfTest> <ListOfTest> <Test> </Test> </ListOfTest> </ListOfListOfTest> </bla>"; var bar = (Bar)new XmlSerializer(typeof(Bar)).Deserialize(new StringReader(xml)); Console.WriteLine(bar.Lists.Sum(_ => _.Items.Count)); // 1 } } [XmlRoot("bla")] public class Bar { [XmlArray("ListOfListOfTest")] [XmlArrayItem("ListOfTest")] public List<Foo> Lists { get; } = new List<Foo>(); } public class Foo { [XmlElement("Test")] public List<Test> Items { get; } = new List<Test>(); } public class Test { } The actual layout depends on which elements might be duplicated, and whether you need to be able to reproduce the exact organisation (vs just wanting all the Test items). In the code above, ListOfListOfTest is not expected to be duplicated, but there can be any number of ListOfTest or Test elements.
Visual Studio has a handy option - you should just copy-paste your xml and go to menu Edit > Paste Special > Paste XML As Classes. And Visual Studio will generate classes which you can use to serialize/deserialize your xml. In this particular case it will generate: [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] public partial class bla { private blaListOfListOfTest listOfListOfTestField; public blaListOfListOfTest ListOfListOfTest { get { return this.listOfListOfTestField; } set { this.listOfListOfTestField = value; } } } [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class blaListOfListOfTest { private blaListOfListOfTestListOfTest listOfTestField; public blaListOfListOfTestListOfTest ListOfTest { get { return this.listOfTestField; } set { this.listOfTestField = value; } } } [System.SerializableAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] public partial class blaListOfListOfTestListOfTest { private object testField; public object Test { get { return this.testField; } set { this.testField = value; } } } You can do some adjustments after that - e.g. remove type qualifiers or replace properties with auto-properties (which can be done with visual studio extensions). After few keystrokes: [Serializable] [DesignerCategory("code")] [XmlType(AnonymousType = true)] [XmlRoot(Namespace = "", IsNullable = false)] public partial class bla { public blaListOfListOfTest ListOfListOfTest { get; set; } } [Serializable] [DesignerCategory("code")] [XmlType(AnonymousType = true)] public partial class blaListOfListOfTest { public blaListOfListOfTestListOfTest ListOfTest { get; set; } } [Serializable] [DesignerCategory("code")] [XmlType(AnonymousType = true)] public partial class blaListOfListOfTestListOfTest { public object Test { get; set; } } And deserialization will look like: var serializer = new XmlSerializer(typeof(bla)); var blaObj = serializer.Deserialize(new StringReader(xmlString));
During C# deserialization, getting System.InvalidOperationException: < xmlns=''> was not expected
I'm new to XMLdeserialization. I used xsd.exe to generate object classes for performing a deserialization on an existing XML file. When I run my solution below, I get the error System.InvalidOperationException: < xmlns=''> was not expected on the s = (NewDataSet)xs.Deserialize(sr) call. I looked this error up on Stack Overflow, and everyone says it's in the XMLRootAttribute line. [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] How can I correct this line? Or where can I find some documentation that explains how to correct it? Also, why doesn't xsd.exe generate the correct XmlRootAttribute line in the first place? Am I invoking this utility wrong? Or are there some situations the xsd.exe utility can't handle? public class Program { static void Main(string[] args) { SortedSet<string> symbolsEstablished = new SortedSet<string>(); GetXmlDataSet("Expt 2buy.xml", ref symbolsEstablished); } public static void GetXmlDataSet(string fileName, ref SortedSet<string> symbols) { XmlSerializer xs = new XmlSerializer(typeof(NewDataSet)); StreamReader sr = new StreamReader(#"C:\Users\mehl\AppData\Roaming\Fidelity Investments\WealthLabPro\1.0.0.0\Data\DataSets\" + fileName); NewDataSet s = (NewDataSet)xs.Deserialize(sr); Console.WriteLine(s.Items[0].DSString); sr.Close(); } [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] public partial class DataSet { private string nameField; private string scaleField; private string barIntervalField; private string dSStringField; private string providerNameField; [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public string Name { get { return this.nameField; } set { this.nameField = value; } } [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public string Scale { get { return this.scaleField; } set { this.scaleField = value; } } [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public string BarInterval { get { return this.barIntervalField; } set { this.barIntervalField = value; } } [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public string DSString { get { return this.dSStringField; } set { this.dSStringField = value; } } [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public string ProviderName { get { return this.providerNameField; } set { this.providerNameField = value; } } } [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)] public partial class NewDataSet { private DataSet[] itemsField; [System.Xml.Serialization.XmlElementAttribute("DataSet")] public DataSet[] Items { get { return this.itemsField; } set { this.itemsField = value; } } } } The entire above code segment is wrapped in a screener2wl namespace. And here's the XML file I'm trying to deserialize: <?xml version="1.0"?> <DataSet xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <Name>Expt 2buy</Name> <Scale>Daily</Scale> <BarInterval>0</BarInterval> <DSString>AAL,AFSI,BEN,BIG,BLKB,CDK,COHR,CRUS,EGP,EPE,ETH,FB,HUM,LSTR,MDP,MSI,NYT,TAST,TER,TSO,TXN,UTHR,VASC,VLO,WRI,</DSString> <ProviderName>FidelityStaticProvider</ProviderName> </DataSet>
Using xml linq : using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml; using System.Xml.Linq; namespace ConsoleApplication1 { class Program { const string FILENAME = #"c:\temp\test.xml"; static void Main(string[] args) { XDocument doc = XDocument.Load(FILENAME); DataSet ds = doc.Descendants("DataSet").Select(x => new DataSet() { nameField = (string)x.Element("Name"), scaleField = (string)x.Element("Scale"), barIntervalField = (string)x.Element("BarInterval"), dSStringField = (string)x.Element("DSString"), providerNameField = (string)x.Element("ProviderName") }).FirstOrDefault(); } } public partial class DataSet { public string nameField { get; set; } public string scaleField { get; set; } public string barIntervalField { get; set; } public string dSStringField { get; set; } public string providerNameField { get; set; } } }
I got to thinking ... isn't it odd xsd.exe would provide a code generated solution that defines two independent XmlRootAttribute nodes? Can an XML file even have two Root Nodes? Maybe the solutions xsd.exe generates shouldn't be taken too literally. :-) So after editing its solution, and removing one part with a second XmlRootAttribute defined, I got the solution below, which works. namespace screener2wl { public class Program { static void Main(string[] args) { SortedSet<string> symbolsEstablished = new SortedSet<string>(); GetXmlDataSet("Expt 2buy.xml", ref symbolsEstablished); } public static void GetXmlDataSet(string fileName, ref SortedSet<string> symbols) { XmlSerializer xs = new XmlSerializer(typeof(DataSet)); StreamReader sr = new StreamReader(#"C:\Users\mehl\AppData\Roaming\Fidelity Investments\WealthLabPro\1.0.0.0\Data\DataSets\" + fileName); DataSet s = (DataSet)xs.Deserialize(sr); Console.WriteLine(s.DSString); sr.Close(); } [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)] [System.Xml.Serialization.XmlRootAttribute(IsNullable = false)] public class DataSet { private string nameField; private string scaleField; private string barIntervalField; private string dSStringField; private string providerNameField; [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public string Name { get { return this.nameField; } set { this.nameField = value; } } [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public string Scale { get { return this.scaleField; } set { this.scaleField = value; } } [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public string BarInterval { get { return this.barIntervalField; } set { this.barIntervalField = value; } } [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public string DSString { get { return this.dSStringField; } set { this.dSStringField = value; } } [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)] public string ProviderName { get { return this.providerNameField; } set { this.providerNameField = value; } } } } } Bottom line, use the code solutions xsd.exe generates from your XML data file as a guide, not a truth. It's a great tool, but needs to be used with a grain of salt. ... welcome your comments on my XMLdeserialization problem.
XmlSerializer doesn't fill in values
I created classes from a DTD (over XSD and xsd.exe) for my C# project, so I could easily deserialize them into a model class in my code. This is roughly how I do it: XmlReaderSettings readerSettings = new XmlReaderSettings(); readerSettings.DtdProcessing = DtdProcessing.Parse; XmlReader reader = XmlReader.Create(tipsfile.FullName, readerSettings); XmlRootAttribute xRoot = new XmlRootAttribute(); xRoot.ElementName = "Tips"; xRoot.IsNullable = true; XmlSerializer serializer = new XmlSerializer(typeof(Tips), xRoot); Tips tips = (Tips)serializer.Deserialize(reader); reader.Close(); But, upon inspection of tips, I see that it holds no values at all from the original XML file. Also, I tried setting a breakpoint on the set-Body of a property of Tips, and it is never reached, although I know for sure that it has a value in the original XML file. Why is the file not correctly deserialized into the class? Is something missing in my code? Edit: Here is the Tips.cs file, which was auto-generated from the XSD using System.Xml.Serialization; namespace MyNs.Model { [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/caravan_1")] [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/caravan_1", IsNullable = false)] public partial class Tips { private Chapter[] chapterField; [System.Xml.Serialization.XmlElementAttribute("Chapter")] public Chapter[] Chapter { get { return this.chapterField; } set { this.chapterField = value; } } } [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true, Namespace = "http://tempuri.org/caravan_1")] [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/caravan_1", IsNullable = false)] public partial class Chapter { private string headingField; private CarType[] carTypesField; private Section[] sectionField; private string countryField; private string languageField; public string Heading { get { return this.headingField; } set { this.headingField = value; } } [System.Xml.Serialization.XmlArrayItemAttribute("CarType", IsNullable = false)] public CarType[] CarTypes { get { return this.carTypesField; } set { this.carTypesField = value; } } [System.Xml.Serialization.XmlElementAttribute("Section")] public Section[] Section { get { return this.sectionField; } set { this.sectionField = value; } } [System.Xml.Serialization.XmlAttributeAttribute()] public string Country { get { return this.countryField; } set { this.countryField = value; } } [System.Xml.Serialization.XmlAttributeAttribute()] public string Language { get { return this.languageField; } set { this.languageField = value; } } } [... and so on ...] And a sample XML file: <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE Tips SYSTEM "caravan_1.dtd"> <Tips> <Chapter Country="dafghagt" Language="de"> <Heading>fgagasgargaergarg</Heading> <Section id="1"> <Heading>afdhwr6u5taehtaqh5</Heading> <SubSection id="1"> <Heading>46k46kw6jhadfgadfha</Heading> <Table> <Row id="1"> <Heading>sgjsfgjsgfh443q572q356</Heading> <Items> <Item car="motor1" id="1"> <BodyText color="red">130*</BodyText> <Subscript>3</Subscript> </Item> </Items> </Row> </Table> </SubSection> </Section> </Chapter> </Tips>
StreamReader sw = new StreamReader(fileName, false); XmlTextReader xmlw = new XmlTextReader(sw); XmlSerializer writer = new XmlSerializer( type, GetOverrides(), extraTypes, null, null); object o = writer.Deserialize(xmlw); As per my comment, get overrides is just a method that contains something similar to your xml root attribute, I can show you this too if necessary EDIT: an example of extra types public Type[] GetTypes() { return new Type[] { typeof(Class1), typeof(Class2)}; } EDIT2: get overrides returns (Note this is untested) XmlAttributes attribs = new XmlAttributes(); //attribs.XmlRoot - can edit root here (instead of xmlrootattribute) attribs.XmlElements.Add(myAttribute); XmlAttributeOverrides myOverride = new XmlAttributeOverrides(); myOverride.Add(typeof(Tips), "Tips", attribs); return myOverride
Your object may not be identical to the xml model. In that case, you need map the properties of your class to the xml fields. I am giving you a quick example I had in one of my projects which may give you bit more information. namespace DatabaseModel { [Description("Represents the selected nodes in the Coverage pane")] [Serializable()] [XmlRootAttribute("XmlCoverage", Namespace = "GISManager", IsNullable = false)] public class TXmlCoverage : IXmlPolygon { [XmlArray(ElementName = "sbets"), XmlArrayItem(ElementName = "sbet")] public List SbetsSelected { get; set; } [XmlArray(ElementName = "sdcs"), XmlArrayItem(ElementName = "sdc")] public List SdcsSelected { get; set; } [XmlElementAttribute(ElementName = "area")] public Boolean IsAreaSelected { get; set; } [XmlElementAttribute(ElementName = "fpath")] public Boolean IsFlightPathSelected { get; set; } [XmlElementAttribute(ElementName = "fpoly")] public Boolean IsFlightPolySelected { get; set; } [XmlElementAttribute(ElementName = "mpoly")] public Boolean IsMinePolySelected { get; set; } [XmlElementAttribute(ElementName = "bldg")] public Boolean IsBuildingsSelected { get; set; } [XmlElementAttribute(ElementName = "hgt")] public Boolean IsHeightSelected { get; set; } [XmlIgnore()] public Boolean ArePolygonsSelected { get { return IsMinePolySelected && IsBuildingsSelected && IsHeightSelected; } } public TXmlCoverage() { SbetsSelected = new List<String>(); SdcsSelected = new List<String>(); IsAreaSelected = false; IsFlightPathSelected = false; IsFlightPolySelected = false; } } }
So it turns out the problem is namespaces. Because my XML has no root namespace: <Tips> but the definition of my Model contained one: [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://tempuri.org/caravan_1", IsNullable = false)] the Serializer didn't match any elements together. When removing the namespace attribute, it worked fine. So now, I reworked the complete model and excluded any attributes that were not absolutely necessary (as it turns out, all but one were), so now every Property has just one Attribute: XmlElement and consorts. using System.Xml.Serialization; namespace MyNs.Model { [XmlRoot("Tips")] public partial class Tips { [XmlElement("Chapter")] public Chapter[] Chapter { get; set; } } [XmlRoot("Chapter")] public partial class Chapter { [XmlElement("Heading")] public string Heading { get; set; } [XmlElement("CarType")] public CarType[] CarTypes { get; set; } [XmlElement("Section")] public Section[] Section { get; set; } [XmlAttribute("Country")] public string Country { get; set; } [XmlAttribute("Language")] public string Language { get; set; } } [... and so on ...] With a simple deserialization it works just fine now: XmlReaderSettings readerSettings = new XmlReaderSettings { DtdProcessing = DtdProcessing.Parse }; XmlSerializer serializer = new XmlSerializer(typeof(Tips)); using (XmlReader reader = XmlReader.Create(fromXmlFile.FullName, readerSettings)) { Tips tips = (Tips)serializer.Deserialize(reader); return tips; }
How to Deserialize this Xml file?
I have this Xml file, and I need to Deserialize it back to a class. The problem is: what is the right structure/design of this class considering that the count of the Xml element (RowInfo) is not constant? The Xml File: <?xml version="1.0"?> <SomeObject xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" > <Layers> <Layer Id="0"> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1</RowInfo> <RowInfo>1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1</RowInfo> <RowInfo>1,1,1,0,0,1,1,1,1,1,1,1,1,1,0,0,1,0,0,1</RowInfo> <RowInfo>1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,1</RowInfo> </Layer> </Layers> </SomeObject> Appreciate your help. Thanks. Edit1:also considering that (Layers) may contains more than one layer.
Something like the following - names will need to be changed to protect the innocent: Class structure after comment public class SomeObject { public List<Layer> Layers {get;set;} } public class Layer { public int Id {get;set;} public List<RowInfo> RowInfos {get;set;} } public class RowInfo { public List<Row> Rows {get;set;} } public class Row { public int RowData {get;set;} }
This should work as you want: public class SomeObject { public List<Layer> Layers { get; set; } } public class Layer { [XmlAttribute] public int Id { get; set; } [XmlElement("RowInfo")] public List<RowInfo> RowInfos { get; set; } } public class RowInfo { [XmlText] public string Info { get; set; } // you'll need to parse the list of ints manually } The only difference is the encoding but you should be able to work around it.
If the count of RowInfo is not constant, use a List in your class.
XmlSerializer serializer = new XmlSerializer(typeof(SomeObject)); you can use XmlSerializer with the following code and call Deserialize :) //------------------------------------------------------------------------------ // <auto-generated> // This code was generated by a tool. // Runtime Version:2.0.50727.4952 // // Changes to this file may cause incorrect behavior and will be lost if // the code is regenerated. // </auto-generated> //------------------------------------------------------------------------------ using System.Xml.Serialization; // // This source code was auto-generated by xsd, Version=2.0.50727.3038. // /// <remarks/> [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)] [System.Xml.Serialization.XmlRootAttribute(Namespace="", IsNullable=false)] public partial class SomeObject { private SomeObjectLayers layersField; /// <remarks/> public SomeObjectLayers Layers { get { return this.layersField; } set { this.layersField = value; } } } /// <remarks/> [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)] public partial class SomeObjectLayers { private SomeObjectLayersLayer layerField; /// <remarks/> public SomeObjectLayersLayer Layer { get { return this.layerField; } set { this.layerField = value; } } } /// <remarks/> [System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "2.0.50727.3038")] [System.SerializableAttribute()] [System.Diagnostics.DebuggerStepThroughAttribute()] [System.ComponentModel.DesignerCategoryAttribute("code")] [System.Xml.Serialization.XmlTypeAttribute(AnonymousType=true)] public partial class SomeObjectLayersLayer { private decimal[] rowInfoField; private int idField; private bool idFieldSpecified; /// <remarks/> [System.Xml.Serialization.XmlElementAttribute("RowInfo")] public decimal[] RowInfo { get { return this.rowInfoField; } set { this.rowInfoField = value; } } /// <remarks/> [System.Xml.Serialization.XmlAttributeAttribute()] public int Id { get { return this.idField; } set { this.idField = value; } } /// <remarks/> [System.Xml.Serialization.XmlIgnoreAttribute()] public bool IdSpecified { get { return this.idFieldSpecified; } set { this.idFieldSpecified = value; } } }
I would say use LINQ-to-Xml. Have a constructor on your object that can take an xlement then do Something along the lines of public class YourObject() { public IEnumerable<Layer> Layers { get; set; } public int Id { get; set; } public YourObj(XElement x) { this.Id = int.Parse(x.Attribute("Id").ToString()); this.Layers = from layer in x.Elements("Layer") select new Layer(layer); } } var objs = (from c in XElement.Load("your.xml").Elements("layer") select new YourObject(c)).ToList() ;
Checkout a tool called XSD.exe it come with visual studio and will allow you to generate code form an xml file. You should see it on the program files menu next to visual studio.