C# Deserialize XML to a list of ChildClasses - c#

I have a XML from a 3rd party software that I have to deserialize, but I have the spec of the XML.
At a certain point I have a node that contains a bunch of different Nodes of different types. I have to deserialize this Node (Vehicles) as a list. Each of the child nodes is one subclass of the class Vehicle
public List<Vehicle> Vehicles = new List<Vehicles>();
the definition of the class is as following
public class Vehicle
{
public string Vehicletype { get; set; }
public virtual bool Drive() { return true; }
}
public class Car:Vehicle
{
public int NumberOfDoors { get; set; }
public override bool Drive() { return false; }
}
public class Boat:Vehicle
{
public int NumberOfSeats { get; set; }
}
The definition of the XML looks like this
<vehicles>
<car NumberOfDoors="4" />
<car NumberOfDoors="3" />
<boat NumberOfSeats="1024" />
<boat NumberOfSeats="20" />
<car NumberOfDoors="5" />
</vehicles>
At a certain point I have to loop through them and let them "Drive". I don't have the experience With XMLSchema definitions. Now I am using The vehicleType in a factory and some other things. It's basically becoming a mess.
I would need a suggestion how to let the Serializer do this instead of me. I doubt that I am the first one to have this issue.

Firstly, you have to mark NumberofSeats and NumberOfDoors with the XmlAttribute attribute to tell XmlSerializer that these properties should appear as XML attributes:
public class Car : Vehicle
{
[XmlAttribute]
public int NumberOfDoors { get; set; }
public override bool Drive() { return false; }
}
public class Boat : Vehicle
{
[XmlAttribute]
public int NumberOfSeats { get; set; }
}
Next, if <vehicles> appears as an XML Node inside some containing root element, you can make your public List<Vehicle> Vehicles appear as a member inside the corresponding container class, and apply an XmlArray attribute to it to indicate that the list should be serialized in two levels, and XmlArrayItem attributes to inform XmlSerializer of the possible of vehicles that might be encountered in the list along with the start tag to use for each:
public class VehiclesContainer // Your container class
{
[XmlArray("vehicles")]
[XmlArrayItem("vehicle", typeof(Vehicle))]
[XmlArrayItem("car", typeof(Car))]
[XmlArrayItem("boat", typeof(Boat))]
public List<Vehicle> Vehicles = new List<Vehicle>();
}
On the other hand, <vehicles> is the root node of the XML document and there is no containing node, you can introduce a root node class containing the list of vehicles, then apply multiple XmlElement attributes to indicate that the list should be serialized in one level rather than two along with the start tag to use for each possible vehicle type:
[XmlRoot("vehicles")]
public class VehicleList
{
[XmlElement("vehicle", typeof(Vehicle))]
[XmlElement("car", typeof(Car))]
[XmlElement("boat", typeof(Boat))]
public List<Vehicle> Vehicles = new List<Vehicle>();
}
Having done this, XmlSerializer will automatically deserialize your class hierarchy.
For more information, see here.

Related

XML attribute for ignoring class tag when serializating object c#

I need to get an xml output like this:
<Partners>
<Partner>
<PartnerType>SomeStringValue</PartnerType>
<PartnerID>SomeStringValue</PartnerID>
<PartnerIDType>SomeStringValue</PartnerIDType>
<PartnerID>BTW BEXXXXXXXXXX</PartnerID>
<PartnerIDType>SomeStringValue</PartnerIDType>
</Partner>
<Partner>
<PartnerType>SomeStringValue</PartnerType>
<PartnerID>SomeStringValue</PartnerID>
<PartnerIDType>SomeStringValue</PartnerIDType>
<PartnerID>BTW BEXXXXXXXXXX</PartnerID>
<PartnerIDType>SomeStringValue</PartnerIDType>
</Partner>
</Partners>
It has to be possible to add multiple PartnerID tags and multiple PartnerIDType tags in the parner tag. To get this result I was using a list of PartnerIdInfo. I had my classes like this:
public class Someclass
{
public List<Partner> Partners {get; set;}
}
public class Partner
{
public string PartnerType { get; set; }
[XmlElement("PartnerIdInfo")]
public List<PartnerIdInfo> PartnerIDInfos { get; set; }
}
public class PartnerIdInfo
{
public string PartnerID { get; set; }
public string PartnerIDType { get; set; }
}
The [XmlElement("PartnerIdInfo")] tag is for not showing the tag from the list property in the partner class. But it is still showing the tag :
<Partners>
<Partner>
<PartnerType>SomeStringValue</PartnerType>
<PartnerIdInfo>
<PartnerID>SomeStringValue</PartnerID>
<PartnerIDType>SomeStringValue</PartnerIDType>
</PartnerIdInfo>
<PartnerIdInfo>
<PartnerID>BTW BEXXXXXXXXXX</PartnerID>
<PartnerIDType>SomeStringValue</PartnerIDType>
</PartnerIdInfo>
</Partner>
</Partners>
Is there an attibute (or another solution) to do this? I prefer not to rewrite my code and fill everything in the code through the use of XmlDocument and XmlNode... Or will this be the only possible solution for this outcome?
Your problem is that you want the serializer to combine the value of Partner.PartnerType with the repeating values of Partner.PartnerIDInfos[*].PartnerID and Partner.PartnerIDInfos[*].PartnerIDType into a single omnibus <Partner> element. Unfortunately, this simply is not implemented. The content of each PartnerIdInfo will always be serialized within its own element.
Several workarounds can be found in the answers to the questions Keep sort when deserialize and serialize XML using XmlSerializer and Xml Deserialization - Merging two elements into a single List<T> object. In particular using a polymorphic array of simple elements with two possible types corresponding to <PartnerID> and <PartnerIDType> should meet your needs. You will need to modify Partner to mark the PartnerIDInfos as ignored and use a surrogate array for the elements:
public class Partner
{
[XmlElement(Order = 1)]
public string PartnerType { get; set; }
[XmlIgnore]
public List<PartnerIdInfo> PartnerIDInfos { get; set; }
[XmlElement(typeof(PartnerID), Order = 2), XmlElement(typeof(PartnerIDType), Order = 2)]
public StringElementBase [] XmlPartnerIDInfos
{
get => PartnerIDInfos?.SelectMany(p => new StringElementBase [] { new PartnerID { Value = p.PartnerID }, new PartnerIDType { Value = p.PartnerIDType } }).ToArray();
set => PartnerIDInfos = value?.OfType<PartnerID>().Zip(value.OfType<PartnerIDType>(), (id, type) => new PartnerIdInfo { PartnerID = id.Value, PartnerIDType = type.Value }).ToList();
}
}
public abstract class StringElementBase { [XmlText] public string Value { get; set; } } // From https://stackoverflow.com/a/48130816/3744182
public class PartnerID : StringElementBase { }
public class PartnerIDType : StringElementBase { }
Notes:
Marking StringElementBase.Value with [XmlText] causes the value to be serialized as text rather than nested markup.
StringElementBase [] XmlPartnerIDInfos should be an array rather than a List<StringElementBase> because XmlSerializer will not set back the value of a resizable collection such as List<T> after populating it.
Setting XmlElement.Order is optional but does indicate that <PartnerType> not come between any of the <PartnerID> and <PartnerIDType> elements.
In the setter for XmlPartnerIDInfos I don't attempt to validate that there are an equal number of PartnerID and PartnerIDType elements, or that the values alternate. You could add that, if you wish.
Demo fiddle here.

Decoupling Pattern

After looking at major pattern designs, I can't seem to make up my mind around the best to one to decouple classes in a big hierarchy system, specially were it concerns on avoiding injecting a Parent property in EVERY object along the way.
Some of the premises are:
A child might me removed from one parent and added to another.
Somewhere down the hierarchy, I need to access Parent of type X.
As mentioned before, I would like to avoid injecting a Parent (either by property or constructor) to it's children.
I have 1..1 and 1...N cardinalities.
The hierarchy from root to furthest leaf is quite extent.
If it was a small project, I would be fine with this (pseudo code):
public abstract class BaseObject()
{
public BaseObject Parent { get; set; }
}
public class RootObject() : BaseObject
{
public int Id { get; }
public ParentObject[] Parent { get; set; }
}
public class ParentObject() : BaseObject
{
public int Id { get; }
public ChildObject[] Parent { get; set; }
}
public class ChildObject() : BaseObject
{
public int Id { get; }
public void DoSomething()
{
//...navigate through Parent to get RootObject (or any other type in between that I might need)...
}
}
Can anyone point me out to the right direction?
All these requirements remind me graph data structure:
A child might me removed from one parent and added to another.
Somewhere down the hierarchy, I need to access Parent of type X.
As mentioned before, I would like to avoid injecting a Parent (either by property or constructor) to it's children.
I have 1..1 and 1...N cardinalities.
The hierarchy from root to furthest leaf is quite extent.
The easiest storage would be List<Node> where each node contains links to its predecessors and successors:
class Example
{
public List<Node> InitGraph()
{
var nodes = new Dictionary<string, Node>();
nodes.Add("Head", new Node("Head"));
nodes.Add("T1", new Node("T1"));
nodes.Add("T2", new Node("T2"));
// While that works, a method is nicer:
nodes.Add("C1");
// These two lines should really be factored out to a single method call
nodes["Head"].Successors.Add(nodes["T1"]);
nodes["T1"].Predecessors.Add(nodes["Head"]);
nodes["Head"].Successors.Add(nodes["T2"]);
nodes["T2"].Predecessors.Add(nodes["Head"]);
// Yes. Much nicer
nodes.Connect("Head", "C1");
nodes.Connect("T1", "C1");
nodes.Connect("T2", "C1");
var nodelist = new List<Node>(nodes.Values);
return nodelist;
}
}
and NodeHelper class:
public static class NodeHelper
{
public static void Add(this Dictionary<string, Node> dict, string nodename)
{
dict.Add(nodename, new Node(nodename));
}
public static void Connect(this Dictionary<string, Node> dict, string from, string to)
{
dict[ from ].Successors.Add(dict[ to ]);
dict[ to ].Predecessors.Add(dict[ from ]);
}
}
and Node class:
public class Node
{
public string Name { get; set; }
public int Coolness { get; set; }
public List<Node> Predecessors { get; set; }
public List<Node> Successors { get; set; }
public Node()
{
Coolness = 1;
}
public Node(string name) : this()
{
this.Name = name;
}
}

How to Deseralize XML nodes of different names to same base type

I'm having trouble finding an example online that explains exactly how to configure the XmlSerializer to Deserialize XML the way I want.
I want to deserialize this XML into a Fruits or at least a List<Fruit>
<fruits>
<apple>{fruitstuff}</apple>
<orange>{fruitstuff}</orange>
<pear>{fruitstuff}</pear>
<fruits>
I imagine a model that looks like this
class Fruits : List<Fruit> {}
class Fruit {
{fruitstuff}
}
class Apple : Fruit {}
class Orange : Fruit {}
class Pear : Fruit {}
The problem I am running into is some combination of XmlSerlization configuration and XML Attributing. When I provide an XmlSeralizer the XML can be read with out throwing an error however it does not recognize the collection of fruits. The collection will contain zero elements.
var seralizer = new XmlSerializer(typeof(Fruits), new XmlRootAttribute("Fruits"));
My question to the internet is, how do I configure the serializer to recognize and deserialize like nodes into a collection of base types?
I would rather have an elaborately configured custom serializer than an XmlAttributed model. I might want to use the model with different formats other than XML. Having xml attributes all over my model is I think less elegant than a targeted serialization implementation.
Add <fruit> element to wrap multiple <fruits> elements
Add XmlRoot and XmlElement attributes to corresponding clases.
My sample code and it works:
class Program
{
static void Main(string[] args)
{
string xml = #"
<fruit>
<fruits>
<apple>
<attr1>1</attr1>
<attr2>2</attr2>
</apple>
<orange>
<attr1>3</attr1>
<attr2>4</attr2>
</orange>
<pear>
<attr1>5</attr1>
<attr2>6</attr2>
</pear>
</fruits>
<fruits>
<apple>
<attr1>7</attr1>
<attr2>8</attr2>
</apple>
<orange>
<attr1>9</attr1>
<attr2>10</attr2>
</orange>
<pear>
<attr1>11</attr1>
<attr2>12</attr2>
</pear>
</fruits>
</fruit>
";
var ser = new XmlSerializer(typeof(Fruit));
using (var reader = new StringReader(xml))
{
var myFruits = (Fruit)ser.Deserialize(reader);
}
Console.Read();
}
}
[XmlRoot("fruit")]
public class Fruit
{
[XmlElement("fruits")]
public List<Fruits> Fruits { get; set; }
}
public class Fruits
{
[XmlElement("apple")]
public Apple Apple { get; set; }
[XmlElement("orange")]
public Orange Orange { get; set; }
[XmlElement("pear")]
public Pear Pear { get; set; }
}
public class FruitCommonProperty
{
[XmlElement("attr1")]
public string Attr1 { get; set; }
[XmlElement("attr2")]
public string Attr2 { get; set; }
}
public class Apple : FruitCommonProperty { }
public class Orange : FruitCommonProperty { }
public class Pear : FruitCommonProperty { }

C# XML Serialization removing wrapper element

I wrote because I have problem with XmlSerializer. I want XML in the following format:
<?xml version="1.0" encoding="utf-8"?>
<RootXML>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>1</Id>
<Value>100</Value>
</TradeInvoice>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>2</Id>
<Value>200</Value>
</TradeInvoice>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>3</Id>
<Value>300</Value>
</TradeInvoice>
</RootXML>
So I created the following classes.
[XmlRoot("RootXML")]
public class Root
{
public Root()
{
RootBodies = new List<RootBody>();
}
[XmlElement("e-Invoice")]
public List<RootBody> RootBodies { get; set; }
}
public class RootBody
{
public RootBody()
{
TradeInvoice = new TradeInvoice();
EInvoiceInfo = new Version(); ;
}
[XmlElement("e-Invoice")]
public Version EInvoiceInfo { get; set; }
[XmlElement("TradeInvoice")]
public TradeInvoice TradeInvoice { get; set; }
}
public class Version
{
[XmlElement("Version")]
public string Version { get; set; }
}
public class TradeInvoice
{
[XmlElement("Id")]
public int Id { get; set; }
[XmlElement("Value")]
public int Value { get; set; }
}
I have problem with removing wraper Elements (remove RootBody). I read similar topic like this link. But it does not solve my problem.
Before the actual explanation, let me point out a couple of very important things:
This XML is not very well designed and will cause a lot of other problems along the line (I'm guessing it is actually a lot more complicated than this).
The naming convention is inconsistent (e-Invoice and TradeInvoce)
The version number looks out of place, make sure this is really what they (whoever told you to do this) want before investing additional time.
This XML defines no namespaces (and probably doesn't have an XSD or DTD either)
Take a look at Google's XML design guidelines. You'll realize there is a lot of room for improvement.
There are a lot of different ways to do this, this is just one of them. I recommend you instead take it up with whoever is responsible for this design and try to change their mind.
Since you want to serialize e-Invoice and TradeInvoce without a wrapper element but still keep the order of elements (because they belong together) you need to make sure they have a common base class so they can be serialized from the same collection.
This abstract Invoice class simply tells the serializer which classes should be included during serialization via the XmlInclude attribute.
[XmlInclude(typeof(EInvoice))]
[XmlInclude(typeof(TradeInvoice))]
public abstract class Invoice
{
}
Your actual classes will be mostly unchanged
[XmlRoot("e-Invoice")]
public class EInvoice : Invoice
{
[XmlElement("Version")]
public string Version { get; set; }
}
[XmlRoot("TradeInvoice")]
public class TradeInvoice : Invoice
{
[XmlElement("Id")]
public int Id { get; set; }
[XmlElement("Value")]
public int Value { get; set; }
}
Your data class doesn't need any XML-related Attributes anymore because as it is now, it can't be serialized into that format directly.
public class InvoicePair
{
public InvoicePair(EInvoice eInvoice, TradeInvoice tradeInvoice)
{
TradeInvoice = tradeInvoice;
EInvoiceInfo = eInvoice;
}
public EInvoice EInvoiceInfo { get; set; }
public TradeInvoice TradeInvoice { get; set; }
}
Your Root class has to be simplified a bit. Since we want EInvoce and TradeInvoice Elements on the same level but mixed together, we need to put them in the same collection. The XmlElement attributes will tell the serializer how to handle elements of different types without relying on the xsi:type attribute.
[XmlRoot("RootXML")]
public class Root
{
public Root()
{
RootBodies = new List<Invoice>();
}
[XmlElement(Type = typeof(EInvoice), ElementName = "e-Invoice")]
[XmlElement(Type = typeof(TradeInvoice), ElementName = "TradeInvoice")]
public List<Invoice> RootBodies { get; set; }
}
Serialization is quite straight-forward at this point. Simply add all elements to the collection of elements one after another:
public static void Serialize(IEnumerable<InvoicePair> invoices, Stream stream)
{
Root root = new Root();
foreach (var invoice in invoices)
{
root.RootBodies.Add(invoice.EInvoiceInfo);
root.RootBodies.Add(invoice.TradeInvoice);
}
XmlSerializer serializer = new XmlSerializer(typeof(Root));
serializer.Serialize(stream, root);
}
Deserialization isn't very hard either, but very prone to erros and makes a lot of assumptions:
public static IEnumerable<InvoicePair> Deserialize(Stream stream)
{
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = serializer.Deserialize(stream) as Root;
for (int i = 0; i < root.RootBodies.Count; i += 2)
{
yield return new InvoicePair(
(EInvoice) root.RootBodies[i],
(TradeInvoice) root.RootBodies[i+1]
);
}
}
Here is a working Demo Fiddle, that outputs the XML

How to serialize the base class with derived classes

.
Hello,
I have this sample code :
public class Vehicule
{
public string Name { get; set; }
public Brand Brand { get; set; }
}
public class Car : Vehicule
{
public string Matriculation { get; set; }
}
public class Brand
{
public string Name { get; set; }
}
public class Renault : Brand
{
public string Information { get; set; }
}
If I create this instance :
var car = new Car { Name = "Clio", Matriculation = "XXX-XXX", Brand = new Renault { Name = "Renault", Information = "Contact Infos" } };
When I serialize this object like that :
var serializer = new XmlSerializer(typeof(Car), new Type[] { typeof(Renault)});
serializer.Serialize(wr, car);
I obtain this :
<?xml version="1.0" encoding="utf-8"?>
<Car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Clio</Name>
<Brand xsi:type="Renault">
<Name>Renault</Name>
<Information>Contact Infos</Information>
</Brand>
<Matriculation>XXX-XXX</Matriculation>
</Car>
But, in my project, I don't have to have informations on derived classes, I would like only elements of base classes from this instance like this :
var serializer = new XmlSerializer(typeof(Vehicule));
serializer.Serialize(wr, car);
The Xml :
<?xml version="1.0" encoding="utf-8"?>
<Vehicule xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Name>Clio</Name>
<Brand>
<Name>Renault</Name>
</Brand>
</Vehicule>
Can you please, help me to obtain the good Xml (only with base type Vehicule and Brand) ?
Many thanks
You can't magically serialize a derived class as it's base because
"...Serialization checks type of instance by calling Object.getType()
method. This method always returns the exact type of object."
http://bytes.com/topic/net/answers/809946-how-force-serialize-base-type
The solution here, if you really need to only serialize the base class is to implement the IXmlSerializable interface and create your own custom serializer.
IXmlSerializable:
http://msdn.microsoft.com/en-us/library/system.xml.serialization.ixmlserializable(v=vs.110).aspx
One more thought. If you can work around the limitation of outputting the extra XML elements, you are able to serialize the derived class using only the base object by either 1) using XmlIncludeAttributes on the base class to tell it which types to expect or 2) using the XmlSerializer constructor overload that takes a list of types.
Edit:
After thinking about this a little more, a workaround would be that you would add a Clone() method onto your base object, then serialize the clone of the base.
LinqPad code:
public class Vehicule
{
public string Name { get; set; }
public Brand Brand { get; set; }
public Vehicule Clone()
{
return new Vehicule { Name = this.Name, Brand = new Brand { Name = this.Brand.Name } };
}
}
public class Car : Vehicule
{
public string Matriculation { get; set; }
}
public class Brand
{
public string Name { get; set; }
}
public class Renault : Brand
{
public string Information { get; set; }
}
void Main()
{
var car = new Car { Name = "Clio", Matriculation = "XXX-XXX", Brand = new Renault { Name = "Renault", Information = "Contact Infos" } };
var vehicle = car as Vehicule;
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(Vehicule));
XmlWriterSettings settings = new XmlWriterSettings
{
Encoding = new UnicodeEncoding(false, false),
Indent = false,
OmitXmlDeclaration = false
};
using(StringWriter textWriter = new StringWriter())
using(XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings)) {
serializer.Serialize(xmlWriter, vehicle.Clone());
textWriter.ToString().Dump();
}
}
This is one of the issues with inheritance, and another reason to favor composition imho.
I ran into the same issue on a mobile app where I had a Contact class that derives from ContactSummary. The repository returns Contact instances, but in lots of cases I only wanted the ContactSummary going over the wire to save on message sizes and data usage etc. The default Xml and Json serialisers would only work when the derived class was attributed with the [KnownType()] of the base class, but this still meant all those extra properties going over the wire.
Using inheritance it is problematic to achieve a viable solution, and I didn't want to resort to custom serialisers, and if the solution is to pollute the DTO with copy constructors and clone properties, then why not change the DTO to use composition instead?
If you have control over your DTOs, then restructuring them to use composition rather than inheritance may be the answer. In my example it was fairly simple...
public class ContactSummary
{
public string Name { get; set;}
public string Phone { get; set; }
}
public class Contact
{
public ContactSummary Summary { get; set; }
// ... other properties here
}
In your example, Car would need to contain a reference to Vehicle not inherit from it - something like...
[KnowTypes(typeof(Renault))]
public class Vehicle
{
public string Name { get; set; }
public Brand Brand { get; set; }
}
public class Car
{
public Vehicle Vehicle { get; set; }
public string Matriculation { get; set; }
}
Then when you want the 'base' type in your example, simply serialise Car.Vehicle.
I had the same problem and I got around it by re-mapping the inheriting class into the base class using AutoMapper:
MapperConfiguration config = new MapperConfiguration(cfg => cfg.CreateMap<Inheriting, Base>());
IMapper mapper = config.CreateMapper();
var baseObj = mapper.Map<Base>(InheritingObj);
There is not much you can customize on XmlSerializer out-of-the-box options.

Categories