Deserializing into a List Without a Container Element in Xml

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 how XmlArrayItemAttribute(String, Type) works for collections with a container element. XmlArrayItem and XmlElement 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 and ThingTwo 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



Leave a reply



Submit