将XML的一部分反序列化为列表<;t>;在C#中

本文关键字:gt XML lt 反序列化 一部分 列表 | 更新日期: 2023-09-27 18:26:10

我有以下XML数据:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<data-set xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <record>
        <LevelNum>0</LevelNum>
        <LevelName>Level 0</LevelName>
        <MaxBubbles>40</MaxBubbles>
        <MaxVisibleBubbles>30</MaxVisibleBubbles>
        <StartingPointValue>11</StartingPointValue>
        <MaxLevelTime>78</MaxLevelTime>
        <LevelPassScore>3000</LevelPassScore>
        <TapsToPopStandard>1</TapsToPopStandard>
        <InitialVisibleBubbles>9</InitialVisibleBubbles>
        <LevelDescription>Level 80</LevelDescription>
        <SeqLinear>1</SeqLinear>
        <SeqEven>0</SeqEven>
        <SeqOdd>0</SeqOdd>
        <SeqTriangular>0</SeqTriangular>
        <SeqSquare>0</SeqSquare>
        <SeqLazy>0</SeqLazy>
        <SeqFibonacci>0</SeqFibonacci>
        <SeqPrime>0</SeqPrime>
        <SeqDouble>0</SeqDouble>
        <SeqTriple>0</SeqTriple>
        <SeqPi>0</SeqPi>
        <SeqRecaman>0</SeqRecaman>
    </record>
</data-set>

我目前正在阅读以下数据:

    //---------------------------------------------------------------------------------------------------------
    // ReadLevels
    //---------------------------------------------------------------------------------------------------------
    // Reads the contents of the levelInfo.xml file and builds a list of level objects with the data in the 
    // xml file.  Allows for easy changing of level setup and addint new levels
    //---------------------------------------------------------------------------------------------------------
    public List<Level> ReadLevels(XDocument levelInfo)
    {
        levelInfo = XDocument.Load ("./levelinfo.xml");
        List<Level> lvl = (from level in levelInfo.Root.Descendants ("record") // "record" has to match the record level identifier in the xml file
            select new Level {
                LevelNum = int.Parse (level.Element ("LevelNum").Value),
                LevelName = level.Element ("LevelName").Value,
                MaxBubbles = int.Parse (level.Element ("MaxBubbles").Value),
                MaxVisibleBubbles = int.Parse (level.Element ("MaxVisibleBubbles").Value),
                StartingPointValue = int.Parse (level.Element ("StartingPointValue").Value),
                MaxLevelTime = int.Parse (level.Element ("MaxLevelTime").Value),
                LevelPassScore = int.Parse (level.Element ("LevelPassScore").Value),
                TapsToPopStandard = int.Parse (level.Element ("TapsToPopStandard").Value),
                InitialVisibleBubbles = int.Parse (level.Element ("InitialVisibleBubbles").Value),
                LevelDescription = level.Element ("LevelDescription").Value,
                SeqLinear = (bool)level.Element ("SeqLinear"),
                SeqEven = (bool)level.Element ("SeqEven"),
                SeqOdd = (bool)level.Element ("SeqOdd"),
                SeqTriangular = (bool)level.Element ("SeqTriangular"),
                SeqSquare = (bool)level.Element ("SeqSquare"),
                SeqLazy = (bool)level.Element ("SeqLazy"),
                SeqFibonacci = (bool)level.Element ("SeqFibonacci"),
                SeqPrime = (bool)level.Element ("SeqPrime"),
                SeqDouble = (bool)level.Element ("SeqDouble"),
                SeqTriple = (bool)level.Element ("SeqTriple"),
                SeqPi = (bool)level.Element ("SeqPi"),
                SeqRecaman = (bool)level.Element ("SeqRecaman")
            }).ToList ();
        return lvl;
    }

我当前的级别数据结构如下:

public class Level
{
    public int LevelNum { get; set; }
    public string LevelName { get; set; }
    public int MaxBubbles { get; set; }
    public int MaxVisibleBubbles { get; set; }
    public int StartingPointValue { get; set; }
    public int MaxLevelTime { get; set; }
    public int LevelPassScore { get; set; }
    public int TapsToPopStandard { get; set; }
    public int InitialVisibleBubbles { get; set; }
    public string LevelDescription { get; set; }
    public bool SeqLinear { get; set; }
    public bool SeqEven { get; set; }
    public bool SeqOdd { get; set; }
    public bool SeqTriangular { get; set; }
    public bool SeqSquare { get; set; }
    public bool SeqLazy { get; set; }
    public bool SeqFibonacci { get; set; }
    public bool SeqPrime { get; set; }
    public bool SeqDouble { get; set; }
    public bool SeqTriple { get; set; }
    public bool SeqPi { get; set; }
    public bool SeqRecaman { get; set; }
    public Level ()
    {
    }
}

我认为有一种更好的方法来处理布尔标志属性列表。与其将它们全部列出并单独设置,不如将它们存储在列表或字典中。

我的问题是,我不知道如何对XML数据进行反序列化。我已经在创建一个级别对象的列表,但我不知道如何以正确的方式创建"列表中的列表"。

有没有可能用我已经使用嵌套linq语句创建的列表来创建另一个列表,或者有没有其他方法可以做到这一点?

将XML的一部分反序列化为列表<;t>;在C#中

在不使用标志列表的情况下实现这一点的一个简单方法是稍微修改XML:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<data-set xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <record>
        <LevelNum>0</LevelNum>
        <LevelName>Level 0</LevelName>
        <MaxBubbles>40</MaxBubbles>
        <MaxVisibleBubbles>30</MaxVisibleBubbles>
        <StartingPointValue>11</StartingPointValue>
        <MaxLevelTime>78</MaxLevelTime>
        <LevelPassScore>3000</LevelPassScore>
        <TapsToPopStandard>1</TapsToPopStandard>
        <InitialVisibleBubbles>9</InitialVisibleBubbles>
        <LevelDescription>Level 80</LevelDescription>
        <LevelSeq>
            <SeqLinear>1</SeqLinear>
            <SeqEven>0</SeqEven>
            <SeqOdd>0</SeqOdd>
            <SeqTriangular>0</SeqTriangular>
            <SeqSquare>0</SeqSquare>
            <SeqLazy>0</SeqLazy>
            <SeqFibonacci>0</SeqFibonacci>
            <SeqPrime>0</SeqPrime>
            <SeqDouble>0</SeqDouble>
            <SeqTriple>0</SeqTriple>
            <SeqPi>0</SeqPi>
            <SeqRecaman>0</SeqRecaman>
        </LevelSeq>
    </record>
</data-set>

然后稍微修改一下您的类,以镜像新的结构并支持使用XmlSerializer:

//Avoids missing xmlns errors with XmlSerializer
[Serializable, XmlRoot("record")]
public class Level
{
    public int LevelNum { get; set; }
    public string LevelName { get; set; }
    public int MaxBubbles { get; set; }
    public int MaxVisibleBubbles { get; set; }
    public int StartingPointValue { get; set; }
    public int MaxLevelTime { get; set; }
    public int LevelPassScore { get; set; }
    public int TapsToPopStandard { get; set; }
    public int InitialVisibleBubbles { get; set; }
    public string LevelDescription { get; set; }
    //gives a hint to the serialiser that the element <LevelSeq> should be used.
    [XmlElement(ElementName="LevelSeq")]
    public LevelSeq Seq {get;set;}
    public Level ()
    {
          Seq=new LevelSeq();
    }
}
public class LevelSeq
{
    public bool SeqLinear { get; set; }
    public bool SeqEven { get; set; }
    public bool SeqOdd { get; set; }
    public bool SeqTriangular { get; set; }
    public bool SeqSquare { get; set; }
    public bool SeqLazy { get; set; }
    public bool SeqFibonacci { get; set; }
    public bool SeqPrime { get; set; }
    public bool SeqDouble { get; set; }
    public bool SeqTriple { get; set; }
    public bool SeqPi { get; set; }
    public bool SeqRecaman { get; set; }
}

然后直接使用串行器:

void Main()
    {
        var levelInfo = XDocument.Load(@"C:'test'data.xml");
        var serialiser = new XmlSerializer(typeof(Level));
        foreach (var level in levelInfo.Root.Descendants("record"))
        {
           Level newLevel = null;
          using (var reader = level.CreateReader())
          {
            try
            {
                newLevel = serialiser.Deserialize(reader) as Level;
            }
            catch(Exception)
            {
                //something went wrong with de-serialisation!
            }
            Console.WriteLine("Level.LevelNum={0}, evel.LevelSeq.SeqLinear=",
                             newLevel.LevelNum,newLevel.Seq.SeqLinear);     
         }
       }
    }

诚然,它不是最花哨的,但它简单而快速;一个优点是,您还可以使用相同的概念轻松地将级别数据写入磁盘。

您可以根据自己的情况调整以下内容。由于我们没有您的设置值代码,我无法推测您是如何调用设置xml的方法的。

public IList<bool> Flags
{
    get
    {
        try
        {
            return self.Element("Flags")
                .Elements()
                .Select(x => (bool)x)
                .ToList();
        }
        catch
        {
            return new bool[] { }.ToList();
        }
    }
    set
    {
        XElement flags = self.GetElement("Flags");
        flags.RemoveAll();
        flags.Add(value.Select(b => new XElement("flag", b)));
    }
}

我使用这个公共xml库中的GetElement扩展方法,它类似于Element()调用,但如果元素不存在,就会创建它。

self类似于level变量,只是我将其作为Level对象的一部分。所以你的代码可能看起来像:

public class Level
{
    XElement self;
    public int LevelNum { get; set; }
    public string LevelName { get; set; }
    public int MaxBubbles { get; set; }
    public int MaxVisibleBubbles { get; set; }
    public int StartingPointValue { get; set; }
    public int MaxLevelTime { get; set; }
    public int LevelPassScore { get; set; }
    public int TapsToPopStandard { get; set; }
    public int InitialVisibleBubbles { get; set; }
    public string LevelDescription { get; set; }
    public IList<bool> Flags { the code from above here }
    public Level (XElement e)
    {
        self = e;
    }
}

我建议您尝试使用XmlSerializer它可以为您直接从XML文件序列化/反序列化到对象。

然后,您可以直接从XML文档移动到对象,而不是解析数据的每个变量:

using (Stream stream = File.OpenRead(path))
        {
            XmlSerializer serializer = new XmlSerializer(typeof(T));
            T deSerializedType = (T)serializer.Deserialize(stream);
            return deSerializedType;
        }

该解决方案将适用于包含其他类或其他对象列表的类,只要它们都作为包含类的公共属性公开即可。