XML反序列化不将值加载到类中

时间:2015-03-01 20:37:39

标签: xml c#-4.0 deserialization

我有以下XML,我自动生成了一个类。

生成课程后,我必须进行一些调整才能获得PayrollEmployeePayrollDatePayrollEmployeePayrollCategoryWorkCode课程。由于我进行了调整,因此加载了两个类,但所有值都为null。除非在反序列化过程中被消耗,否则我不会收到任何错误。为什么我的值没有加载到类中?

<Payroll>
<StartDate>2015-02-22</StartDate>
<EndDate>2015-02-28</EndDate>
<PostedDate>2015-02-28</PostedDate>
<Employee EmployeeId="123456">
<EmployeePayStatus></EmployeePayStatus>
<PayrollStoreNumber>1111</PayrollStoreNumber>
<ReviewedDate></ReviewedDate>
<PayrollCategory Category="OT">
</PayrollCategory>
<PayrollCategory Category="DT">
</PayrollCategory>
<PayrollCategory Category="REGULAR">
<PayrollDate>2015-02-23</PayrollDate>
<Hours>5.97</Hours>
<WorkCode code="888">
<TotalHours>5.97</TotalHours>
</WorkCode>
<PayrollDate>2015-02-24</PayrollDate>
<Hours>6.07</Hours>
<WorkCode code="888">
<TotalHours>6.07</TotalHours>
</WorkCode>
<PayrollDate>2015-02-25</PayrollDate>
<Hours>6.00</Hours>
<WorkCode code="888">
<TotalHours>6.00</TotalHours>
</WorkCode>
<PayrollDate>2015-02-26</PayrollDate>
<Hours>8.44</Hours>
<WorkCode code="888">
<TotalHours>8.44</TotalHours>
</WorkCode>
<PayrollDate>2015-02-27</PayrollDate>
<Hours>7.90</Hours>
<WorkCode code="888">
<TotalHours>7.90</TotalHours>
</WorkCode>
</PayrollCategory>
<PayrollCategory Category="SICK">
</PayrollCategory>
<PayrollCategory Category="VACATION">
</PayrollCategory>
<PayrollCategory Category="HOLIDAY">
</PayrollCategory>
<PayrollCategory Category="RT">
</PayrollCategory>
<PayrollCategory Category="EO">
</PayrollCategory>
<PayrollCategory Category="RSA">
</PayrollCategory>
</Employee>
<Employee EmployeeId="987654">
<EmployeePayStatus></EmployeePayStatus>
<PayrollStoreNumber>1111</PayrollStoreNumber>
<ReviewedDate></ReviewedDate>
<PayrollCategory Category="OT">
</PayrollCategory>
<PayrollCategory Category="DT">
</PayrollCategory>
<PayrollCategory Category="REGULAR">
<PayrollDate>2015-02-23</PayrollDate>
<Hours>6.38</Hours>
<WorkCode code="888">
<TotalHours>6.38</TotalHours>
</WorkCode>
<PayrollDate>2015-02-24</PayrollDate>
<Hours>6.82</Hours>
<WorkCode code="888">
<TotalHours>6.82</TotalHours>
</WorkCode>
<PayrollDate>2015-02-25</PayrollDate>
<Hours>6.83</Hours>
<WorkCode code="888">
<TotalHours>6.83</TotalHours>
</WorkCode>
<PayrollDate>2015-02-26</PayrollDate>
<Hours>7.32</Hours>
<WorkCode code="888">
<TotalHours>7.32</TotalHours>
</WorkCode>
<PayrollDate>2015-02-27</PayrollDate>
<Hours>7.40</Hours>
<WorkCode code="888">
<TotalHours>7.40</TotalHours>
</WorkCode>
<PayrollDate>2015-02-28</PayrollDate>
<Hours>4.17</Hours>
<WorkCode code="888">
<TotalHours>4.17</TotalHours>
</WorkCode>
</PayrollCategory>
<PayrollCategory Category="SICK">
</PayrollCategory>
<PayrollCategory Category="VACATION">
</PayrollCategory>
<PayrollCategory Category="HOLIDAY">
</PayrollCategory>
<PayrollCategory Category="RT">
</PayrollCategory>
<PayrollCategory Category="EO">
</PayrollCategory>
<PayrollCategory Category="RSA">
</PayrollCategory>
</Employee>
</Payroll>

这是我正在上课的课程。

namespace PayrollProcessor.BL
{
    /// <remarks/>
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
    public class Payroll
    {

        private System.DateTime startDateField;

        private System.DateTime endDateField;

        private System.DateTime postedDateField;

        private PayrollEmployee[] employeeField;

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
        public System.DateTime StartDate
        {
            get
            {
                return this.startDateField;
            }
            set
            {
                this.startDateField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
        public System.DateTime EndDate
        {
            get
            {
                return this.endDateField;
            }
            set
            {
                this.endDateField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
        public System.DateTime PostedDate
        {
            get
            {
                return this.postedDateField;
            }
            set
            {
                this.postedDateField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("Employee")]
        public PayrollEmployee[] Employee
        {
            get
            {
                return this.employeeField;
            }
            set
            {
                this.employeeField = value;
            }
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
    public partial class PayrollEmployee
    {

        private string employeePayStatusField;

        private string payrollStoreNumberField;

        private string reviewedDateField;

        private PayrollEmployeePayrollCategory[] payrollCategoryField;

        private int employeeIdField;

        /// <remarks/>
        public string EmployeePayStatus
        {
            get
            {
                return this.employeePayStatusField;
            }
            set
            {
                this.employeePayStatusField = value;
            }
        }

        /// <remarks/>
        public string PayrollStoreNumber
        {
            get
            {
                return this.payrollStoreNumberField;
            }
            set
            {
                this.payrollStoreNumberField = value;
            }
        }

        /// <remarks/>
        public string ReviewedDate
        {
            get
            {
                return this.reviewedDateField;
            }
            set
            {
                this.reviewedDateField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("PayrollCategory")]
        public PayrollEmployeePayrollCategory[] PayrollCategory
        {
            get
            {
                return this.payrollCategoryField;
            }
            set
            {
                this.payrollCategoryField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public int EmployeeId
        {
            get
            {
                return this.employeeIdField;
            }
            set
            {
                this.employeeIdField = value;
            }
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
    public partial class PayrollEmployeePayrollCategory
    {
        private PayrollEmployeePayrollDate[] payrollEmployeePayrollDatesField;

        private string categoryField;

        /// <remarks/>
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public string Category
        {
            get
            {
                return this.categoryField;
            }
            set
            {
                this.categoryField = value;
            }
        }

        [System.Xml.Serialization.XmlElementAttribute("PayrollDate")]
        public PayrollEmployeePayrollDate[] PayrollEmployeePayrollDates
        {
            get
            {
                return payrollEmployeePayrollDatesField;
            }
            set
            {
                payrollEmployeePayrollDatesField = value;
            }
        }

    }

    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
    public partial class PayrollEmployeePayrollDate
    {
        private DateTime? paryrollDateField;

        private decimal? hours;

        private PayrollEmployeePayrollCategoryWorkCode[] payrollEmployeePayrollCategoryWorkCode;

        [System.Xml.Serialization.XmlElementAttribute("PayrollDate", typeof(System.DateTime), DataType = "date")]
        public DateTime? PayrollDate
        {
            get
            {
                return this.paryrollDateField;
            }
            set
            {
                this.paryrollDateField = value;
            }
        }

        [System.Xml.Serialization.XmlElementAttribute("Hours", typeof(decimal))]
        public decimal? Hours
        {
            get
            {
                return this.hours;
            }
            set
            {
                this.hours = value;
            }
        }

         [System.Xml.Serialization.XmlElementAttribute("WorkCode", typeof(PayrollEmployeePayrollCategoryWorkCode))]
        public PayrollEmployeePayrollCategoryWorkCode[] WorkCode
        {
            get
            {
                return payrollEmployeePayrollCategoryWorkCode;
            }
            set
            {
                payrollEmployeePayrollCategoryWorkCode = value;
            }
        }
    }


    /// <remarks/>
    [System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
    public partial class PayrollEmployeePayrollCategoryWorkCode
    {

        private decimal totalHoursField;

        private int codeField;

        /// <remarks/>
        [System.Xml.Serialization.XmlElementAttribute("TotalHours", typeof(decimal))]
        public decimal TotalHours
        {
            get
            {
                return this.totalHoursField;
            }
            set
            {
                this.totalHoursField = value;
            }
        }

        /// <remarks/>
        [System.Xml.Serialization.XmlAttributeAttribute()]
        public int code
        {
            get
            {
                return this.codeField;
            }
            set
            {
                this.codeField = value;
            }
        }
    }
}

我更改生成的类的原因是因为当我遍历类别时,我只有一个日期。正如XML所示,每个类别下最多可以有7个日期。

XML来自第三方,我不认为我可以让他们改变它。

1 个答案:

答案 0 :(得分:1)

问题是XML结构不再匹配您所拥有的类的结构。

PayrollCategory的XML如下所示:

<PayrollCategory Category="REGULAR">
<PayrollDate>2015-02-23</PayrollDate>
<Hours>5.97</Hours>
<WorkCode code="888">
<TotalHours>5.97</TotalHours>
</WorkCode>
<!-- ... -->

请注意,PayrollDateHoursWorkCode元素是PayrollCategory的直接子元素。

但是PayrollEmployeePayrollCategory的C#类结构通过PayrollDate类型的PayrollEmployeePayrollDates属性将所有这三个元素移动到子元素PayrollEmployeePayrollDate[]中。 PayrollEmployeePayrollDate定义了PayrollDateHoursWorkCode属性(因此也将这些属性声明为PayrollDate的子元素。)

对于您现在拥有的类结构,相应的XML将如下所示:

<PayrollCategory Category="REGULAR">
    <PayrollDate>
        <PayrollDate>2015-02-23</PayrollDate>
        <Hours>5.97</Hours>
        <WorkCode code="888">
        <TotalHours>5.97</TotalHours>
        </WorkCode>
    </PayrollDate>
    <!-- ... -->

因此,您必须调整您的类以匹配您拥有的XML,或者更改您的XML生成以匹配新的类结构(如果这是您需要的。)

更新:您无法更新XML,并希望在C#类中反映出PayrollDate / Hours / WorkCode的分组。

没有一个干净的解决方案,因为.NET XML序列化框架没有将一组元素映射到类的概念,即使这是一个合理的XML习惯用法(如下所示) W3C XML Schema作为模型组xs:group定义。)

.NET XML序列化的优点在于它很容易做到这一点,但缺点是它不能很好地扩展到更复杂的用例。

假设我正确理解您的输入XML结构,您可以采取的方法是以“平面”表示形式为PayrollDateHoursWorkCode中的每一个存储数组在您的课程内,映射到PayrollCategory。这些将用于XML序列化。然后,添加一个属性,该属性从这些XML映射属性计算对象集合,这些属性以您希望的方式重构数据:

[System.Xml.Serialization.XmlElementAttribute("PayrollDate", typeof(System.DateTime), DataType = "date")]
public DateTime[] Xml_PayrollDates
{
    get;
    set;
}

[System.Xml.Serialization.XmlElementAttribute("Hours", typeof(decimal))]
public decimal[] Xml_Hours
{
    get;
    set;
}

[System.Xml.Serialization.XmlElementAttribute("WorkCode", typeof(PayrollEmployeePayrollCategoryWorkCode))]
public PayrollEmployeePayrollCategoryWorkCode[] Xml_WorkCodes
{
    get;
    set;
}

[System.Xml.Serialization.XmlIgnore()]
public PayrollEmployeePayrollDate[] PayrollEmployeePayrollDates
{
    get
    {
        if (Xml_PayrollDates == null || Xml_Hours == null || Xml_WorkCodes == null)
        {
            if (Xml_PayrollDates == null && Xml_Hours == null && Xml_WorkCodes == null)
            {
                return new PayrollEmployeePayrollDate[0];
            }
            else
            {
                throw new ApplicationException("Mismatched PayrollDate/Hours/WorkCode");
            }
        }

        if (Xml_PayrollDates.Length != Xml_WorkCodes.Length || Xml_WorkCodes.Length != Xml_Hours.Length)
        {
            throw new ApplicationException("Mismatched PayrollDate/Hours/WorkCode");
        }

        var dates = new PayrollEmployeePayrollDate[Xml_PayrollDates.Length];

        for(int i = 0; i < dates.Length; i++)
        {
            dates[i] = new PayrollEmployeePayrollDate
            {
                Hours = Xml_Hours[i],
                WorkCode = Xml_WorkCodes[i],
                PayrollDate = Xml_PayrollDates[i]
            };
        }

        return dates;
    }
}

元素将按照它们在XML中出现的顺序进行反序列化,因此,如果我正确地解释您的XML结构,您可以再次匹配所有内容,因为这些元素总是以相同的顺序出现在如果其他元素存在,则组中的每个元素始终存在。这意味着索引0处的Hours,索引0处的WorkCode和索引0处的TotalHours都可以打包到PayrollEmployeePayrollDate的单个实例中。

我没有通过这个计算属性以相同的XML格式写回来,但是根据我对你的要求的理解,你只是在阅读数据,所以这不是必需的。

这是完整的类集,需要进行必要的调整以支持此方案(请注意PayrollEmployeePayrollDate已被修改,此类不再参与XML序列化):

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
public class Payroll
{

    private System.DateTime startDateField;

    private System.DateTime endDateField;

    private System.DateTime postedDateField;

    private PayrollEmployee[] employeeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
    public System.DateTime StartDate
    {
        get
        {
            return this.startDateField;
        }
        set
        {
            this.startDateField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
    public System.DateTime EndDate
    {
        get
        {
            return this.endDateField;
        }
        set
        {
            this.endDateField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(DataType = "date")]
    public System.DateTime PostedDate
    {
        get
        {
            return this.postedDateField;
        }
        set
        {
            this.postedDateField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("Employee")]
    public PayrollEmployee[] Employee
    {
        get
        {
            return this.employeeField;
        }
        set
        {
            this.employeeField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class PayrollEmployee
{

    private string employeePayStatusField;

    private string payrollStoreNumberField;

    private string reviewedDateField;

    private PayrollEmployeePayrollCategory[] payrollCategoryField;

    private int employeeIdField;

    /// <remarks/>
    public string EmployeePayStatus
    {
        get
        {
            return this.employeePayStatusField;
        }
        set
        {
            this.employeePayStatusField = value;
        }
    }

    /// <remarks/>
    public string PayrollStoreNumber
    {
        get
        {
            return this.payrollStoreNumberField;
        }
        set
        {
            this.payrollStoreNumberField = value;
        }
    }

    /// <remarks/>
    public string ReviewedDate
    {
        get
        {
            return this.reviewedDateField;
        }
        set
        {
            this.reviewedDateField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("PayrollCategory")]
    public PayrollEmployeePayrollCategory[] PayrollCategory
    {
        get
        {
            return this.payrollCategoryField;
        }
        set
        {
            this.payrollCategoryField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public int EmployeeId
    {
        get
        {
            return this.employeeIdField;
        }
        set
        {
            this.employeeIdField = value;
        }
    }
}

/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class PayrollEmployeePayrollCategory
{
    private string categoryField;

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public string Category
    {
        get
        {
            return this.categoryField;
        }
        set
        {
            this.categoryField = value;
        }
    }

    [System.Xml.Serialization.XmlElementAttribute("PayrollDate", typeof(System.DateTime), DataType = "date")]
    public DateTime[] Xml_PayrollDates
    {
        get;
        set;
    }

    [System.Xml.Serialization.XmlElementAttribute("Hours", typeof(decimal))]
    public decimal[] Xml_Hours
    {
        get;
        set;
    }

    [System.Xml.Serialization.XmlElementAttribute("WorkCode", typeof(PayrollEmployeePayrollCategoryWorkCode))]
    public PayrollEmployeePayrollCategoryWorkCode[] Xml_WorkCodes
    {
        get;
        set;
    }

    [System.Xml.Serialization.XmlIgnore()]
    public PayrollEmployeePayrollDate[] PayrollEmployeePayrollDates
    {
        get
        {
            if (Xml_PayrollDates == null || Xml_Hours == null || Xml_WorkCodes == null)
            {
                if (Xml_PayrollDates == null && Xml_Hours == null && Xml_WorkCodes == null)
                {
                    return new PayrollEmployeePayrollDate[0];
                }
                else
                {
                    throw new ApplicationException("Mismatched PayrollDate/Hours/WorkCode");
                }
            }

            if (Xml_PayrollDates.Length != Xml_WorkCodes.Length || Xml_WorkCodes.Length != Xml_Hours.Length)
            {
                throw new ApplicationException("Mismatched PayrollDate/Hours/WorkCode");
            }

            var dates = new PayrollEmployeePayrollDate[Xml_PayrollDates.Length];

            for(int i = 0; i < dates.Length; i++)
            {
                dates[i] = new PayrollEmployeePayrollDate
                {
                    Hours = Xml_Hours[i],
                    WorkCode = Xml_WorkCodes[i],
                    PayrollDate = Xml_PayrollDates[i]
                };
            }

            return dates;
        }
    }

}

public partial class PayrollEmployeePayrollDate
{
    public DateTime PayrollDate
    {
        get;
        set;
    }

    public decimal Hours
    {
        get;
        set;
    }

    public PayrollEmployeePayrollCategoryWorkCode WorkCode
    {
        get;
        set;
    }
}


/// <remarks/>
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
public partial class PayrollEmployeePayrollCategoryWorkCode
{

    private decimal totalHoursField;

    private int codeField;

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute("TotalHours", typeof(decimal))]
    public decimal TotalHours
    {
        get
        {
            return this.totalHoursField;
        }
        set
        {
            this.totalHoursField = value;
        }
    }

    /// <remarks/>
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public int code
    {
        get
        {
            return this.codeField;
        }
        set
        {
            this.codeField = value;
        }
    }
}

附注:如果使用List<T>而不是数组,您可能会发现您的类更容易使用,并且安排集合属性的默认值为空集合(因此您不必担心检查两个属性是否为空,如果没有子元素,则集合为空。)