I need to serialize in XML a class that contains a List<> implemented with different concrete classes. I need an XML without xmlns references.
this is my example:
[Serializable]
public class Root
{
[XmlElement("Tables")]
public List<AbstractTable> Tables { get; set; } = new List<AbstractTable>();
}
[XmlInclude(typeof(TableType1))]
[XmlInclude(typeof(TableType2))]
[Serializable]
public class AbstractTable
{
[XmlAttribute]
public string TableName { get; set; }
}
[Serializable]
public class TableType1 : AbstractTable
{
public TableType1()
{
TableName = "TableType1";
}
[XmlAttribute]
public string ValueA { get; set; }
}
[Serializable]
public class TableType2 : AbstractTable
{
public TableType2()
{
TableName = "TableType2";
}
[XmlAttribute]
public string ValueB { get; set; }
}
class Program
{
static void Main(string[] args)
{
var allegato = new Root();
var tableType1 = new TableType1();
tableType1.ValueA = "AAA";
allegato.Tables.Add(tableType1);
var tableType2 = new TableType2();
tableType2.ValueB = "BBB";
allegato.Tables.Add(tableType2);
var string2Write = SerializeToString(allegato);
File.WriteAllText(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "Test.xml"), string2Write);
}
public static string SerializeToString<T>(T value)
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var serializer = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings();
settings.Indent = true;
settings.OmitXmlDeclaration = true;
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, value, emptyNamespaces);
return stream.ToString();
}
}
}
I got SerializeToString from StackOverflow but works only for container class.
The problem is I am not able to remove xmlns from XML, this is what i get:
<Root>
<Tables p2:type="TableType1" TableName="TableType1" ValueA="AAA" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance" />
<Tables p2:type="TableType2" TableName="TableType2" ValueB="BBB" xmlns:p2="http://www.w3.org/2001/XMLSchema-instance" />
</Root>
Use XmlSerializerNamespaces
with Empty
namespace: You already did this for the Root
class. This should help prevent any unwanted namespace prefixes from being included in the root element, but it might not completely stop the xmlns:p2
for the concrete types (TableType1, TableType2
).
Remove XmlInclude
on the abstract base class: Instead of using the XmlInclude
attribute on the base class (AbstractTable
), you can use the XmlArrayItem
attribute directly in the Root
class to indicate the possible types.
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
[Serializable]
public class Root
{
[XmlArray("Tables")]
[XmlArrayItem("TableType1", typeof(TableType1))]
[XmlArrayItem("TableType2", typeof(TableType2))]
public List<AbstractTable> Tables { get; set; } = new List<AbstractTable>();
}
[Serializable]
public abstract class AbstractTable
{
[XmlAttribute]
public string TableName { get; set; }
}
[Serializable]
public class TableType1 : AbstractTable
{
public TableType1()
{
TableName = "TableType1";
}
[XmlAttribute]
public string ValueA { get; set; }
}
[Serializable]
public class TableType2 : AbstractTable
{
public TableType2()
{
TableName = "TableType2";
}
[XmlAttribute]
public string ValueB { get; set; }
}
class Program
{
static void Main(string[] args)
{
var allegato = new Root();
var tableType1 = new TableType1();
tableType1.ValueA = "AAA";
allegato.Tables.Add(tableType1);
var tableType2 = new TableType2();
tableType2.ValueB = "BBB";
allegato.Tables.Add(tableType2);
var string2Write = SerializeToString(allegato);
File.WriteAllText(Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), "Test.xml"), string2Write);
}
public static string SerializeToString<T>(T value)
{
var emptyNamespaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
var serializer = new XmlSerializer(value.GetType());
var settings = new XmlWriterSettings
{
Indent = true,
OmitXmlDeclaration = true
};
using (var stream = new StringWriter())
using (var writer = XmlWriter.Create(stream, settings))
{
serializer.Serialize(writer, value, emptyNamespaces);
return stream.ToString();
}
}
}