Deserializing into a List without a container element in XML
Use
[XmlElement("result")]
public List<Result> Results { get; set; }
How to deserialize 2 child elements without the container in c#
<ColumnList>
can contain multiple child elements of type <LockersColumn>
and <Section>
mixed together, so it needs to be deserialized as a polymorphic array of a shared base class -- in this case, object
:
[XmlRoot("LockerBank")]
public class TestBank
{
public TestBank()
{
TerminalSize = 4;
}
[XmlArray(ElementName = "ColumnList")]
[XmlArrayItem(Type = typeof(LockerColumnLayout), ElementName = "LockersColumn", IsNullable = true)]
[XmlArrayItem(Type = typeof(SectionLayout), ElementName = "Section", IsNullable = true)]
public List<object> LockerAndSectionLayouts { get; set; }
[XmlIgnore]
public IEnumerable<LockerColumnLayout> Columns { get { return (LockerAndSectionLayouts ?? Enumerable.Empty<object>()).OfType<LockerColumnLayout>(); } }
[XmlIgnore]
public IEnumerable<SectionLayout> SectionCollection { get { return (LockerAndSectionLayouts ?? Enumerable.Empty<object>()).OfType<SectionLayout>(); } }
[XmlAttribute("TerminalSize")]
public int TerminalSize { get; set; }
}
I added a couple of properties that returned filtered enumerables of each type of object in the list.
How to remove an ArrayOfX container element when serializing a List T into an existing XML document
You can serialize directly into an XDocument
by using XContainer.CreateWriter()
. This in turn will allow you to serialize directly into a child XElement
of your categories
element without any intermediate string representation.
First, define the following extension method:
public static class XObjectExtensions
{
public static XElement SerializeToXElement<T>(this T obj, XContainer parent = null, XmlSerializer serializer = null, XmlSerializerNamespaces ns = null)
{
if (obj == null)
throw new ArgumentNullException();
// Initially, write to a fresh XDocument to cleanly avoid the exception described in
// https://stackoverflow.com/questions/19045921/net-xmlserialize-throws-writestartdocument-cannot-be-called-on-writers-created
var doc = new XDocument();
using (var writer = doc.CreateWriter())
{
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(writer, obj, ns ?? NoStandardXmlNamespaces());
}
// Now move to the incoming parent.
var element = doc.Root;
if (element != null)
{
element.Remove();
if (parent != null)
{
parent.Add(element);
}
}
return element;
}
public static XmlSerializerNamespaces NoStandardXmlNamespaces()
{
var ns = new XmlSerializerNamespaces();
ns.Add("", ""); // Disable the xmlns:xsi and xmlns:xsd lines.
return ns;
}
}
Now you can add the Categories
of your WikiEntry
to your xDoc
as follows:
var categories = xDoc.Root.Element("Categories");
foreach (var category in wiki.Categories)
{
category.SerializeToXElement(categories);
}
Working sample .Net fiddle here.
How to NOT have a wrapper element for list elements after XML serialization
Just define your Loans as a XmlElement
:
public class Payment
{
public decimal Amount { get; set; }
[XmlElement("Loan")]
public List<Loan> Loans { get; set; }
}
public class Loan
{
public decimal Debt { get; set; }
public string Lender { get; set; }
}
How do I deserialize a list from xml without the plural parent element?
Try setting the attributes as shown below. Note that you'll have to change the type of Value
on the Cell
class from object
to string
.
[XmlRoot("table")]
public class Table
{
[XmlElement(typeof(Row), ElementName = "tr")]
public List<Row> Rows { get; set; }
}
public class Row
{
[XmlElement(typeof(Cell), ElementName = "td")]
public List<Cell> Cells { get; set; }
}
public class Cell
{
[XmlText(typeof(string))]
public string Value { get; set; }
}
How to deserialize child elements of different types into list/collection of base type which is a property of the corresponding class
You can deserialize your XML by modifying your types as follows:
public interface IHasThings
{
List<SomeThing> ChildThings { get; set; }
}
[XmlRoot("Things")]
public class Things : IHasThings
{
[XmlElement(typeof(ThingOne), ElementName = "ThingOne")]
[XmlElement(typeof(ThingTwo), ElementName = "ThingTwo")]
public List<SomeThing> ChildThings { get; set; } = new List<SomeThing>();
}
public abstract class SomeThing : IHasThings
{
[XmlIgnore]
public int ItemNumber { get; set; }
[XmlAttribute]
public string Name {get; set;}
[XmlElement(typeof(ThingOne), ElementName = "ThingOne")]
[XmlElement(typeof(ThingTwo), ElementName = "ThingTwo")]
public List<SomeThing> ChildThings {get; set;} = new List<SomeThing>();
public abstract void InspectChildren();
}
Notes:
By applying
[XmlElementAttribute]
to your lists, the list elements will be serialized as immediate children of the parent's element without inserting an extra, intermediate container element.Polymorphism is handled by applying
[XmlElement(typeof(TThing), ElementName = "ThingName")]
which specifies an alternate XML element, name for that specific polymorphic child type, similarly to howXmlArrayItemAttribute(String, Type)
works for collections with a container element.XmlArrayItem
andXmlElement
should not be applied to the same property.Introduction of
IHasThings
is optional but may make it easier to traverse your hierarchy, treating the root container and child things in a uniform manner.ThingOne
andThingTwo
are unchanged.A good way to debug issues in XML deserialization is to manually construct your expected deserialization graph, and then serialize it. Any divergences between the observed and expected XML likely indicate where your deserialization bug lies. With your data model you would have seen an extra level of container element
<ChildThings>
for the child collections.
Demo fiddle here.
How can I deserialize a XML file without defining the parent node?
As @Rand Random pointed out a possible dublicate, I looked at that question and finally git it working combining this and this.
XmlReader reader = XmlReader.Create(path);
reader.MoveToContent();
reader.ReadToDescendant("Products");
XmlSerializer serializer = new XmlSerializer(typeof(Product[]), new XmlRootAttribute() { ElementName = "Products" });
var products = (Product[])serializer.Deserialize(reader);
Related Topics
How to Compare Two Rich Text Box Contents and Highlight the Characters That Are Changed
Why Is .Contains Slow? Most Efficient Way to Get Multiple Entities by Primary Key
How to Show Animated Gifs on a Windows Form (C#)
Avoiding First Chance Exception Messages When the Exception Is Safely Handled
How to Combine More Than Two Generic Lists in C# Zip
Parsing Ftpwebrequest Listdirectorydetails Line
Oledbparameters and Parameter Names
Find a Control in Windows Forms by Name
Properly Draw Text Using Graphicspath
Escape Special Character in Regex
How to Assign a Func<> Conditionally Between Lambdas Using the Conditional Ternary Operator