将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:
<?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;
}
该解决方案将适用于包含其他类或其他对象列表的类,只要它们都作为包含类的公共属性公开即可。