I'm trying to deserialize an XML into a C# object that has numerous elements of the same type. I've pared down the contents for clarity. My C# class looks like this:
[XmlInclude(typeof(RootElement))]
[XmlInclude(typeof(Entry))]
[Serializable, XmlRoot("Form")]
public class DeserializedClass
{
public List<Entry> listEntry;
public RootElement rootElement { get; set; }
}
Then I define the Entry and RootElement classes as follows:
public class RootElement
{
public string rootElementValue1 { get; set; }
public string rootElementValue2 { get; set; }
}
public class Entry
{
public string entryValue1 { get; set; }
public string entryValue2 { get; set; }
}
And the structure of the XML I'm trying to deserialize looks like this:
<Entry property="value">
<entryValue1>Data 1</entryValue1>
<entryValue2>Data 2</entryValue2>
<RootElement>
<rootElementValue1>Data 3</rootElementValue1>
<rootElementValue2>Data 4</rootElementValue2>
</RootElement>
<RootElement>
<rootElementValue1>Data 5</rootElementValue1>
<rootElementValue2>Data 6</rootElementValue2>
</RootElement>
</Entry>
As you can see there will be multiple RootElement elements that I want to deserialize into the List of the C# object. To deserialize I use the following:
XmlSerializer serializer = new XmlSerializer(typeof(DeserializedClass));
using (StringReader reader = new StringReader(xml))
{
DeserializedClass deserialized = (DeserializedClass)serializer.Deserialize(reader);
return deserialized;
}
Any ideas how to fix it?
I tweaked your classes a little bit for your deserialization code to work:
[Serializable, XmlRoot("Entry")]
public class DeserializedClass
{
public string entryValue1;
public string entryValue2;
[XmlElement("RootElement")]
public List<RootElement> rootElement { get; set; }
}
public class RootElement
{
public string rootElementValue1 { get; set; }
public string rootElementValue2 { get; set; }
}
Now it works fine.
I don't know why you declared your XmlRoot as "Form" as there is no element in the XML with that name so I replaced it with "Entry".
You cannot use an Entry class with entryvalue1 and entryvalue2 properties because they are direct children of the root (Event) and there is no child as Entry. In short your classes must reflect the hierarchy of the XML so that deserialization can work properly.
Related
I want to convert a c# class to an xml file without declaring default values in it. If I declare values on every propery in the class I got it to work and the XML has all the properties in it. The primarydata is my class with properties in it.
var pD = new PrimaryData();
XmlSerializer serializerPrimaryData = new XmlSerializer(typeof(PrimaryData));
serializerPrimaryData.Serialize(File.Create(xmlLocation), pD,ns);
But I dont want to declare any values.
If i run this code I get just:
<?xml version="1.0"?>
<PrimaryData />
I don't get the properties in the class as you can see. So how can I get the properties in the class without declaring them to a default value?
Any suggestions?
I have followed this guide: https://codehandbook.org/c-object-xml/
But he is declaring default values to his class.
public class PrimaryData
{
public PrimaryData();
public string BatchId { get; set; }
public CurrentOperation CurrentOperation { get; set; }
public Heat Heat { get; set; }
public string MaterialId { get; set; }
public List<Operation> Operations { get; set; }
public OrderInfo OrderInfo { get; set; }
public Plate Plate { get; set; }
}
Just set default values.
public class Employee
{
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
}
public static void Main(string[] args)
{
var employee = new Employee();
var sw = new StringWriter();
var se = new XmlSerializer(employee.GetType());
var tw = new XmlTextWriter(sw);
se.Serialize(tw, employee);
Console.WriteLine(sw.ToString());
Console.Read();
}
Result
<?xml version="1.0" encoding="utf-16"?>
<Employee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<FirstName />
<LastName />
</Employee>
Second solution is to set XmlElement(IsNullable = true)
public class Employee
{
[XmlElement(IsNullable = true)]
public string FirstName { get; set; }
[XmlElement(IsNullable = true)]
public string LastName { get; set; }
}
I have no clue what you are trying to do ...
XML serialization just makes a mirror of the object in different structure (aka XML - object will be represented by structured text).
If your class has no properties, nothing will be serialized to XML but only the base empty object.
My suggestion is to make a class with Dictionary<string, object> as property. Then you will be able to write into the Dictionary and serialize it.
But, it has some drawbacks. XML Serialization (if I remember correctly) does not support Dictionaries, so I would go with DataContract instead.
That might work :)
[DataContract]
public class PrimaryData
{
[DataMember(Name = "Data", Order = 0, IsRequired = true)]
public Dictionary<string, object> Data { get; set; }
}
You should add this annotation to your properties:
[XmlElement(IsNullable = true)]
public string Prop { get; set; }
The result in your xml should be something like this:
<Prop xsi:nil="true" />
I have the following XML:
<MyType>
<MyProperty1>Value 1</MyProperty1>
<MyProperty2>Value 2</MyProperty2>
<MyNestedXml>
<h1>Heading</h1>
<p>Lorum</p>
<p>Ipsum</p>
</MyNestedXml>
</MyType>
This can be deserialized to XML in C# by creating classes and adding attributes as below:
[Serializable]
public class MyType
{
[XmlElement("MyProperty1")
public string MyProperty1 { get; set; }
[XmlElement("MyProperty2")
public string MyProperty2 { get; set; }
[XmlIgnore]
public string MyNestedXml { get; set; }
}
However, the inner XML within the <MyNestedXml> element varies and doesn't follow a consistent structure which I can effectively map using attributes.
I don't have control over the XML structure unfortunately.
I have tried using an [XmlElement("MyNestedXml") with an XmlNode type but this results in the first child node being deserialized instead of the entire inner XML.
I have also tried deserializing to a type of string but that throws an InvalidOperationException:
"Unexpected node type Element. ReadElementString method can only be called on elements with simple or empty content."
The problem is that the content of the MyNestedXml element could be an array of Elements sometimes but could be simple or empty content at other times.
Ideally I could use a different serialization attribute such as [XmlAsString] to skip serialization altogether and just assign the inner XML as is.
The intended result would be a class of type MyType having a property MyProperty1 = "Value 1", a property MyProperty2 = "Value 2", and a property MyNestedXml = "<h1>Heading</h1><p>Lorum</p><p>Ipsum</p>".
Make it an XmlElement property with the XmlAnyElement attribute and the serializer will deserialize an arbitrary XML structure.
[XmlRoot("MyType")]
public class MyType
{
[XmlElement("MyProperty1")]
public string MyProperty1 { get; set; }
[XmlElement("MyProperty2")]
public string MyProperty2 { get; set; }
[XmlAnyElement("MyNestedXml")]
public XmlElement MyNestedXml { get; set; }
}
I have managed to solve this...
I created a class to deserialize to:
public class RichText : IXmlSerializable
{
public string Raw { get; set; }
public XmlSchema GetSchema()
{
return null;
}
public void ReadXml(XmlReader reader)
{
Raw = reader.ReadInnerXml();
}
public void WriteXml(XmlWriter writer)
{
writer.WriteString(Raw);
}
}
This allows me to have the following class definition:
[Serializable]
public class MyType
{
[XmlElement("MyProperty1")
public string MyProperty1 { get; set; }
[XmlElement("MyProperty2")
public string MyProperty2 { get; set; }
[XmlElement("MyNestedXml")]
public RichText MyNestedXml { get; set; }
}
I can now use InstanceOfMyType.MyNestedXml.Raw to get the inner XML as string. If I so choose I can override the .ToString() method of RichText to return the Raw property also.
Hope this helps others out in the future.
You're going to have to use an XMLReader if the structure of the XML isn't consistent.
I'd suggest you look at this link for a recursion pattern on how to use an XMLReader. It is probably also going to be the fastest way to parse the XML as well.
Traverse a XML using Recursive function
I have an auto generated xml file with the following format.
<?xml version="1.0"?>
<School>
<Classes numberOfFields="5">
<Class name="10" dataType="double">
<Section value="A"/>
<Section value="B"/>
<Section value="C"/>
</Class>
<Class dataType="double"/>
<Class dataType="double"/>
<Class dataType="double"/>
<Class dataType="double"/>
</Classes>
</School>
I deserialize using "XmlDeserializer" as follows
School schoolResult = (School)xmlSerializer.Deserialize(stream);
XmlRootElement contains a collection of "Class" under "Classes" tag and further each "Class" would contain Collection of "Section".
And in C#, I have declared like this to deserialize "Classes" into a List of classes.
[XmlArray("Classes")]
[XmlArrayItem("Class", typeof(Class))]
public List<Class> Classes {};
Now to further deserialize Class into List of Sections, I have added the code as below.
[XmlArray("Class")]
[XmlArrayItem(ElementName="Section")]
public List<Section> ClassSections {};
My problem is I couldn't get the List of Sections values properly. Because I have "Class" as a class name in the first part and in second part I have mentioned same "Class" as Array element. So could any one tell how can I properly Deserialize my "School" object using "XmlSerializer" to get all the values properly.
Note: I cannot have a Array root tag like "Sections" under "Class". Because my xml document is auto generated. I cannot specify my own format.
Thanks...
try this :
public class School
{
[XmlAttribute]
public int numberOfFields { get; set; }
[XmlArray("Classes")]
[XmlArrayItem("Class", typeof(Class))]
public List<Class> Classes { get; set; }
}
public class Class
{
[XmlAttribute]
public string name { get; set; }
[XmlAttribute]
public string dataType { get; set; }
[XmlElement("Section")]
public List<Section> ClassSections { get; set; }
}
public class Section
{
[XmlAttribute]
public string value { get; set; }
}
* EDIT #1 **
--------------- Update Structure due to NumberOfFields is not readed ----------------
in my opinion it's not correct structure, but when u said it's an auto generated XML file, i think it simplest way to read it.
public class School
{
[XmlElement("Classes")]
public List<ArrayClass> Classes { get; set; }
}
public class ArrayClass
{
[XmlAttribute]
public int numberOfFields { get; set; }
[XmlElement("Class")]
public List<Class> Class { get; set; }
}
static void Main(string[] args)
{
var xml ="<?xml version=\"1.0\"?><School><Classes numberOfFields=\"5\"><Class name=\"10\" dataType=\"double\"><Section value=\"A\"/><Section value=\"B\"/><Section value=\"C\"/></Class><Class dataType=\"double\"/><Class dataType=\"double\"/><Class dataType=\"double\"/><Class dataType=\"double\"/></Classes></School>";
School result;
var serializer = new XmlSerializer(typeof(School));
var xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
using (var reader = new XmlNodeReader(xmlDoc))
{
result = (School)serializer.Deserialize(reader);
}
}
public class School
{
[XmlArray("Classes")]
[XmlArrayItem("Class")]
public List<Class> Classes { get; set; }
}
public class Class
{
[XmlElement("Section")]
public List<Section> ClassSections { get; set; }
}
public class Section
{
[XmlAttribute("value")]
public string Value { get; set; }
}
I have XML-based config for application shortcuts bindings. i need to parse it.
<ShortcutBinding>
<ShortcutHandler Name ="Retail.Application.Documents.Outcome.Presentation.OutcomePresenter">
<Shortcut Name="EditHeader">
<Key>CTRL</Key>
<Key>F4</Key>
</Shortcut>
<Shortcut Name="EditItem">
<Key>F4</Key>
</Shortcut>
</ShortcutHandler>
</ShortcutBinding>
I know that .Net has attributes for deserializing XML into objects.
Can anyone write complete example for such deserialization, using attributes.
public class ShortcutBinding
{
public ShortcutHandler ShortcutHandler { get; set; }
}
public class ShortcutHandler
{
[XmlAttribute]
public string Name { get; set; }
[XmlElement("Shortcut")]
public List<Shortcut> Shortcuts { get; set; }
}
public class Shortcut
{
[XmlAttribute]
public string Name { get; set; }
[XmlElement("Key")]
public List<string> Keys { get; set; }
}
Deserializing:
XmlSerializer serializer = new XmlSerializer(typeof(ShortcutBinding));
var binding = (ShortcutBinding)serializer.Deserialize(XmlReader.Create(path));
I have xml with several items, for example:
<TestObject>
<TestElement1/>
<TestElement2/>
</TestObject>
<TestObject>
<TestElement1/>
<TestElement2/>
</TestObject>
Also I have class:
class TestClass {
public int TestElement1 { get; set; }
public int Element { get; set; }
}
If I do:
XmlSerializer s = new XmlSerializer(typeof(List<TestClass>));
List<TestClass> list = (List<TestClass>)s.Deserialize("myXml.xml");
After it I get list with objects TestClass, but property Element didn't set. How I must change serialization, if I want to set TestElement2 in Element field?
You need to decorate the Element property with an [XmlElement] attribute:
[XmlRoot("TestObject")]
class TestClass {
public int TestElement1 { get; set; }
[XmlElement("TestElement2")]
public int Element { get; set; }
}
Try XmlElement attribute
public class TaxRates{
[XmlElement(ElementName = "TaxRate")]
public decimal ReturnTaxRate;
}
see Controlling XML Serialization Using Attributes