【问题标题】:XML Serialize elements inside one anotherXML 在彼此内部序列化元素
【发布时间】:2017-12-08 01:36:43
【问题描述】:

我有一个可以自行序列化的类,例如:

[XmlRoot("NameOfMyRoot", Namespace = "myNamespace")]
public class Inner
{
    public Inner(){}
    public string SomeString { get; set; }
}

完美序列化为(我使用ns 别名为myNamespace,请参阅完整演示)

<?xml version="1.0" encoding="utf-16"?>
<NameOfMyRoot xmlns:ns="myNamespace">
    <ns:SomeString></ns:SomeString>
</NameOfMyRoot>

现在我希望这个对象成为另一个对象(包装器)的一部分:

[XmlRoot("Root")]
public class Outer<T>
{
    public T Property{ get; set; }

    public Outer(){}
    public Outer(T inner)
    {
        Property = inner;
    }
}

这给了我这个:

<?xml version="1.0" encoding="utf-16"?>
<Root xmlns:ns="myNamespace">
    <Property>
        <ns:SomeString></ns:SomeString>
    </Property>
</Root>

我想要的只是将内部对象按原样嵌入其父对象中,如下所示:

<?xml version="1.0" encoding="utf-16"?>
<Root>
    <NameOfMyRoot xmlns:ns="myNamespace">
        <ns:SomeString></ns:SomeString>
    </NameOfMyRoot>
</Root>

请注意,命名空间不应移动到根目录,并且我不能指定元素的名称,因为会有许多不同的类型。 Fiddle with full example

当然,我可以将它们单独序列化并通过一些讨厌的字符串操作进行组合,但我希望有一种巧妙的方法可以以某种方式实现这一点。

【问题讨论】:

  • 注意:问题看起来不一致; [XmlRoot("NameOfMyRoot", Namespace = "myNamespace")] public class Inner {...} 的 xml 不是 &lt;NameOfMyRoot xmlns:ns="myNamespace"&gt; - 而是&lt;NameOfMyRoot xmlns="myNamespace"&gt; - 这是一个巨大的差异
  • @MarcGravell 同意。对此添加了注释。

标签: c# .net xml generics serialization


【解决方案1】:

没有简单的方法可以做到这一点。不过,您可以在运行时执行此操作:

// perhaps discover these details at runtime
var attribs = new XmlAttributeOverrides();
attribs.Add(typeof(Outer<Inner>), "Property", new XmlAttributes
{
    XmlElements = { new XmlElementAttribute {ElementName = "NameOfMyRoot" } }
});
attribs.Add(typeof(Inner), "SomeString", new XmlAttributes
{
    XmlElements = { new XmlElementAttribute {  Namespace = "myNamespace"} }
});

var ser = new XmlSerializer(typeof(Outer<Inner>), attribs);

var obj = new Outer<Inner> { Property = new Inner { SomeString = "abc" } };
ser.Serialize(Console.Out, obj);

请注意,您必须存储并重复使用此类序列化程序;对于简单的new XmlSerializer() 示例,序列化程序在内部缓存并重复使用;然而,对于像这样的不平凡的情况,每次都会发出一个新的动态类型,所以你会泄漏内存(它不会被卸载)。

这给了你:

<Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <NameOfMyRoot>
    <SomeString xmlns="myNamespace">abc</SomeString>
  </NameOfMyRoot>
</Root>

如果您不想要两个 xmlns 别名声明,可以单独删除它们,但它们不会改变含义,至少对于兼容的阅读器而言。同样,ns 可以添加为别名:

var obj = new Outer<Inner> { Property = new Inner { SomeString = "abc" } };
var ns = new XmlSerializerNamespaces();
ns.Add("", "");
ns.Add("ns", "myNamespace");
ser.Serialize(Console.Out, obj, ns);

给出:

<Root xmlns:ns="myNamespace">
  <NameOfMyRoot>
    <ns:SomeString>abc</ns:SomeString>
  </NameOfMyRoot>
</Root>

作为替代方法:

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

[XmlRoot("NameOfMyRoot")]
public class Inner
{
    public Inner() { }
    [XmlElement(Namespace = "myNamespace")]
    public string SomeString { get; set; }
}
static class Program
{
    static void Main()
    {
        using (XmlWriter writer = XmlWriter.Create(Console.Out))
        {
            writer.WriteStartDocument(false);
            writer.WriteStartElement("Root");

            var ser = new XmlSerializer(typeof(Inner));
            var obj = new Inner { SomeString = "abc" };

            var ns = new XmlSerializerNamespaces();
            ns.Add("", "");
            ns.Add("ns", "myNamespace");
            ser.Serialize(writer, obj, ns);

            writer.WriteEndElement();
            writer.WriteEndDocument();
        }
    }
}

我这里做的是手动写根节点,只拿到XmlSerializer写里面的内容。请注意,我必须更改 SomeString 周围的属性以使其以您期望的方式工作(它是具有命名空间的字符串,而不是对象)。

【讨论】:

  • 我需要在内部类本身上设置命名空间(就像它在类的声明中一样)。在SomeStringRoot 上都没有。至于元素的名称替代它很棒。
  • @MaximGrishin 这是一个命名空间别名声明,而不是命名空间;它在任一级别都同样有效——别名是继承的,不会改变声明元素的语义。如果您的意思是 NameOfMyRoot 应该在 myNamespace 命名空间中:那 不是 您的示例显示的内容。我很乐意调整我的代码以适应 - 我编写代码以适应您的示例。
  • @MaximGrishin 具体来说,当您说“我想要的只是将内部对象按原样嵌入到其父对象中时,如下所示:&lt;?xml version="1.0" encoding="utf-16"?&gt;&lt;Root&gt;&lt;NameOfMyRoot xmlns:ns="myNamespace"&gt; - 在该代码中 NameOfMyRoot 在 空/默认命名空间,而不是myNamespace命名空间。
  • 是的,对不起,我的意思是命名空间别名声明应该属于NameOfMyRoot元素。
  • @MaximGrishin 不直接受支持,但无论命名空间别名声明位于何处(或者即使它完全有别名 - 它也可以使用显式命名空间语法)。我能问一下为什么你需要移动命名空间别名吗?因为它使事情变得非常复杂......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-23
  • 1970-01-01
相关资源
最近更新 更多