简体   繁体   English

将对象序列化为 XML 数组

[英]Serialize an Object into XML Array

I have a scenario where I may need to serialize an object as a root element into an XML file or if a file is provided that already has an array of objects I need to serialize the object into the array.我有一个场景,我可能需要将一个对象作为根元素序列化到 XML 文件中,或者如果提供的文件已经有一个对象数组,我需要将对象序列化到数组中。

Because the object may be a root I have decorated it with the System.Xml.Serialization.XmlRootAttribute .因为对象可能是根,所以我用System.Xml.Serialization.XmlRootAttribute修饰了它。

When I serialize the object to an XElement I get the root version of the object.当我将对象序列化为 XElement 时,我得到了对象的根版本。 When I add the XElement to the array it retains the namespace attributes and can not be deserialized properly.当我将 XElement 添加到数组时,它会保留命名空间属性并且无法正确反序列化。

Here is a portion of the class:这是课程的一部分:

[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 {
    ...
}

When I create a file with a list it works just fine.当我创建一个带有列表的文件时,它工作得很好。

    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);
    }

This will serialize an array with one message:这将使用一条消息序列化一个数组:

<?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>

However, I may read that file and add a message to that array.但是,我可能会读取该文件并向该数组添加一条消息。

    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);
    }

This produces the the following XML:这将生成以下 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>

When I attempt to deserialize the ArrayOfCommodityMovement it only deserializes the first CommodityMovement message.当我尝试反序列化 ArrayOfCommodityMovement 时,它只会反序列化第一个 CommodityMovement 消息。

If I open the generated XML file and remove the namespace attributes from the second CommodityMovement element then it will deserialize correctly.如果我打开生成的 XML 文件并从第二个 CommodityMovement 元素中删除命名空间属性,那么它将正确反序列化。 Here is the test I am using to define "correctly".这是我用来定义“正确”的测试。

            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);

So how can I deserialize the object and insert the resulting element into an existing array and make sure the attributes aren't added?那么如何反序列化对象并将结果元素插入现有数组并确保不添加属性?

BTW, I need to keep the System.Xml.Serialization.XmlRootAttribute because depending on configuration I need to be able to generate one message per file and the CommodityMovement then becomes a root element.顺便说一句,我需要保留 System.Xml.Serialization.XmlRootAttribute 因为根据配置,我需要能够为每个文件生成一条消息,然后 CommodityMovement 成为根元素。

Note: This isn't my exact code.注意:这不是我的确切代码。 It is a simplified example.这是一个简化的例子。

Thanks in advance for any help.在此先感谢您的帮助。

I found the solution is to remove the attributes and namespace if this is not the first element in the array.我发现解决方案是删除属性和命名空间,如果这不是数组中的第一个元素。 To see if it is the first I check to see if the document root is null:要查看它是否是第一个,我检查文档根目录是否为空:

if (xmlDoc.Root is null)

If it is not null, I serialize the element, remove it's attributes and namespace and add the element to the root element:如果它不为空,我会序列化该元素,删除它的属性和命名空间并将该元素添加到根元素:

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);
}

Now my test will pass:现在我的测试将通过:

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM