You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# XmlElement数组序列化多余嵌套层级问题求助

解决XML序列化中节点直接包含元素的问题

嘿,我明白你现在的困扰——用XmlElement[]存储plate元素后,序列化出来每个plate都被<XmlElement>包裹,而你想要它们直接在<cars>节点下排列对吧?这其实是XmlSerializer默认行为导致的,咱们用一个简单的特性就能搞定。

问题出在哪?

默认情况下,当你把XmlElement[]作为类的属性时,XmlSerializer会把数组里的每个元素都包装在<XmlElement>标签里,这就是为什么你看到了多余的嵌套。我们需要告诉序列化器:“直接把这些元素放到<cars>节点下面,别加额外包装!”

怎么解决?

核心就是用**[XmlAnyElement]特性**,它能让XmlSerializer把数组里的每个XmlElement直接嵌入指定的父节点中。下面是修改后的完整代码,我会标注关键改动:

修改后的完整代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using Xunit;
using Xunit.Abstractions;

namespace TestsProjec.XML
{
    public class Tests
    {
        private readonly ITestOutputHelper _testOutputHelper;
        public Tests(ITestOutputHelper testOutputHelper)
        {
            _testOutputHelper = testOutputHelper;
        }

        [Fact]
        public void InjectingXml()
        {
            var serializer = new XmlSerializer(typeof(Garage));
            var cars = new List<XmlElement>();
            cars.Add(StringToXmlElement("<plate>ABC123</plate>"));
            cars.Add(StringToXmlElement("<plate>DSC563</plate>"));
            cars.Add(StringToXmlElement("<plate>AIO789</plate>"));
            cars.Add(StringToXmlElement("<plate>IUE692</plate>"));

            string fullXml;
            var entity = new Garage()
            {
                owner = "Daniel",
                CarsElements = cars.ToArray()
            };

            using (MemoryStream ms = new MemoryStream())
            {
                // 可选:设置XmlWriter不生成UTF-8 BOM,避免手动跳过字节的麻烦
                var writerSettings = new XmlWriterSettings { Encoding = new UTF8Encoding(false) };
                using (XmlWriter tw = XmlWriter.Create(ms, writerSettings))
                {
                    serializer.Serialize(tw, entity);
                    ms.Position = 0;
                    fullXml = Encoding.UTF8.GetString(ms.ToArray());
                }
            }

            _testOutputHelper.WriteLine(fullXml);
        }

        public XmlElement StringToXmlElement(string xml)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xml);
            return doc.DocumentElement;
        }
    }

    [XmlRoot("Garage")]
    public class Garage
    {
        public string owner { get; set; }

        // 关键:用XmlAnyElement指定父节点名为cars,数组里的元素直接嵌入其中
        [XmlAnyElement("cars")]
        public XmlElement[] CarsElements { get; set; }
    }
}

关键改动说明

  1. 添加[XmlAnyElement("cars")]特性:这个特性是核心,它告诉XmlSerializer把CarsElements数组里的每个XmlElement,直接作为<cars>节点的子元素输出,不会再套<XmlElement>标签。
  2. 调整属性名称:把原来的cars属性改名为CarsElements(只是为了语义更清晰,你也可以保留原名,只要特性指定正确就行)。
  3. 优化流读取逻辑:原来手动跳过3字节的操作其实没必要,通过XmlWriterSettings设置不生成UTF-8 BOM,就能直接读取整个流的内容,代码更简洁可靠。

最终效果

修改后序列化出来的XML会是你想要的样子:

<Garage xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <owner>Daniel</owner>
  <cars>
    <plate>ABC123</plate>
    <plate>DSC563</plate>
    <plate>AIO789</plate>
    <plate>IUE692</plate>
  </cars>
</Garage>

这样<cars>节点下就直接排列<plate>标签了,完美符合你的需求!

内容的提问来源于stack exchange,提问作者Daniel Maiochi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:19:06