[英]Serialize an Object into XML Array
我有一个场景,我可能需要将一个对象作为根元素序列化到 XML 文件中,或者如果提供的文件已经有一个对象数组,我需要将对象序列化到数组中。
因为对象可能是根,所以我用System.Xml.Serialization.XmlRootAttribute
修饰了它。
当我将对象序列化为 XElement 时,我得到了对象的根版本。 当我将 XElement 添加到数组时,它会保留命名空间属性并且无法正确反序列化。
这是课程的一部分:
[System.CodeDom.Compiler.GeneratedCodeAttribute("xsd", "4.8.3928.0")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="urn:www.agxml.org:schemas:all:4:0", TypeName = "CommodityMovement")]
[System.Xml.Serialization.XmlRootAttribute(ElementName ="CommodityMovement", Namespace="urn:www.agxml.org:schemas:all:4:0", IsNullable=false)]
public partial class CommodityMovementType {
...
}
当我创建一个带有列表的文件时,它工作得很好。
private static String CreateMessageFile<T>(String filePath, T message)
{
var xmlDoc = new XDocument();
// serialize XML to string to the xmlEntity document
using (var writer = new StringWriter())
{
var entitySerializer = new XmlSerializer(typeof(List<T>));
var list = new List<T>();
list.Add(message);
entitySerializer.Serialize(writer, list);
xmlDoc.Add(XElement.Parse(writer.ToString()));
}
xmlDoc.Save(filePath);
}
这将使用一条消息序列化一个数组:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfCommodityMovement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CommodityMovement>
...
</CommodityMovement>
</ArrayOfCommodityMovement>
但是,我可能会读取该文件并向该数组添加一条消息。
private static String CreateMessageFile<T>(String filePath, T message)
{
var xmlDoc = new XDocument();
using var sourceStream = File.Open(filePath,FileMode.Open);
xmlDoc.Add(XElement.Load(sourceStream));
using (var writer = new StringWriter())
{
var entitySerializer = new XmlSerializer(entity.DotNetType);
// entitySerializer.Serialize(writer, list);
entitySerializer.Serialize(writer, message);
xmlDoc.Root.Add(XElement.Parse(writer.ToString()));
}
xmlDoc.Save(filePath);
}
这将生成以下 XML:
<?xml version="1.0" encoding="utf-8"?>
<ArrayOfCommodityMovement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<CommodityMovement>
...
</CommodityMovement>
<CommodityMovement xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:www.agxml.org:schemas:all:4:0">
...
</CommodityMovement>
</ArrayOfCommodityMovement>
当我尝试反序列化 ArrayOfCommodityMovement 时,它只会反序列化第一个 CommodityMovement 消息。
如果我打开生成的 XML 文件并从第二个 CommodityMovement 元素中删除命名空间属性,那么它将正确反序列化。 这是我用来定义“正确”的测试。
XDocument xDocument = XDocument.Load(filePath);
var descendants = xDocument.Descendants("CommodityMovement");
Assert.Equal(2, descendants.Count());
var entitySerializer = new XmlSerializer(typeof(List<CommodityMovementType>));
var commodityMovementList = entitySerializer.Deserialize(xDocument.CreateReader()) as List<CommodityMovementType>;
Assert.NotEmpty(commodityMovementList);
Assert.Equal(2, commodityMovementList.Count);
那么如何反序列化对象并将结果元素插入现有数组并确保不添加属性?
顺便说一句,我需要保留 System.Xml.Serialization.XmlRootAttribute 因为根据配置,我需要能够为每个文件生成一条消息,然后 CommodityMovement 成为根元素。
注意:这不是我的确切代码。 这是一个简化的例子。
在此先感谢您的帮助。
我发现解决方案是删除属性和命名空间,如果这不是数组中的第一个元素。 要查看它是否是第一个,我检查文档根目录是否为空:
if (xmlDoc.Root is null)
如果它不为空,我会序列化该元素,删除它的属性和命名空间并将该元素添加到根元素:
else
{
var element = SerializeEntityAsElement(entity, masterData);
// remove attributes and namespace so element can be added to existing array
element.RemoveAttributes();
element.Name = element.Name.LocalName;
xmlDoc.Root.Add(element);
}
现在我的测试将通过:
XDocument xDocument = XDocument.Load(filePath);
var descendants = xDocument.Descendants("CommodityMovement");
Assert.Equal(2, descendants.Count());
var entitySerializer = new XmlSerializer(typeof(List<CommodityMovementType>));
var commodityMovementList = entitySerializer.Deserialize(xDocument.CreateReader()) as List<CommodityMovementType>;
Assert.NotEmpty(commodityMovementList);
Assert.Equal(2, commodityMovementList.Count);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.