[英]Serialize XML elements as their class name
簡而言之,我希望從一組看起來如下的對象創建XML模式;
<?xml version="1.0" encoding="utf-16"?>
<QBXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<QBXMLMsgsRq>
<InvoiceQueryRq>
<TxnID>1</TxnID>
</InvoiceQueryRq>
<InvoiceAddRq>
<TxnID>2</TxnID>
</InvoiceAddRq>
</QBXMLMsgsRq>
</QBXML>
但我得到的是;
<?xml version="1.0" encoding="utf-16"?>
<QBXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<QBXMLMsgsRq>
<Requests>
<AbstractXmlSerializerOfQBBaseMessageRequest>
<InvoiceQueryRq>
<TxnID>1</TxnID>
</InvoiceQueryRq>
<InvoiceAddRq>
<TxnID>2</TxnID>
</InvoiceAddRq>
</AbstractXmlSerializerOfQBBaseMessageRequest>
</Requests>
</QBXMLMsgsRq>
</QBXML>
QBXMLMsgsRq實際上是abstract class
的集合,因為在不同類型的集合中可能存在許多請求(此處為InvoiceQueryRq,但也可能存在InvoiceAddRq,InvoiceDeleteRq等)。 默認情況下,XML序列化程序不允許這樣做,但經過一些研究后我發現了這個鏈接; XML Serialize可序列化對象的通用列表
我在那里調整了AbstractXmlSerializer
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml.Serialization;
public class AbstractXmlSerializer<AbstractType> : IXmlSerializable
{
public static implicit operator AbstractType(AbstractXmlSerializer<AbstractType> o)
{
return o.Data;
}
public static implicit operator AbstractXmlSerializer<AbstractType>(AbstractType o)
{
return o == null ? null : new AbstractXmlSerializer<AbstractType>(o);
}
private AbstractType _data;
public AbstractType Data
{
get { return _data; }
set { _data = value; }
}
/// <summary>
/// **DO NOT USE** This is only added to enable XML Serialization.
/// </summary>
/// <remarks>DO NOT USE THIS CONSTRUCTOR</remarks>
public AbstractXmlSerializer()
{
// Default Ctor (Required for Xml Serialization - DO NOT USE)
}
public AbstractXmlSerializer(AbstractType data)
{
_data = data;
}
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null; // this is fine as schema is unknown.
}
public void ReadXml(System.Xml.XmlReader reader)
{
// Cast the Data back from the Abstract Type.
string typeAttrib = reader.LocalName; // reader.GetAttribute("type");
// Ensure the Type was Specified
if (typeAttrib == null)
throw new ArgumentNullException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
"' because no 'type' attribute was specified in the XML.");
Type type = Type.GetType(typeAttrib);
// Check the Type is Found.
if (type == null)
throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
"' because the type specified in the XML was not found.");
// Check the Type is a Subclass of the AbstractType.
if (!type.IsSubclassOf(typeof(AbstractType)))
throw new InvalidCastException("Unable to Read Xml Data for Abstract Type '" + typeof(AbstractType).Name +
"' because the Type specified in the XML differs ('" + type.Name + "').");
// Read the Data, Deserializing based on the (now known) concrete type.
reader.ReadStartElement();
this.Data = (AbstractType)new
XmlSerializer(type).Deserialize(reader);
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
// Write the Type Name to the XML Element as an Attrib and Serialize
Type type = _data.GetType();
// BugFix: Assembly must be FQN since Types can/are external to current.
new XmlSerializer(type).Serialize(writer, _data);
}
#endregion
}
為了方便和測試任何幫助,我正在處理的對象是;
[Serializable]
public class QBXML
{
[XmlElement("QBXMLMsgsRq")]
public QBXMLMsgsRq MessageRequests { get; set; }
}
[Serializable]
public class QBXMLMsgsRq
{
public QBXMLMsgsRq()
: base()
{
Requests = new List<QBBaseMessageRequest>();
}
[XmlArray(""), XmlArrayItem("", Type = typeof(AbstractXmlSerializer<QBBaseMessageRequest>))]
public List<QBBaseMessageRequest> Requests { get; set; }
}
public abstract class QBBaseMessageRequest
{
[DefaultValue(""), XmlAttribute("requestID")]
public string RequestID { get; set; }
}
[Serializable]
public class InvoiceQueryRq : QBBaseMessageRequest
{
[DefaultValue(0), XmlElement("TxnID")]
public int TransactionID { get; set; }
}
[Serializable]
public class InvoiceAddRq : QBBaseMessageRequest
{
[DefaultValue(0), XmlElement("TxnID")]
public int TransactionID { get; set; }
}
我認為只需標准的XML序列化屬性,您就可以完成所需的一切,而無需自定義序列化程序。 請參閱以下示例:
public class Container
{
[XmlElement("ElementType1", typeof(ElementType1))]
[XmlElement("ElementType2", typeof(ElementType2))]
public ElementBase[] Elements { get; set; }
}
[XmlInclude(typeof(ElementType1)),XmlInclude(typeof(ElementType2))]
public abstract class ElementBase
{
public string Name { get; set; }
}
public class ElementType1 : ElementBase
{
public int ID1 { get; set; }
}
public class ElementType2 : ElementBase
{
public int ID2 { get; set; }
}
使用默認序列化程序序列化一些測試數據...
var container = new Container
{
Elements = new ElementBase[] {
new ElementType1 { Name = "first object", ID1 = 999 },
new ElementType2 { Name = "second object", ID2 = 31337 }
}
};
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(Container));
serializer.Serialize(stream, container);
...並獲得以下輸出,看起來像您需要的格式:
<?xml version="1.0" encoding="utf-8"?>
<Container xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<ElementType1>
<Name>first object</Name>
<ID1>999</ID1>
</ElementType1>
<ElementType2>
<Name>second object</Name>
<ID2>31337</ID2>
</ElementType2>
</Container>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.