如何用XmlSerializer序列化含派生类集合并移除xmlns引用
解决序列化抽象类List时移除XML xmlns引用的问题
需要序列化包含不同子类的List<AbstractTable>集合,生成不含xmlns引用的XML。当前代码生成的XML中每个<Tables>元素都带有xmlns:p2="http://www.w3.org/2001/XMLSchema-instance"命名空间声明,以及p2:type属性,需要移除这些内容。
方案一:自定义XmlWriter移除命名空间和前缀
通过自定义XmlWriter拦截并处理xsi相关的命名空间声明和属性,直接生成无命名空间的XML。
自定义XmlWriter代码
public class NoNamespaceXmlWriter : XmlTextWriter { public NoNamespaceXmlWriter(TextWriter writer) : base(writer) { } public override void WriteStartElement(string prefix, string localName, string ns) { // 忽略元素的命名空间和前缀 base.WriteStartElement("", localName, ""); } public override void WriteStartAttribute(string prefix, string localName, string ns) { // 将xsi:type转换为无前缀的type属性 if (prefix == "p2" && localName == "type" && ns == "http://www.w3.org/2001/XMLSchema-instance") { base.WriteStartAttribute("", "type", ""); } else { base.WriteStartAttribute("", localName, ""); } } public override void WriteAttributeString(string prefix, string localName, string ns, string value) { // 忽略所有xmlns相关的属性声明 if (prefix == "xmlns" || (localName == "xmlns" && prefix == "")) { return; } // 处理xsi:type属性,转换为无命名空间的type if (prefix == "p2" && localName == "type" && ns == "http://www.w3.org/2001/XMLSchema-instance") { base.WriteAttributeString("", "type", "", value); } else { base.WriteAttributeString("", localName, "", value); } } }
修改序列化方法
替换原有的SerializeToString方法,使用自定义的NoNamespaceXmlWriter:
public static string SerializeToString<T>(T value) { var serializer = new XmlSerializer(value.GetType()); using (var stream = new StringWriter()) using (var writer = new NoNamespaceXmlWriter(stream)) { writer.Formatting = Formatting.Indented; serializer.Serialize(writer, value); return stream.ToString(); } }
生成的XML效果
<Root> <Tables type="TableType1" TableName="TableType1" ValueA="AAA" /> <Tables type="TableType2" TableName="TableType2" ValueB="BBB" /> </Root>
方案二:使用XmlChoiceIdentifier替代xsi:type
利用XmlChoiceIdentifierAttribute通过已有TableName属性(或自定义枚举)标识子类类型,彻底移除xsi相关内容。
步骤1:定义类型枚举
public enum TableType { TableType1, TableType2 }
步骤2:修改Root类
添加XmlChoiceIdentifier属性和对应的枚举集合:
[Serializable] public class Root { [XmlElement("Tables", Type = typeof(TableType1))] [XmlElement("Tables", Type = typeof(TableType2))] [XmlChoiceIdentifier("TableTypeIdentifier")] public List<AbstractTable> Tables { get; set; } = new List<AbstractTable>(); [XmlIgnore] public List<TableType> TableTypeIdentifier { get; set; } = new List<TableType>(); }
步骤3:修改序列化前的赋值逻辑
添加子类时同步设置对应的枚举值:
var allegato = new Root(); var tableType1 = new TableType1(); tableType1.ValueA = "AAA"; allegato.Tables.Add(tableType1); allegato.TableTypeIdentifier.Add(TableType.TableType1); var tableType2 = new TableType2(); tableType2.ValueB = "BBB"; allegato.Tables.Add(tableType2); allegato.TableTypeIdentifier.Add(TableType.TableType2);
生成的XML效果
<Root> <Tables TableName="TableType1" ValueA="AAA" /> <Tables TableName="TableType2" ValueB="BBB" /> </Root>
内容的提问来源于stack exchange,提问作者Gabriele
相关产品推荐
相关产品推荐

