如何在类而不是属性上设置 XML 元素的名称

jch*_*tel 2 c# xml serialization

我正在尝试做看似简单的任务,但事实证明它相当复杂。

.NET 的System.Xml.Serialization命名空间似乎在支持静态 XML 结构方面做得非常好,但对动态结构的支持却不太好。

我正在尝试建立一个 XML 文档,其中的元素的子元素可以具有多种类型中的一种并且可以按任意顺序排列。据我了解,您可以通过以下方式命名具有相同名称的子元素列表:

[Serializable]
[XmlRoot("Parent")]
public class MyElement
{
    [XmlElement("Child")]
    public string[] MyChildren { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这将导致 XML 看起来像这样:

<Parent>
    <Child></Child>
    ...
    <Child></Child>
</Parent>
Run Code Online (Sandbox Code Playgroud)

我正在尝试建立一个如下所示的结构:

<Parent>
    <ChildTypeA></ChildTypeA>
    <ChildTypeB></ChildTypeB>
    ...
    <ChildTypeZ></ChildTypeZ>
</Parent>
Run Code Online (Sandbox Code Playgroud)

它们没有特定的顺序,并且类型可以出现多次。我看到了一些答案,人们建议在类上使用XmlType属性来声明元素名称,但从那时到现在,功能似乎发生了变化,因为该类型所做的只是声明元素的架构类型:

[Serializable]
[XmlRoot("Parent")]
public class MyElement
{
    [XmlElement]
    public BaseChildElement[] MyChildren { get; set; }
}

[Serializable]
public abstract class BaseChildElement {}

[Serializable]
[XmlType("ChildTypeA")]
public class ChildElementA : BaseChildElement
{
    [XmlAttribute]
    public string Content { get; set; }
}

[Serializable]
[XmlType("ChildTypeB")]
public class ChildElementB : BaseChildElement
{
    [XmlAttribute]
    public string Content { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这将生成如下所示的 XML:

<Parent>
    <MyChildren xsi:type="ChildTypeA" Content="" />
    <MyChildren xsi:type="ChildTypeB" Content="" />
    <MyChildren xsi:type="ChildTypeA" Content="" />
    ...
</Parent>
Run Code Online (Sandbox Code Playgroud)

有人知道如何生成子元素的动态列表,其中子元素的类可以设置元素名称吗?

HTML 是我正在尝试做的事情的完美示例。在 HTML 中,您可以按任意顺序拥有任意类型的子元素:

<html>
    <head></head>
    <body>
        <p>
            <a href="google.com">Google</a>
            <span>Some text</span>
        <p>
        <div>
            <button>Click me</button>
            <a href="stackoverflow.com">Stack Overflow</a>
        <div>
        <p>Hello world</p>
    </body>
</html>
Run Code Online (Sandbox Code Playgroud)

dbc*_*dbc 5

一般来说,当序列化多态对象(或者包含多态对象的集合)时,XmlSerializer需要通过属性提前静态声明可能遇到的类型。由于您希望类型由所使用的元素名称而不是属性来确定"xsi:type"因此您应该将属性的多个实例应用于[XmlElement(typeof(TBaseChildElement))]您的MyChildren属性,每个实例对应以下的每个可能的子类型BaseChildElement

[XmlRoot("Parent")]
public class MyElement
{
    [XmlElement(typeof(ChildElementA))]
    [XmlElement(typeof(ChildElementB))]
    public BaseChildElement[] MyChildren { get; set; }
}

public abstract class BaseChildElement { }

[XmlType("ChildTypeA")]
public class ChildElementA : BaseChildElement
{
    [XmlAttribute]
    public string Content { get; set; }
}

[XmlType("ChildTypeB")]
public class ChildElementB : BaseChildElement
{
    [XmlAttribute]
    public string BContent { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

小提琴样本。

由于XmlElementAttribute.ElementName没有为任何子类型显式指定,因此将从XmlTypeAttribute.TypeName每个子类型中获取。