XML 属性的选择性序列化



这是一项正在进行的工作。我正在开发这些 C# 类来序列化 XML 数据:

using SimpleLogger;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Xml.Serialization;
namespace MSAToolsLibrary.SRRAssignmentHistory
{
    [Guid("xxx")]
    [ComVisible(true)]
    public enum AssignmentMode
    {
        Weekly,
        Midweek,
        Weekend
    }
    [Guid("xxx")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    [ComVisible(true)]
    public interface IAssignmentHistorySRRInterface
    {
        void SetPathXML(String strPathXML, out Int64 iResult);
        bool SaveDutyAssignmentHistory();
        bool ReadDutyAssignmentHistory(out Int64 iNumberEntriesRead);
        void Test();
    }
    public class AssignmentHistorySRR : IAssignmentHistorySRRInterface
    {
        private DutyAssignmentHistory _DutyAssignmentHistory;
        private string _strPathXML;
        public AssignmentHistorySRR()
        {
            _DutyAssignmentHistory = new DutyAssignmentHistory();
            _strPathXML = "";
        }
        public void SetPathXML(string strPathXML, out Int64 iResult)
        {
            _strPathXML = strPathXML;
            iResult = 1;
        }
        public bool ReadDutyAssignmentHistory(out Int64 iNumberEntriesRead)
        {
            bool bRead = false;
            iNumberEntriesRead = 0;
            try
            {
                _DutyAssignmentHistory.DutyAssignments.Clear(); // Reset
                XmlSerializer x = new XmlSerializer(_DutyAssignmentHistory.GetType());
                using (StreamReader reader = new StreamReader(_strPathXML))
                {
                    _DutyAssignmentHistory = (DutyAssignmentHistory)x.Deserialize(reader);
                    _DutyAssignmentHistory.BuildDutyAssignmentDictionaryFromList();
                    iNumberEntriesRead = _DutyAssignmentHistory.DutyAssignments.Count;
                    bRead = true;
                }
            }
            catch (Exception ex)
            {
                SimpleLog.Log(ex);
            }
            return bRead;
        }
        public bool SaveDutyAssignmentHistory()
        {
            bool bSaved = false;
            try
            {
                _DutyAssignmentHistory.BuildDutyAssignmentListFromDictionary();
                XmlSerializer x = new XmlSerializer(_DutyAssignmentHistory.GetType());
                using (StreamWriter writer = new StreamWriter(_strPathXML))
                {
                    x.Serialize(writer, _DutyAssignmentHistory);
                    bSaved = true;
                }
            }
            catch (Exception ex)
            {
                SimpleLog.Log(ex);
            }
            return bSaved;
        }
        public void Test()
        {
            SetPathXML(@"d:testsrr.xml", out long iResult);
            List<int> columnindex = new List<int>();
            List<string> names = new List<string>();
            columnindex.Add(1);
            columnindex.Add(2);
            columnindex.Add(3);
            columnindex.Add(4);
            columnindex.Add(5);
            columnindex.Add(6);
            names.Add("Assign 1");
            names.Add("Assign 2");
            names.Add("Assign 3");
            names.Add("Assign 4");
            names.Add("Assign 5");
            names.Add("Assign 6");
            _DutyAssignmentHistory.AddAssignments("W20180101", -1, AssignmentMode.Weekly, columnindex, names);
            SaveDutyAssignmentHistory();
        }
    }
    [XmlRoot(ElementName = "DutyAssignmentHistory", Namespace = "http://www.publictalksoftware.co.uk/msa")]
    public class DutyAssignmentHistory
    {
        public List<DutyAssignmentEntry> DutyAssignments
        {
            get => _DutyAssignments; set => _DutyAssignments = value;
        }
        private List<DutyAssignmentEntry> _DutyAssignments;
        private Dictionary<string, DutyAssignmentEntry> _DutyAssignmentsDictionary = new Dictionary<string, DutyAssignmentEntry>();
        public DutyAssignmentHistory()
        {
            _DutyAssignments = new List<DutyAssignmentEntry>();
        }
        public void BuildDutyAssignmentDictionaryFromList()
        {
            _DutyAssignmentsDictionary = _DutyAssignments.ToDictionary(x => x.Week, x => x);
        }
        public void BuildDutyAssignmentListFromDictionary()
        {
            _DutyAssignments = _DutyAssignmentsDictionary.Select(x => x.Value).ToList();
        }
        public void AddAssignments(string Week, int Template, AssignmentMode eMode, List<int> ColumnIndex, List<string> Names)
        {
            DutyAssignmentEntry oEntry = new DutyAssignmentEntry
            {
                Week = Week,
                Template = Template,
                WeeklyMode = eMode == AssignmentMode.Weekly
            };
            int iNumNames = Names.Count;
            for(int iName = 0; iName < iNumNames; iName++)
            {
                Assignment oAssign = new Assignment
                {
                    ColumnIndex = ColumnIndex[iName],
                    Name = Names[iName]
                };
                if (eMode == AssignmentMode.Midweek)
                    oEntry.MidweekAssignments.Add(oAssign);
                else if (eMode == AssignmentMode.Weekend)
                    oEntry.WeekendAssignments.Add(oAssign);
                else
                    oEntry.WeeklyAssignments.Add(oAssign);
            }
            _DutyAssignmentsDictionary.Add(Week, oEntry);
        }
    }
    public class DutyAssignmentEntry
    {
        [XmlAttribute]
        public string Week
        {
            get => _Week; set => _Week = value;
        }
        private string _Week;
        [XmlAttribute]
        public int Template
        {
            get => _Template; set => _Template = value;
        }
        private int _Template;
        [XmlAttribute]
        public bool WeeklyMode
        {
            get => _WeeklyMode; set => _WeeklyMode = value;
        }
        private bool _WeeklyMode;
        public List<Assignment> MidweekAssignments
        {
            get => _MidweekAssignments; set => _MidweekAssignments = value;
        }
        private List<Assignment> _MidweekAssignments;
        public List<Assignment> WeekendAssignments
        {
            get => _WeekendAssignments; set => _WeekendAssignments = value;
        }
        private List<Assignment> _WeekendAssignments;
        public List<Assignment> WeeklyAssignments
        {
            get => _WeeklyAssignments; set => _WeeklyAssignments = value;
        }
        private List<Assignment> _WeeklyAssignments;
        public DutyAssignmentEntry()
        {
            _Week = "";
            _Template = -1;
            _WeeklyMode = true;
            _MidweekAssignments = new List<Assignment>();
            _WeekendAssignments = new List<Assignment>();
            _WeeklyAssignments = new List<Assignment>();
        }
    }
    public class Assignment
    {
        [XmlAttribute]
        public int ColumnIndex
        {
            get => _ColumnIndex; set => _ColumnIndex = value;
        }
        private int _ColumnIndex;
        [XmlText]
        public string Name
        {
            get => _Name; set => _Name = value;
        }
        private string _Name;
        public Assignment()
        {
            _ColumnIndex = -1;
            _Name = "";
        }
    }
}

以上在我的DLL库中。它从我的 MFC 项目调用。我现在只是在做测试:

void CMSATools::Test2()
{
    if (m_pInterface != nullptr)
    {
        m_pInterface->Test2();
    }
}

当我执行上述MFC代码时,我得到一个XML文件(如我预期的那样(,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<DutyAssignmentHistory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.publictalksoftware.co.uk/msa">
  <DutyAssignments>
    <DutyAssignmentEntry Week="W20180101" Template="-1" WeeklyMode="true">
      <MidweekAssignments />
      <WeekendAssignments />
      <WeeklyAssignments>
        <Assignment ColumnIndex="1">Assign 1</Assignment>
        <Assignment ColumnIndex="2">Assign 2</Assignment>
        <Assignment ColumnIndex="3">Assign 3</Assignment>
        <Assignment ColumnIndex="4">Assign 4</Assignment>
        <Assignment ColumnIndex="5">Assign 5</Assignment>
        <Assignment ColumnIndex="6">Assign 6</Assignment>
      </WeeklyAssignments>
    </DutyAssignmentEntry>
  </DutyAssignments>
</DutyAssignmentHistory>

请注意,我有三个潜在的内部节点列表:

  • 周中作业
  • 周末作业
  • 每周作业

我希望 XML 序列化的方式是这样的:

如果"每周

模式"设置为"每周",则 XMl 条目中应存在"每周分配"节点,否则,应存在"周中/周末"节点。

目前,即使节点列表中没有条目,它也在创建空节点。这并不重要,它可以保持这样。但是是否可以调整代码,使其仅在有数据时才读取/写入?

[XmlElement] 属性添加到属性中:

[XmlElement]
public List<Assignment> MidweekAssignments
{
    get { return  _MidweekAssignments; } set {   _MidweekAssignments = value;}
}
private List<Assignment> _MidweekAssignments;
[XmlElement]
public List<Assignment> WeekendAssignments
{
    get { return _WeekendAssignments; } set {   _WeekendAssignments = value;}
}
private List<Assignment> _WeekendAssignments;
[XmlElement]
public List<Assignment> WeeklyAssignments
{
    get 
    {  return  _WeeklyAssignments;  } set {   _WeeklyAssignments = value;}
}
private List<Assignment> _WeeklyAssignments;

对不起,没有花哨的 C#7 语法,我这里只有旧东西方便

这不会更改接口及其行为,因为它将呈现如下 XML:

<?xml version="1.0" encoding="utf-16"?>
<DutyAssignmentHistory xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.publictalksoftware.co.uk/msa">
  <DutyAssignments>
    <DutyAssignmentEntry Week="W20180101" Template="-1" WeeklyMode="true">
      <WeeklyAssignments ColumnIndex="1">Assign 1</WeeklyAssignments>
      <WeeklyAssignments ColumnIndex="2">Assign 2</WeeklyAssignments>
      <WeeklyAssignments ColumnIndex="3">Assign 3</WeeklyAssignments>
      <WeeklyAssignments ColumnIndex="4">Assign 4</WeeklyAssignments>
      <WeeklyAssignments ColumnIndex="5">Assign 5</WeeklyAssignments>
      <WeeklyAssignments ColumnIndex="6">Assign 6</WeeklyAssignments>
    </DutyAssignmentEntry>
  </DutyAssignments>
</DutyAssignmentHistory>

这符合您的要求

如果我像这样调整我的类:

public class DutyAssignmentEntry
{
    private string _Week;
    private int _Template;
    private bool _WeeklyMode;
    private List<Assignment> _MidweekAssignments;
    private List<Assignment> _WeekendAssignments;
    private List<Assignment> _WeeklyAssignments;
    [XmlAttribute]
    public string Week
    {
        get => _Week; set => _Week = value;
    }
    [XmlAttribute]
    public int Template
    {
        get => _Template; set => _Template = value;
    }
    [XmlAttribute]
    public bool WeeklyMode
    {
        get => _WeeklyMode; set => _WeeklyMode = value;
    }
    public List<Assignment> MidweekAssignments
    {
        get => _MidweekAssignments; set => _MidweekAssignments = value;
    }
    [XmlIgnore]
    public bool MidweekAssignmentsSpecified
    {
        get { return (_MidweekAssignments.Count > 0); }
    }
    public List<Assignment> WeekendAssignments
    {
        get => _WeekendAssignments; set => _WeekendAssignments = value;
    }
    [XmlIgnore]
    public bool WeekendAssignmentsSpecified
    {
        get { return (_WeekendAssignments.Count > 0); }
    }
    public List<Assignment> WeeklyAssignments
    {
        get => _WeeklyAssignments; set => _WeeklyAssignments = value;
    }
    [XmlIgnore]
    public bool WeeklyAssignmentsSpecified
    {
        get { return (_WeeklyAssignments.Count > 0); }
    }
    public DutyAssignmentEntry()
    {
        _Week = "";
        _Template = -1;
        _WeeklyMode = true;
        _MidweekAssignments = new List<Assignment>();
        _WeekendAssignments = new List<Assignment>();
        _WeeklyAssignments = new List<Assignment>();
    }
}

然后我得到了想要的行为。我仍然有我的节点列表,并且只有在三个附加属性为真时才写入节点:

  • MidweekAssignmentsSpecified
  • WeekendAssignmentsSpecified
  • WeeklyAssignmentsSpecified

最新更新