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

我完全不明白为什么变量会突然改变,所以任何帮助都会非常感激!

c# XML的浮点值问题

大多数情况下,可以简单地使用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; }
}