c# XML的浮点值问题
本文关键字:问题 XML | 更新日期: 2023-09-27 18:12:35
我刚开始使用xml,我有这个xml文件:
<?xml version="1.0" encoding="utf-8"?>
<Colonists>
<ColonistAmount amount="3" />
<Colonist num="1">
<BasicInfo Name="Susumu Croc Andersen" />
<BasicInfo Age="22" />
<BasicInfo Gender="1" />
<BasicInfo Trait1="Claustrophobic" />
<BasicInfo Trait2="Truthful" />
<Graphics BodyType="Thin" />
<Graphics SkinColor="0.9490196,0.9294118,0.8784314,1" />
<Graphics CrownType="Narrow" />
<Graphics HeadGraphicPath="Things/Pawn/Humanoid/Heads/Male/Male_Narrow_Pointy" />
<Graphics HairColor="0.9294118,0.7921569,0.6117647,1" />
<HairDef DefName="Wavy" />
<HairDef GraphicPath="Things/Pawn/Humanoid/Hairs/Wavy" />
<HairDef HairGender="Any" />
<HairTags Tag0="Urban" />
<HairTags Tag1="Rural" />
<HairDef Label="Wavy" />
<HairDef ShortHash="9521" />
<HairDef Selected="True" />
<Apparel>
<OnSkin Layer="OnSkin" Label="Button-down shirt" GraphicPath="Things/Pawn/Humanoid/Apparel/ShirtButton/ShirtButton" Color="1,0,0,1" />
<Shell Layer="Shell" Label="Duster" GraphicPath="Things/Pawn/Humanoid/Apparel/Duster/Duster" Color="1,0,0,1" />
</Apparel>
<Backstories>
<Childhood Index="190" />
<Adulthood Index="76" />
</Backstories>
<SkillPool Amount="40" />
<Skills Name="Construction" Value="0" Passion="1" />
<Skills Name="Growing" Value="0" Passion="2" />
<Skills Name="Research" Value="0" Passion="3" />
<Skills Name="Mining" Value="0" Passion="0" />
<Skills Name="Shooting" Value="0" Passion="0" />
<Skills Name="Melee" Value="0" Passion="0" />
<Skills Name="Social" Value="0" Passion="0" />
<Skills Name="Cooking" Value="0" Passion="0" />
<Skills Name="Medicine" Value="0" Passion="0" />
<Skills Name="Artistic" Value="0" Passion="0" />
<Skills Name="Crafting" Value="0" Passion="0" />
<End />
</Colonist>
<Colonist num="2">
<BasicInfo Name="Ignat Sir Juarez" />
<BasicInfo Age="27" />
<BasicInfo Gender="1" />
<BasicInfo Trait1="Careful" />
<BasicInfo Trait2="No self-awareness" />
<Graphics BodyType="Male" />
<Graphics SkinColor="1,0.9372549,0.7411765,1" />
<Graphics CrownType="Average" />
<Graphics HeadGraphicPath="Things/Pawn/Humanoid/Heads/Male/Male_Average_Normal" />
<Graphics HairColor="0.2,0.2,0.2,1" />
<HairDef DefName="Burgundy" />
<HairDef GraphicPath="Things/Pawn/Humanoid/Hairs/Burgundy" />
<HairDef HairGender="Male" />
<HairTags Tag0="Urban" />
<HairDef Label="Burgundy" />
<HairDef ShortHash="29636" />
<HairDef Selected="True" />
<Apparel>
<OnSkin Layer="OnSkin" Label="Button-down shirt" GraphicPath="Things/Pawn/Humanoid/Apparel/ShirtButton/ShirtButton" Color="0,1,0,1" />
<Shell Layer="Shell" Label="Duster" GraphicPath="Things/Pawn/Humanoid/Apparel/Duster/Duster" Color="0,1,0,1" />
</Apparel>
<Backstories>
<Childhood Index="134" />
<Adulthood Index="43" />
</Backstories>
<SkillPool Amount="40" />
<Skills Name="Construction" Value="0" Passion="1" />
<Skills Name="Growing" Value="0" Passion="2" />
<Skills Name="Research" Value="0" Passion="3" />
<Skills Name="Mining" Value="0" Passion="0" />
<Skills Name="Shooting" Value="0" Passion="0" />
<Skills Name="Melee" Value="0" Passion="0" />
<Skills Name="Social" Value="0" Passion="0" />
<Skills Name="Cooking" Value="0" Passion="0" />
<Skills Name="Medicine" Value="0" Passion="0" />
<Skills Name="Artistic" Value="0" Passion="0" />
<Skills Name="Crafting" Value="0" Passion="0" />
<End />
</Colonist>
<Colonist num="3">
<BasicInfo Name="Troy Guts Owens" />
<BasicInfo Age="63" />
<BasicInfo Gender="1" />
<BasicInfo Trait1="Poor self-esteem" />
<BasicInfo Trait2="Bad back" />
<Graphics BodyType="Male" />
<Graphics SkinColor="0.9490196,0.9294118,0.8784314,1" />
<Graphics CrownType="Average" />
<Graphics HeadGraphicPath="Things/Pawn/Humanoid/Heads/Male/Male_Average_Pointy" />
<Graphics HairColor="0.25,0.2,0.15,1" />
<HairDef DefName="Tuft" />
<HairDef GraphicPath="Things/Pawn/Humanoid/Hairs/Tuft" />
<HairDef HairGender="MaleUsually" />
<HairTags Tag0="Punk" />
<HairTags Tag1="Tribal" />
<HairDef Label="Tuft" />
<HairDef ShortHash="4402" />
<HairDef Selected="True" />
<Apparel>
<OnSkin Layer="OnSkin" Label="Button-down shirt" GraphicPath="Things/Pawn/Humanoid/Apparel/ShirtButton/ShirtButton" Color="0,0,1,1" />
<Shell Layer="Shell" Label="Duster" GraphicPath="Things/Pawn/Humanoid/Apparel/Duster/Duster" Color="0,0,1,1" />
</Apparel>
<Backstories>
<Childhood Index="196" />
<Adulthood Index="122" />
</Backstories>
<SkillPool Amount="40" />
<Skills Name="Construction" Value="0" Passion="1" />
<Skills Name="Growing" Value="0" Passion="2" />
<Skills Name="Research" Value="0" Passion="3" />
<Skills Name="Mining" Value="0" Passion="0" />
<Skills Name="Shooting" Value="0" Passion="0" />
<Skills Name="Melee" Value="0" Passion="0" />
<Skills Name="Social" Value="0" Passion="0" />
<Skills Name="Cooking" Value="0" Passion="0" />
<Skills Name="Medicine" Value="0" Passion="0" />
<Skills Name="Artistic" Value="0" Passion="0" />
<Skills Name="Crafting" Value="0" Passion="0" />
<End />
</Colonist>
</Colonists>
,我试图用以下代码反序列化(这是正确的术语吗?):
private static void RecurseXmlDocument(XmlNode root, ref int num, int tags, int skill)
{
if (num < ColonistManager.Population.Count)
{
if (root is XmlElement)
{
if (root.Name == "End")
{
skill = 0;
tags = 0;
num = num + 1;
}
if (root.Attributes != null)
{
foreach (XmlAttribute attribute in root.Attributes)
{
string text = attribute.Value;
if (root.Name == "BasicInfo" && attribute.Name == "Name")
{
string name = text;
List<string> namelist = new List<string>();
namelist = name.Split().ToList<string>();
ColonistManager.Population[num].FirstName = namelist[0];
ColonistManager.Population[num].NickName = namelist[1];
ColonistManager.Population[num].LastName = namelist[2];
}
else if (root.Name == "BasicInfo" && attribute.Name == "Age")
{
int age;
string value = text;
bool result = int.TryParse(value, out age);
ColonistManager.Population[num].Age = age;
}
else if (root.Name == "BasicInfo" && attribute.Name == "Gender")
{
int gender;
string value = text;
bool result = int.TryParse(value, out gender);
ColonistManager.Population[num].Gender = gender;
}
else if (root.Name == "BasicInfo" && attribute.Name == "Trait1")
{
ColonistManager.Population[num].Traits[0].TraitName = text;
}
else if (root.Name == "BasicInfo" && attribute.Name == "Trait2")
{
ColonistManager.Population[num].Traits[1].TraitName = text;
}
else if (root.Name == "Graphics" && attribute.Name == "BodyType")
{
int bodyType = 0;
if (text == "Male")
{
bodyType = 1;
}
else if (text == "Female")
{
bodyType = 2;
}
else if (text == "Thin")
{
bodyType = 3;
}
else if (text == "Hulk")
{
bodyType = 4;
}
else if (text == "Fat")
{
bodyType = 5;
}
ColonistManager.Population[num].BodyType = (BodyType)bodyType;
}
else if (root.Name == "Graphics" && attribute.Name == "SkinColor")
{
float fcolor = 0;
List<string> Colors = new List<string>();
List<float> fColors = new List<float>();
Colors = text.Split(',').ToList<string>();
foreach (string color in Colors)
{
bool result = float.TryParse(color, out fcolor);
fColors.Add(fcolor);
}
Color skinColor = new Color();
skinColor.r = fColors[0];
skinColor.g = fColors[1];
skinColor.b = fColors[2];
skinColor.a = fColors[3];
ColonistManager.Population[num].SkinColor = skinColor;
}
else if (root.Name == "Graphics" && attribute.Name == "CrownType")
{
int crownType = 0;
if (text == "Average")
{
crownType = 1;
}
else if (text == "Narrow")
{
crownType = 2;
}
ColonistManager.Population[num].CrownType = (CrownType)crownType;
}
else if (root.Name == "Graphics" && attribute.Name == "HeadGraphicPath")
{
ColonistManager.Population[num].HeadGraphicPath = text;
}
else if (root.Name == "Graphics" && attribute.Name == "HairColor")
{
float fcolor = 0;
List<string> Colors = new List<string>();
List<float> fColors = new List<float>();
Colors = text.Split(',').ToList<string>();
foreach (string color in Colors)
{
bool result = float.TryParse(color, out fcolor);
fColors.Add(fcolor);
}
Color hairColor = new Color();
hairColor.r = fColors[0];
hairColor.g = fColors[1];
hairColor.b = fColors[2];
hairColor.a = fColors[3];
ColonistManager.Population[num].HairColor = hairColor;
}
else if (root.Name == "HairDef" && attribute.Name == "DefName")
{
ColonistManager.Population[num].HairDefItem.hairDef.defName = text;
}
else if (root.Name == "HairDef" && attribute.Name == "GraphicPath")
{
ColonistManager.Population[num].HairDefItem.hairDef.graphicPath = text;
}
else if (root.Name == "HairDef" && attribute.Name == "HairGender")
{
int hairGender = 0;
if (text == "Any")
{
hairGender = 2;
}
else if (text == "Female")
{
hairGender = 4;
}
else if (text == "FemaleUsually")
{
hairGender = 3;
}
else if (text == "MaleUsually")
{
hairGender = 1;
}
ColonistManager.Population[num].HairDefItem.hairDef.hairGender = (HairGender)hairGender;
ColonistManager.Population[num].HairDefItem.hairDef.hairTags.Clear();
}
else if (root.Name == "HairTags")
{
ColonistManager.Population[num].HairDefItem.hairDef.hairTags.Add(text);
tags = tags + 1;
}
else if (root.Name == "HairDef" && attribute.Name == "Label")
{
ColonistManager.Population[num].HairDefItem.hairDef.label = text;
}
else if (root.Name == "HairDef" && attribute.Name == "ShortHash")
{
ushort shortHash = 0;
string value = text;
bool result = ushort.TryParse(value, out shortHash);
ColonistManager.Population[num].HairDefItem.hairDef.shortHash = shortHash;
}
else if (root.Name == "HairDef" && attribute.Name == "Selected")
{
if (text == "True")
{
ColonistManager.Population[num].HairDefItem.selected = true;
}
}
else if (root.Name == "OnSkin" && attribute.Name == "Layer")
{
ColonistManager.Population[num].Clothing[0].Layer = text;
}
else if (root.Name == "OnSkin" && attribute.Name == "Label")
{
ColonistManager.Population[num].Clothing[0].Label = text;
}
else if (root.Name == "OnSkin" && attribute.Name == "GraphicPath")
{
ColonistManager.Population[num].Clothing[0].GraphicPath = text;
}
else if (root.Name == "OnSkin" && attribute.Name == "Color")
{
float fcolor = 0;
List<string> Colors = new List<string>();
List<float> fColors = new List<float>();
Colors = text.Split(',').ToList<string>();
foreach (string color in Colors)
{
bool result = float.TryParse(color, out fcolor);
fColors.Add(fcolor);
}
Color clothColor = new Color();
clothColor.r = fColors[0];
clothColor.g = fColors[1];
clothColor.b = fColors[2];
clothColor.a = fColors[3];
ColonistManager.Population[num].Clothing[0].Color = clothColor;
Log.Message("Colonist " + num.ToString() + " Shirt Color Before: " + ColonistManager.Population[num].Clothing[0].Color.r.ToString() + ", " + ColonistManager.Population[num].Clothing[0].Color.g.ToString() + ", " + ColonistManager.Population[num].Clothing[0].Color.b.ToString() + ", " + ColonistManager.Population[num].Clothing[0].Color.a.ToString());
}
else if (root.Name == "Shell" && attribute.Name == "Layer")
{
ColonistManager.Population[num].Clothing[1].Layer = text;
}
else if (root.Name == "Shell" && attribute.Name == "Label")
{
ColonistManager.Population[num].Clothing[1].Label = text;
}
else if (root.Name == "Shell" && attribute.Name == "GraphicPath")
{
ColonistManager.Population[num].Clothing[1].GraphicPath = text;
}
else if (root.Name == "Shell" && attribute.Name == "Color")
{
float fcolor = 0;
List<string> Colors = new List<string>();
List<float> fColors = new List<float>();
Colors = text.Split(',').ToList<string>();
foreach (string color in Colors)
{
bool result = float.TryParse(color, out fcolor);
fColors.Add(fcolor);
}
Color clothColor = new Color();
clothColor.r = fColors[0];
clothColor.g = fColors[1];
clothColor.b = fColors[2];
clothColor.a = fColors[3];
ColonistManager.Population[num].Clothing[1].Color = clothColor;
Log.Message("Colonist " + num.ToString() + " Coat Color Before: " + ColonistManager.Population[num].Clothing[1].Color.r.ToString() + ", " + ColonistManager.Population[num].Clothing[1].Color.g.ToString() + ", " + ColonistManager.Population[num].Clothing[1].Color.b.ToString() + ", " + ColonistManager.Population[num].Clothing[1].Color.a.ToString());
}
else if (root.Name == "Childhood" && attribute.Name == "Index")
{
int index;
string value = text;
bool result = int.TryParse(value, out index);
ColonistManager.Population[num].Backstory[0] = ColonistManager.Backstories[index];
}
else if (root.Name == "Adulthood" && attribute.Name == "Index")
{
int index;
string value = text;
bool result = int.TryParse(value, out index);
ColonistManager.Population[num].Backstory[1] = ColonistManager.Backstories[index];
}
else if (root.Name == "SkillPool" && attribute.Name == "Amount")
{
int amount;
string value = text;
bool result = int.TryParse(value, out amount);
ColonistManager.Population[num].SkillPool = amount;
}
else if (root.Name == "Skills" && attribute.Name == "Value")
{
int skillValue;
string value = text;
bool result = int.TryParse(value, out skillValue);
ColonistManager.Population[num].Skills[skill].SkillValue += skillValue;
}
else if (root.Name == "Skills" && attribute.Name == "Passion")
{
int skillPassion;
string value = text;
bool result = int.TryParse(value, out skillPassion);
ColonistManager.Population[num].Skills[skill].SkillPassion = skillPassion;
skill = skill + 1;
}
}
}
if (root.HasChildNodes)
RecurseXmlDocument(root.FirstChild, ref num, tags, skill);
if (root.NextSibling != null)
RecurseXmlDocument(root.NextSibling, ref num, tags, skill);
}
}
}
所有内容都正确导入,日志文件为:
Colonist 0 Shirt Color Before: 1, 0, 0, 1
Colonist 0 Coat Color Before: 1, 0, 0, 1
Colonist 1 Shirt Color Before: 0, 1, 0, 1
Colonist 1 Coat Color Before: 0, 1, 0, 1
Colonist 2 Shirt Color Before: 0, 0, 1, 1
Colonist 2 Coat Color Before: 0, 0, 1, 1
但是当我用这段代码重新检查值时:
private static void VerifyLoad()
{
for (int i = 0; i < ColonistManager.Population.Count; i++)
{
Log.Message("Colonist " + i.ToString() + " Shirt Color After: " + ColonistManager.Population[i].Clothing[0].Color.r.ToString() + ", " + ColonistManager.Population[i].Clothing[0].Color.g.ToString() + ", " + ColonistManager.Population[i].Clothing[0].Color.b.ToString() + ", " + ColonistManager.Population[i].Clothing[0].Color.a.ToString());
Log.Message("Colonist " + i.ToString() + " Coat Color After: " + ColonistManager.Population[i].Clothing[1].Color.r.ToString() + ", " + ColonistManager.Population[i].Clothing[1].Color.g.ToString() + ", " + ColonistManager.Population[i].Clothing[1].Color.b.ToString() + ", " + ColonistManager.Population[i].Clothing[1].Color.a.ToString());
}
}
日志显示:
Colonist 0 Shirt Color After: 0, 0, 1, 1
Colonist 0 Coat Color After: 1, 0, 0, 1
Colonist 1 Shirt Color After: 0, 0, 1, 1
Colonist 1 Coat Color After: 0, 0, 1, 1
Colonist 2 Shirt Color After: 0, 0, 1, 1
Colonist 2 Coat Color After: 0, 0, 1, 1
我完全不明白为什么变量会突然改变,所以任何帮助都会非常感激!
大多数情况下,可以简单地使用XmlSerializer从Xml转换为对象。在您的例子中,Xml不太适合自动序列化,因为在具有相同名称但不同属性的类似元素(例如:BasicInfo、Graphics元素)和具有多个值的属性(例如:所有Color属性)中使用了不规则的约定。因此,像您所做的那样手动解析似乎是处理这种特定Xml的最佳方法。
但是,您遇到的问题是在解析逻辑中。如果您清理了解析逻辑,可能会更容易发现问题。一个庞大的递归方法和一堆if
语句将很难调试。
考虑使用访问者模式重写解析逻辑。您的代码将更容易维护和修改。下面是如何在特定Xml上使用访问者模式的示例。当我运行这个程序时,我得到了预期的结果。
static void Main()
{
List<Colonist> colonists = Parse();
for (int i = 0; i < colonists.Count; i++)
{
Console.WriteLine("Colonist " + i.ToString() + " Shirt Color After: " + colonists[i].Clothing[0].Color.R.ToString() + ", " + colonists[i].Clothing[0].Color.G.ToString() + ", " + colonists[i].Clothing[0].Color.B.ToString() + ", " + colonists[i].Clothing[0].Color.A.ToString());
Console.WriteLine("Colonist " + i.ToString() + " Coat Color After: " + colonists[i].Clothing[1].Color.R.ToString() + ", " + colonists[i].Clothing[1].Color.G.ToString() + ", " + colonists[i].Clothing[1].Color.B.ToString() + ", " + colonists[i].Clothing[1].Color.A.ToString());
}
}
private static List<Colonist> Parse()
{
List<Colonist> colonists = new List<Colonist>();
using (XmlTextReader reader = new XmlTextReader(File.OpenRead("XMLFile1.xml")))
{
while (reader.Read())
{
switch (reader.Name)
{
case "Colonist":
var colonist = VisitColonist(reader);
colonists.Add(colonist);
break;
}
}
}
return colonists;
}
private static Colonist VisitColonist(XmlTextReader reader)
{
Colonist colonist = new Colonist();
while (reader.Read())
{
if (reader.Name == "Colonist" && reader.NodeType == XmlNodeType.EndElement)
break;
switch(reader.Name)
{
case "BasicInfo":
VisitBasicInfo(reader, colonist);
break;
case "OnSkin":
VisitOnSkin(reader, colonist);
break;
case "Shell":
VisitShell(reader, colonist);
break;
}
}
return colonist;
}
private static void VisitBasicInfo(XmlTextReader reader, Colonist colonist)
{
while (reader.MoveToNextAttribute())
{
switch(reader.Name)
{
case "Name":
var parts = reader.Value.Split(' ');
colonist.FirstName = parts[0];
colonist.NickName = parts[1];
colonist.LastName = parts[2];
break;
case "Age":
colonist.Age = Int32.Parse(reader.Value);
break;
}
}
}
private static void VisitOnSkin(XmlTextReader reader, Colonist colonist)
{
Clothing clothing = new Clothing();
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "Color":
clothing.Color = GetColor(reader.Value);
break;
}
}
colonist.Clothing[0] = clothing;
}
private static void VisitShell(XmlTextReader reader, Colonist colonist)
{
Clothing clothing = new Clothing();
while (reader.MoveToNextAttribute())
{
switch (reader.Name)
{
case "Color":
clothing.Color = GetColor(reader.Value);
break;
}
}
colonist.Clothing[1] = clothing;
}
private static Color GetColor(string colorValue)
{
var parts = colorValue.Split(',');
Color color = new Color {
R = Single.Parse(parts[0]),
G = Single.Parse(parts[1]),
B = Single.Parse(parts[2]),
A = Single.Parse(parts[3])
};
return color;
}
我只是解析了文件的一部分。下面是我使用的类:
public class Colonist
{
public string FirstName { get; set; }
public string NickName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public Clothing[] Clothing { get; set; }
public Colonist()
{
Clothing = new Clothing[2];
}
}
public class Clothing
{
public Color Color { get; set; }
}
public class Color
{
public float R { get; set; }
public float G { get; set; }
public float B { get; set; }
public float A { get; set; }
}