C# XmlSerializer 使用不同的命名空间序列化同一个类

标签 c# xml xml-serialization xmlserializer

假设我有一个类:

using System.Xml;
using System.Xml.Serialization;

class Foo {
    [XmlElement(ElementName="Bar")]
    public string Bar {get; set;}
}

现在我想序列化它。但。我想指定不同的命名空间, 有一次我希望我的 XML 看起来像这样:

<Foo xmlns:v1="http://site1">
    <v1:Bar />
</Foo>

另一张 - 像这样:

<Foo xmlns:v2="http://site2">
    <v2:Bar />
</Foo>

我知道我需要在 XmlElement 属性中指定命名空间,但这正是我想要避免的。 当然,我可以创建两个不同的类,除了字段属性之外,它们是相同的,但这在某种程度上感觉不对。 有什么方法可以强制 XmlSerializer 使用我在运行时选择的命名空间吗?

最佳答案

是的; XmlAttributeOverrides:

    static void Main()
    {
        var obj = new Foo { Bar = "abc" };
        GetSerializer("http://site1").Serialize(Console.Out, obj);
        Console.WriteLine();
        GetSerializer("http://site2").Serialize(Console.Out, obj);
    }
    static XmlSerializer GetSerializer(string barNamespace)
    {
        var ao = new XmlAttributeOverrides();
        var a = new XmlAttributes();
        a.XmlElements.Add(new XmlElementAttribute { Namespace = barNamespace });
        ao.Add(typeof(Foo), nameof(Foo.Bar), a);
        return new XmlSerializer(typeof(Foo), ao);
    }

但是!!!

当您执行此操作时,它每次都会在内存中生成一个附加程序集;您必须缓存并重用序列化器实例 - 通常通过并发字典或类似的方式。例如:

private static readonly ConcurrentDictionary<string, XmlSerializer>
    s_serializersByNamespace = new();
static XmlSerializer GetSerializer(string barNamespace)
{
    if (!s_serializersByNamespace.TryGetValue(barNamespace, out var serializer))
    {
        lock (s_serializersByNamespace)
        {
            // double-checked, avoid dups
            if (!s_serializersByNamespace.TryGetValue(barNamespace, out serializer))
            {
                var ao = new XmlAttributeOverrides();
                var a = new XmlAttributes();
                a.XmlElements.Add(new XmlElementAttribute { Namespace = barNamespace });
                ao.Add(typeof(Foo), nameof(Foo.Bar), a);
                serializer = new XmlSerializer(typeof(Foo), ao);
                s_serializersByNamespace[barNamespace] = serializer;
            }
        }
    }
    return serializer;
}

注意:如果您也想要特定的 xmlns 控件,那就是 XmlSerializerNamespaces:

        var obj = new Foo { Bar = "abc" };
        var ns = new XmlSerializerNamespaces();
        ns.Add("v1", "http://site1");
        GetSerializer("http://site1").Serialize(Console.Out, obj, ns);

        Console.WriteLine();

        ns = new XmlSerializerNamespaces();
        ns.Add("v2", "http://site2");
        GetSerializer("http://site2").Serialize(Console.Out, obj, ns);

关于C# XmlSerializer 使用不同的命名空间序列化同一个类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67004952/

相关文章:

c# - 使用 Dynamic 将 XML 反序列化为对象

c# - 使用 uint 与 int

c# - WinRT 中 ViewModel 层的虚拟化

c# - 将 XML 反序列化为对象 : XML element with xsi:nil ="true" should have null value (and not empty value) for respective property in object

java - 哪个是 Java 序列化的最佳替代方案?

c# - 要每 50 毫秒发送一次图像,我应该使用 TCP 还是 UDP?

java - Android:从mysql获取数据时doInBackground出错

javascript - 解析来自远程网站的xml数据

ruby-on-rails - Rails RESTful to_xml - 如何实现连接?

c# - 使用 XmlReaderSettings.Schemas 并指定要使用的多个架构时性能下降