读取反序列化的 xml 文件 - 具有一个值数组的类

本文关键字:有一个 数组 具有一 反序列化 xml 文件 读取 | 更新日期: 2023-09-27 18:34:04

我需要创建/读取xml文件。我得到了一个 .xsd 文件,并生成了.cs类。序列化和反序列化有效。当我创建文件时,我只是将值添加到 Items 数组并键入 ItemsElementName 数组。

问题在于阅读。在类中没有像Date,Header等属性,但是只有一个数组存储对象,第二个数组存储类型。

通常,当我需要读取 xml 文件时,我会反序列化它并获取一个包含对象的实例,但在这种情况下,它并不那么简单。我只有一个充满值的数组,很难获得我需要的值。

public partial class Invoice
{
    private object[] itemsField;
    public Invoice()
    {
    }
    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("Dates", typeof(Dates))]
    [System.Xml.Serialization.XmlElementAttribute("Header", typeof(Header))]
    [System.Xml.Serialization.XmlElementAttribute("CompanyData", typeof(CompanyData))]
    [System.Xml.Serialization.XmlElementAttribute("TextDescription", typeof(TextDescription))]
    [System.Xml.Serialization.XmlElementAttribute("InvoiceItems", typeof(InvoiceItems))]
    [System.Xml.Serialization.XmlChoiceIdentifierAttribute("ItemsElementName")]
    public object[] Items
    {
        get
        {
            return this.itemsField;
        }
        set
        {
            this.itemsField = value;
        }
    }
    [System.Xml.Serialization.XmlElementAttribute("ItemsElementName")]
    [System.Xml.Serialization.XmlIgnoreAttribute()]
    public ItemsChoiceType1[] ItemsElementName
    {
        get
        {
            return this.itemsElementNameField;
        }
        set
        {
            this.itemsElementNameField = value;
        }
    }
// etc ...
}

类标头再次有一个用于值的数组,第二个用于类型(类型可以是字符串和用户定义的,如 InvoiceType...

目前,我尝试了两种解决方案。首先,我反序列化了 xml 文件并遍历了 Items 数组。但这并不那么简单,因为在一个数组中我有值,在第二个数组中是类型。

第二秒,我远离反序列化并使用 XDocument 并获得了我需要的值。

有没有更好的解决方案?

读取反序列化的 xml 文件 - 具有一个值数组的类

例如,您可以手动定义类

public partial class Invoice
{
    public Invoice()
    {
    }
    [XmlElement("Dates")]
    public List<Dates> Dates { get; set; }
    // and so on.
}

这真的不是那么困难,几分钟你就完成了,XmlSerializer可以以更方便的方式反序列化它们。

或者,您可以使用 Lambda 表达式 + 扩展方法来挑选所需的信息,例如:

public static class InvoiceExtensions
{
    public static IEnumerable<Dates> Dates(this Invoice invoice)
    {
        return invoice.Items.OfType<Dates>();
    }
}

Items表中的对象实际上是预期的类型,您只需要过滤掉它们。 您真正需要使用ItemsElementName的唯一时间是当不同的选择(即不同的 XML 元素名称(映射到相同的数据类型时,您需要知道哪个是哪个。在这种情况下,您可以使用Enumerable.Zip将它们放在一起:

public static class InvoiceExtensions
{
    public static IEnumerable<KeyValuePair<ItemsChoiceType1, object>> ElementNamesAndItems<T>(this Invoice invoice)
    {
        return invoice.ItemsElementName.Zip(invoice.Items, (choice, item) => new KeyValuePair<ItemsChoiceType1, object>(choice, item)).Where(p => p.Value is T);
    }
}

然后过滤它们:

var relevantDates = invoice.ElementNamesAndItems<Dates>().Where(p => p.Key == ItemsChoiceType1.StartDate).Select(p => p.Value);

在您的情况下,这可能不是必需的,因为您的每个选择似乎都对应于不同的类。

相关文章: