【问题标题】:How do I deserialize XML that has 2 elements with the same name but the elements have different datatypes?如何反序列化具有 2 个同名元素但元素具有不同数据类型的 XML?
【发布时间】:2019-11-08 21:25:16
【问题描述】:

我正在使用返回 XML 的 API。如果我使用一组参数调用 API,我将得到如下所示的 XML:

类型 1:

<root>
    <foos>
      <foo>some</foo>
      <foo>text</foo>
      <foo>here</foo>
    </foos>
</root>

但如果我使用另一组参数调用 API,我会得到如下所示的 XML:

类型 2:

<root>
    <foos>
        <foo>
            <fooName>some</fooName>
            <fooId>1</fooId>
            <fooDate>11-8-2019</fooDate>
        </foo>
        <foo>
            <fooName>text</fooName>
            <fooId>2</fooId>
            <fooDate>11-9-2019</fooDate>
        </foo>
        <foo>
            <fooName>here</fooName>
            <fooId>3</fooId>
            <fooDate>11-10-2019</fooDate>
        </foo>
    </foos>
</root>

如果可能的话,我想将其建模为单个 C# 对象...这样我就可以使用以下方式反序列化任一 XML:

private root Deserialize(string xmlData)
{
    var serializer = new XmlSerializer(typeof(root));
    using (var reader = new StringReader(xmlData))
    {                
        return (root)serializer.Deserialize(reader);                
    }            
}

我尝试像这样对 XML 类进行建模:

[XmlRoot("root")]
public class Root
{
    [XmlAttribute(AttributeName = "foos")]
    public List<string> foos { get; set; }              
}

当类看起来像这样时,我可以反序列化类型 1 的 xmlData(我得到一个字符串列表)。但是当我尝试反序列化类型 2 的 xmlData 时,一切都为空......

如果我像这样对 XML 类建模:

[XmlRoot("root")]
public class Root
{
    [XmlAttribute(AttributeName = "foos")]
    public List<Foo> foos { get; set; }              
}

[XmlRoot("foo")]
public class Foo
{
    [XmlAttribute(AttributeName = "fooName")]
    public string FooName { get; set; }

    [XmlAttribute(AttributeName = "fooId")]
    public string FooId { get; set; }

    [XmlAttribute(AttributeName = "fooDate")]
    public string FooDate { get; set; }               
}

然后我可以反序列化类型 2 的 xmlData(我得到一个复杂对象的列表)。但当然,这不适用于类型 1 的 xmlData。

有没有办法在 C# 中对类进行建模以处理这两种情况?

【问题讨论】:

    标签: c# xml xmlserializer


    【解决方案1】:

    您可以做的是修改Foo,以便它可以通过添加字符串值属性并用[XmlText] 标记它来捕获文本值和预期的嵌套子元素,如下所示:

    [XmlRoot("root")]
    public class Root
    {
        [XmlArray("foos")]
        [XmlArrayItem("foo")]
        public List<Foo> foos { get; set; }              
    }
    
    [XmlRoot("foo")]
    public class Foo
    {
        [XmlElement("fooName")]
        public string FooName { get; set; }
    
        [XmlElement("fooId")]
        public string FooId { get; set; }
    
        [XmlElement("fooDate")]
        public string FooDate { get; set; }               
    
        [XmlText]
        public string Value { get; set; }
    }
    

    注意事项:

    1. XmlTextAttribute

      XmlSerializer 表明,当包含该成员的类被序列化或反序列化时,该成员必须被视为 XML 文本。

    2. Foo 现在可以绑定到mixed content 节点,例如

      <foo>Some text<fooName>text</fooName>
        <fooId>2</fooId>
        <fooDate>11-9-2019</fooDate>
      </foo>
      
    3. 我在上面更正的现有RootFoo 数据模型中存在一些错误,包括:

      • &lt;fooName&gt;&lt;fooId&gt;&lt;fooDate&gt;是子元素不是属性,所以它们对应的属性必须用[XmlElement]标记。

      • foos 绑定到具有外部容器元素&lt;foos&gt; 和内部顺序元素&lt;foo&gt; 的序列,因此必须用[XmlArray] 标记。

    演示小提琴here.

    【讨论】:

    • 效果很好,谢谢!还要感谢您清理我的 foo 示例中的 XML 装饰器,并为此找到正确的搜索词:“混合内容”。真是太感谢你了!
    猜你喜欢
    • 1970-01-01
    • 2017-02-07
    • 1970-01-01
    • 2015-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多