C# XML 序列化删除包装元素
C# XML Serialization removing wrapper element
我写信是因为 XmlSerializer 有问题。我想要 XML 以下格式:
<?xml version="1.0" encoding="utf-8"?>
<RootXML>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>1</Id>
<Value>100</Value>
</TradeInvoice>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>2</Id>
<Value>200</Value>
</TradeInvoice>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>3</Id>
<Value>300</Value>
</TradeInvoice>
</RootXML>
所以我创建了以下 类。
[XmlRoot("RootXML")]
public class Root
{
public Root()
{
RootBodies = new List<RootBody>();
}
[XmlElement("e-Invoice")]
public List<RootBody> RootBodies { get; set; }
}
public class RootBody
{
public RootBody()
{
TradeInvoice = new TradeInvoice();
EInvoiceInfo = new Version(); ;
}
[XmlElement("e-Invoice")]
public Version EInvoiceInfo { get; set; }
[XmlElement("TradeInvoice")]
public TradeInvoice TradeInvoice { get; set; }
}
public class Version
{
[XmlElement("Version")]
public string Version { get; set; }
}
public class TradeInvoice
{
[XmlElement("Id")]
public int Id { get; set; }
[XmlElement("Value")]
public int Value { get; set; }
}
我在删除包装元素(删除 RootBody)时遇到问题。我读过类似的话题 link。但这并没有解决我的问题。
在实际解释之前,让我指出几件非常重要的事情:
- 这个 XML 设计得不是很好,会导致很多其他问题(我猜它实际上比这复杂得多)。
- 命名约定不一致(
e-Invoice
和 TradeInvoce
)
- 版本号看起来不合适,在投入更多时间之前确保这确实是他们(告诉你这样做的人)想要的。
- 这个XML定义了没有namespaces (and probably doesn't have an XSD or DTD)
- 看看Google's XML design guidelines。你会发现还有很大的改进空间。
有很多不同的方法可以做到这一点,这只是其中一种。我建议您转而与负责此设计的人联系并尝试改变他们的想法。
因为你想在没有包装元素的情况下序列化 e-Invoice
和 TradeInvoce
但仍然保持元素的顺序(因为它们属于一起)你需要确保它们有一个共同的基础 class 所以它们可以从同一个集合中序列化。
这个摘要 Invoice
class 只是通过 XmlInclude
属性告诉序列化程序在序列化期间应包含哪些 classes。
[XmlInclude(typeof(EInvoice))]
[XmlInclude(typeof(TradeInvoice))]
public abstract class Invoice
{
}
您的实际 classes 将基本保持不变
[XmlRoot("e-Invoice")]
public class EInvoice : Invoice
{
[XmlElement("Version")]
public string Version { get; set; }
}
[XmlRoot("TradeInvoice")]
public class TradeInvoice : Invoice
{
[XmlElement("Id")]
public int Id { get; set; }
[XmlElement("Value")]
public int Value { get; set; }
}
您的数据 class 不再需要任何 XML-related 属性,因为现在无法直接将其序列化为该格式。
public class InvoicePair
{
public InvoicePair(EInvoice eInvoice, TradeInvoice tradeInvoice)
{
TradeInvoice = tradeInvoice;
EInvoiceInfo = eInvoice;
}
public EInvoice EInvoiceInfo { get; set; }
public TradeInvoice TradeInvoice { get; set; }
}
您的 Root
class 必须稍微简化一下。由于我们希望 EInvoce
和 TradeInvoice
元素在同一层级但混合在一起,因此我们需要将它们放在同一个集合中。 XmlElement
属性将告诉序列化程序如何在不依赖 xsi:type
属性的情况下处理不同类型的元素。
[XmlRoot("RootXML")]
public class Root
{
public Root()
{
RootBodies = new List<Invoice>();
}
[XmlElement(Type = typeof(EInvoice), ElementName = "e-Invoice")]
[XmlElement(Type = typeof(TradeInvoice), ElementName = "TradeInvoice")]
public List<Invoice> RootBodies { get; set; }
}
此时序列化相当 straight-forward。只需将所有元素依次添加到元素集合中即可:
public static void Serialize(IEnumerable<InvoicePair> invoices, Stream stream)
{
Root root = new Root();
foreach (var invoice in invoices)
{
root.RootBodies.Add(invoice.EInvoiceInfo);
root.RootBodies.Add(invoice.TradeInvoice);
}
XmlSerializer serializer = new XmlSerializer(typeof(Root));
serializer.Serialize(stream, root);
}
反序列化也不是很难,但很容易出错,并且会做出很多假设:
public static IEnumerable<InvoicePair> Deserialize(Stream stream)
{
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = serializer.Deserialize(stream) as Root;
for (int i = 0; i < root.RootBodies.Count; i += 2)
{
yield return new InvoicePair(
(EInvoice) root.RootBodies[i],
(TradeInvoice) root.RootBodies[i+1]
);
}
}
我写信是因为 XmlSerializer 有问题。我想要 XML 以下格式:
<?xml version="1.0" encoding="utf-8"?>
<RootXML>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>1</Id>
<Value>100</Value>
</TradeInvoice>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>2</Id>
<Value>200</Value>
</TradeInvoice>
<e-Invoice>
<Version>1.03</Version>
</e-Invoice>
<TradeInvoice>
<Id>3</Id>
<Value>300</Value>
</TradeInvoice>
</RootXML>
所以我创建了以下 类。
[XmlRoot("RootXML")]
public class Root
{
public Root()
{
RootBodies = new List<RootBody>();
}
[XmlElement("e-Invoice")]
public List<RootBody> RootBodies { get; set; }
}
public class RootBody
{
public RootBody()
{
TradeInvoice = new TradeInvoice();
EInvoiceInfo = new Version(); ;
}
[XmlElement("e-Invoice")]
public Version EInvoiceInfo { get; set; }
[XmlElement("TradeInvoice")]
public TradeInvoice TradeInvoice { get; set; }
}
public class Version
{
[XmlElement("Version")]
public string Version { get; set; }
}
public class TradeInvoice
{
[XmlElement("Id")]
public int Id { get; set; }
[XmlElement("Value")]
public int Value { get; set; }
}
我在删除包装元素(删除 RootBody)时遇到问题。我读过类似的话题 link。但这并没有解决我的问题。
在实际解释之前,让我指出几件非常重要的事情:
- 这个 XML 设计得不是很好,会导致很多其他问题(我猜它实际上比这复杂得多)。
- 命名约定不一致(
e-Invoice
和TradeInvoce
) - 版本号看起来不合适,在投入更多时间之前确保这确实是他们(告诉你这样做的人)想要的。
- 这个XML定义了没有namespaces (and probably doesn't have an XSD or DTD)
- 看看Google's XML design guidelines。你会发现还有很大的改进空间。
有很多不同的方法可以做到这一点,这只是其中一种。我建议您转而与负责此设计的人联系并尝试改变他们的想法。
因为你想在没有包装元素的情况下序列化 e-Invoice
和 TradeInvoce
但仍然保持元素的顺序(因为它们属于一起)你需要确保它们有一个共同的基础 class 所以它们可以从同一个集合中序列化。
这个摘要 Invoice
class 只是通过 XmlInclude
属性告诉序列化程序在序列化期间应包含哪些 classes。
[XmlInclude(typeof(EInvoice))]
[XmlInclude(typeof(TradeInvoice))]
public abstract class Invoice
{
}
您的实际 classes 将基本保持不变
[XmlRoot("e-Invoice")]
public class EInvoice : Invoice
{
[XmlElement("Version")]
public string Version { get; set; }
}
[XmlRoot("TradeInvoice")]
public class TradeInvoice : Invoice
{
[XmlElement("Id")]
public int Id { get; set; }
[XmlElement("Value")]
public int Value { get; set; }
}
您的数据 class 不再需要任何 XML-related 属性,因为现在无法直接将其序列化为该格式。
public class InvoicePair
{
public InvoicePair(EInvoice eInvoice, TradeInvoice tradeInvoice)
{
TradeInvoice = tradeInvoice;
EInvoiceInfo = eInvoice;
}
public EInvoice EInvoiceInfo { get; set; }
public TradeInvoice TradeInvoice { get; set; }
}
您的 Root
class 必须稍微简化一下。由于我们希望 EInvoce
和 TradeInvoice
元素在同一层级但混合在一起,因此我们需要将它们放在同一个集合中。 XmlElement
属性将告诉序列化程序如何在不依赖 xsi:type
属性的情况下处理不同类型的元素。
[XmlRoot("RootXML")]
public class Root
{
public Root()
{
RootBodies = new List<Invoice>();
}
[XmlElement(Type = typeof(EInvoice), ElementName = "e-Invoice")]
[XmlElement(Type = typeof(TradeInvoice), ElementName = "TradeInvoice")]
public List<Invoice> RootBodies { get; set; }
}
此时序列化相当 straight-forward。只需将所有元素依次添加到元素集合中即可:
public static void Serialize(IEnumerable<InvoicePair> invoices, Stream stream)
{
Root root = new Root();
foreach (var invoice in invoices)
{
root.RootBodies.Add(invoice.EInvoiceInfo);
root.RootBodies.Add(invoice.TradeInvoice);
}
XmlSerializer serializer = new XmlSerializer(typeof(Root));
serializer.Serialize(stream, root);
}
反序列化也不是很难,但很容易出错,并且会做出很多假设:
public static IEnumerable<InvoicePair> Deserialize(Stream stream)
{
XmlSerializer serializer = new XmlSerializer(typeof(Root));
Root root = serializer.Deserialize(stream) as Root;
for (int i = 0; i < root.RootBodies.Count; i += 2)
{
yield return new InvoicePair(
(EInvoice) root.RootBodies[i],
(TradeInvoice) root.RootBodies[i+1]
);
}
}