访客模式循环问题

时间:2014-07-14 02:46:25

标签: c# xml parsing loops visitor-pattern

我正在使用以下访问者模式代码来解析xml文件:

using RimWorld;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using UnityEngine;
using Verse;

namespace ColonistCreationMod
{
class LoadColonists
{
    public static void LoadFromFile(Map map, string groupName)
    {
        try
        {
            string path = Directory.GetParent(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)).FullName;
            if (Environment.OSVersion.Version.Major >= 6)
            {
                path = Directory.GetParent(path).FullName;
            }
            path += "\\AppData\\LocalLow\\Ludeon Studios\\RimWorld\\CharSaves\\" + groupName + ".col";
            ColonistRegen(path);
            Parse(path);
        }
        catch (Exception e)
        {
            Log.Message(e.Message);
        }
        GC.Collect();
    }

    private static void ColonistRegen(string file)
    {
        using (XmlTextReader reader = new XmlTextReader(File.OpenRead(file)))
        {
            while (reader.Read())
            {
                switch (reader.Name)
                {
                    case "ColonistAmount":
                        ColonistNum.Amount = VisitAmount(reader);
                        ColonistManager.RandomColonists();
                        ModdedMapInitParams.GenerateColonists();
                        break;
                }
            }
        }
    }

    private static int VisitAmount(XmlTextReader reader)
    {
        int amount = 0;
        while (reader.MoveToNextAttribute())
        {
            switch (reader.Name)
            {
                case "amount":
                    amount = int.Parse(reader.Value);
                    break;
            }
        }

        return amount;
    }

    private static void Parse(string file)
    {
        using (XmlTextReader reader = new XmlTextReader(File.OpenRead(file)))
        {
            int i = 0;
            while (reader.Read())
            {
                switch (reader.Name)
                {
                    case "Colonist":
                        Log.Message("Colonist: " + i.ToString());
                        VisitColonist(reader, i);
                        i++;
                        break;
                }
            }
        }
    }

    private static void VisitColonist(XmlTextReader reader, int i)
    {
        while (reader.Read())
        {
            if (reader.Name == "Colonist" && reader.NodeType == XmlNodeType.EndElement)
                break;

            switch (reader.Name)
            {
                case "BasicInfo":
                    VisitBasicInfo(reader, i);
                    break;

                case "Graphics":
                    VisitGraphics(reader, i);
                    break;

                case "HairDef":
                    VisitHairDef(reader, i);
                    break;

                case "OnSkin":
                    VisitOnSkin(reader, i);
                    break;

                case "Shell":
                    VisitShell(reader, i);
                    break;

                case "Childhood":
                    VisitChildhood(reader, i);
                    break;

                case "Adulthood":
                    VisitAdulthood(reader, i);
                    break;

                case "SkillPool":
                    VisitSkillPool(reader, i);
                    break;

                case "Skills":
                    VisitSkills(reader, i);
                    break;
            }
        }
    }

    private static void VisitBasicInfo(XmlTextReader reader, int i)
    {
        while (reader.MoveToNextAttribute())
        {
            switch (reader.Name)
            {
                case "Name":
                    var parts = reader.Value.Split(' ');
                    ColonistManager.Population[i].FirstName = parts[0];
                    ColonistManager.Population[i].NickName = parts[1];
                    ColonistManager.Population[i].LastName = parts[2];
                    Log.Message("Colonist Name: " + ColonistManager.Population[i].FirstName + ColonistManager.Population[i].NickName + ColonistManager.Population[i].LastName);
                    break;

                case "Age":
                    ColonistManager.Population[i].Age = int.Parse(reader.Value);
                    Log.Message("Colonist Age: " + ColonistManager.Population[i].Age.ToString());
                    break;
            }
        }
    }

    private static void VisitGraphics(XmlTextReader reader, int i)
    {
        while (reader.MoveToNextAttribute())
        {
            switch (reader.Name)
            {
                case "BodyType":
                    string body = reader.Value;
                    int bodyType = 0;
                    if (body == "Male")
                    {
                        bodyType = 1;
                    }
                    else if (body == "Female")
                    {
                        bodyType = 2;
                    }
                    else if (body == "Thin")
                    {
                        bodyType = 3;
                    }
                    else if (body == "Hulk")
                    {
                        bodyType = 4;
                    }
                    else if (body == "Fat")
                    {
                        bodyType = 5;
                    }
                    ColonistManager.Population[i].BodyType = (BodyType)bodyType;
                    Log.Message("Colonist BodyType: " + ColonistManager.Population[i].BodyType.ToString());
                    break;

                case "SkinColor":
                    ColonistManager.Population[i].SkinColor = GetColor(reader.Value);
                    Log.Message("Colonist SkinColor: " + ColonistManager.Population[i].SkinColor.r.ToString() + ", " + ColonistManager.Population[i].SkinColor.g.ToString() + ", " + ColonistManager.Population[i].SkinColor.b.ToString() + ", " + ColonistManager.Population[i].SkinColor.a.ToString());
                    break;

                case "CrownType":
                    string crown = reader.Value;
                    int crownType = 0;
                    if (crown == "Average")
                    {
                        crownType = 1;
                    }
                    else if (crown == "Narrow")
                    {
                        crownType = 2;
                    }
                    ColonistManager.Population[i].CrownType = (CrownType)crownType;
                    break;

                case "HeadGraphicPath":
                    ColonistManager.Population[i].HeadGraphicPath = reader.Value;
                    break;

                case "HairColor":
                    ColonistManager.Population[i].HairColor = GetColor(reader.Value);
                    break;
            }
        }
    }

    private static void VisitHairDef(XmlTextReader reader, int i)
    {
        ColHairDef hairDef = new ColHairDef();

        while (reader.MoveToNextAttribute())
        {
            switch (reader.Name)
            {
                case "DefName":
                    hairDef.DefName = reader.Value;
                    break;

                case "GraphicPath":
                    hairDef.GraphicPath = reader.Value;
                    break;

                case "HairGender":
                    string hair = reader.Value;
                    int hairGender = 0;
                    if (hair == "Any")
                    {
                        hairGender = 2;
                    }
                    else if (hair == "Female")
                    {
                        hairGender = 4;
                    }
                    else if (hair == "FemaleUsually")
                    {
                        hairGender = 3;
                    }
                    else if (hair == "MaleUsually")
                    {
                        hairGender = 1;
                    }
                    hairDef.HairGender = (HairGender)hairGender;
                    break;

                case "Label":
                    hairDef.Label = reader.Value;
                    break;

                case "Tags":
                    hairDef.HairTags = GetTags(reader.Value);
                    ColonistManager.Population[i].HairDef = hairDef;
                    break;
            }
        }
    }

    private static List<string> GetTags(string tagList)
    {
        List<string> tags = tagList.Split(',').ToList<string>();
        return tags;
    }

    private static void VisitOnSkin(XmlTextReader reader, int i)
    {
        Clothing clothing = new Clothing();

        while (reader.MoveToNextAttribute())
        {
            switch (reader.Name)
            {
                case "Layer":
                    clothing.Layer = reader.Value;
                    break;

                case "Label":
                    clothing.Label = reader.Value;
                    break;

                case "GraphicPath":
                    clothing.GraphicPath = reader.Value;
                    break;

                case "Color":
                    clothing.Color = GetColor(reader.Value);
                    break;
            }
        }
        ColonistManager.Population[i].Clothing[0] = clothing;
    }

    private static void VisitShell(XmlTextReader reader, int i)
    {
        Clothing clothing = new Clothing();

        while (reader.MoveToNextAttribute())
        {
            switch (reader.Name)
            {
                case "Layer":
                    clothing.Layer = reader.Value;
                    break;

                case "Label":
                    clothing.Label = reader.Value;
                    break;

                case "GraphicPath":
                    clothing.GraphicPath = reader.Value;
                    break;

                case "Color":
                    clothing.Color = GetColor(reader.Value);
                    break;
            }
        }
        ColonistManager.Population[i].Clothing[1] = clothing;
    }

    private static Color GetColor(string colorValue)
    {
        var parts = colorValue.Split(',');
        Color color = new Color();
        color.r = Single.Parse(parts[0]);
        color.g = Single.Parse(parts[1]);
        color.b = Single.Parse(parts[2]);
        color.a = Single.Parse(parts[3]);

        return color;
    }

    private static void VisitChildhood(XmlTextReader reader, int i)
    {
        while (reader.MoveToNextAttribute())
        {
            switch (reader.Name)
            {
                case "Index":
                    ColonistManager.Population[i].Backstory[0] = ColonistManager.Backstories[int.Parse(reader.Value)];
                    break;
            }
        }
    }

    private static void VisitAdulthood(XmlTextReader reader, int i)
    {
        while (reader.MoveToNextAttribute())
        {
            switch (reader.Name)
            {
                case "Index":
                    ColonistManager.Population[i].Backstory[1] = ColonistManager.Backstories[int.Parse(reader.Value)];
                    break;
            }
        }
    }

    private static void VisitSkillPool(XmlTextReader reader, int i)
    {
        while (reader.MoveToNextAttribute())
        {
            switch (reader.Name)
            {
                case "Amount":
                    ColonistManager.Population[i].SkillPool = int.Parse(reader.Value);
                    break;
            }
        }
    }

    private static void VisitSkills(XmlTextReader reader, int i)
    {
        while (reader.MoveToNextAttribute())
        {
            string name = "";
            int value = 0;
            switch (reader.Name)
            {
                case "Name":
                    name = reader.Value;
                    break;

                case "Value":
                    value = int.Parse(reader.Value);
                    break;

                case "Passion":
                    value = int.Parse(reader.Value);
                    if (name == "Construction")
                    {
                        ColonistManager.Population[i].Skills[0].SkillName = name;
                        ColonistManager.Population[i].Skills[0].SkillValue = value;
                        ColonistManager.Population[i].Skills[0].SkillPassion = int.Parse(reader.Value);
                    }
                    else if (name == "Growing")
                    {
                        ColonistManager.Population[i].Skills[1].SkillName = name;
                        ColonistManager.Population[i].Skills[1].SkillValue = value;
                        ColonistManager.Population[i].Skills[1].SkillPassion = int.Parse(reader.Value);
                    }
                    else if (name == "Research")
                    {
                        ColonistManager.Population[i].Skills[2].SkillName = name;
                        ColonistManager.Population[i].Skills[2].SkillValue = value;
                        ColonistManager.Population[i].Skills[2].SkillPassion = int.Parse(reader.Value);
                    }
                    else if (name == "Mining")
                    {
                        ColonistManager.Population[i].Skills[3].SkillName = name;
                        ColonistManager.Population[i].Skills[3].SkillValue = value;
                        ColonistManager.Population[i].Skills[3].SkillPassion = int.Parse(reader.Value);
                    }
                    else if (name == "Shooting")
                    {
                        ColonistManager.Population[i].Skills[4].SkillName = name;
                        ColonistManager.Population[i].Skills[4].SkillValue = value;
                        ColonistManager.Population[i].Skills[4].SkillPassion = int.Parse(reader.Value);
                    }
                    else if (name == "Melee")
                    {
                        ColonistManager.Population[i].Skills[5].SkillName = name;
                        ColonistManager.Population[i].Skills[5].SkillValue = value;
                        ColonistManager.Population[i].Skills[5].SkillPassion = int.Parse(reader.Value);
                    }
                    else if (name == "Social")
                    {
                        ColonistManager.Population[i].Skills[6].SkillName = name;
                        ColonistManager.Population[i].Skills[6].SkillValue = value;
                        ColonistManager.Population[i].Skills[6].SkillPassion = int.Parse(reader.Value);
                    }
                    else if (name == "Cooking")
                    {
                        ColonistManager.Population[i].Skills[7].SkillName = name;
                        ColonistManager.Population[i].Skills[7].SkillValue = value;
                        ColonistManager.Population[i].Skills[7].SkillPassion = int.Parse(reader.Value);
                    }
                    else if (name == "Medicine")
                    {
                        ColonistManager.Population[i].Skills[8].SkillName = name;
                        ColonistManager.Population[i].Skills[8].SkillValue = value;
                        ColonistManager.Population[i].Skills[8].SkillPassion = int.Parse(reader.Value);
                    }
                    else if (name == "Artistic")
                    {
                        ColonistManager.Population[i].Skills[9].SkillName = name;
                        ColonistManager.Population[i].Skills[9].SkillValue = value;
                        ColonistManager.Population[i].Skills[9].SkillPassion = int.Parse(reader.Value);
                    }
                    else if (name == "Crafting")
                    {
                        ColonistManager.Population[i].Skills[10].SkillName = name;
                        ColonistManager.Population[i].Skills[10].SkillValue = value;
                        ColonistManager.Population[i].Skills[10].SkillPassion = int.Parse(reader.Value);
                    }
                    break;
            }
        }
    }
}

}

这是xml文件:

<?xml version="1.0" encoding="utf-8"?>
<Colonists>
<ColonistAmount amount="1" />
<Colonist num="1">
    <BasicInfo Name="Argain Don Bentham" />
    <BasicInfo Age="29" />
    <BasicInfo Gender="1" />
    <BasicInfo Trait1="Gadgeteer" />
    <BasicInfo Trait2="Knitter" />
    <Graphics BodyType="Thin" />
    <Graphics SkinColor="0.9490196,0.9294118,0.8784314,1" />
    <Graphics CrownType="Narrow" />
    <Graphics HeadGraphicPath="Things/Pawn/Humanoid/Heads/Female/Female_Narrow_Wide" />
    <Graphics HairColor="0.5,0.5,0.5,1" />
    <HairDef DefName="Mop" />
    <HairDef GraphicPath="Things/Pawn/Humanoid/Hairs/Mop" />
    <HairDef HairGender="MaleUsually" />
    <HairDef Label="Mop" />
    <HairDef Tags="Urban,Rural" />
    <Apparel>
        <OnSkin Layer="OnSkin" Label="Button-down shirt" GraphicPath="Things/Pawn/Humanoid/Apparel/ShirtButton/ShirtButton" Color="1,1,1,1" />
        <Shell Layer="Shell" Label="Duster" GraphicPath="Things/Pawn/Humanoid/Apparel/Duster/Duster" Color="0,0,0,1" />
    </Apparel>
    <Backstories>
        <Childhood Index="177" />
        <Adulthood Index="26" />
    </Backstories>
    <SkillPool Amount="0" />
    <Skills Name="Construction" Value="0" Passion="0" />
    <Skills Name="Growing" Value="0" Passion="0" />
    <Skills Name="Research" Value="6" Passion="0" />
    <Skills Name="Mining" Value="0" Passion="0" />
    <Skills Name="Shooting" Value="16" Passion="2" />
    <Skills Name="Melee" Value="0" Passion="1" />
    <Skills Name="Social" Value="18" Passion="3" />
    <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>

我刚开始使用这种“访问者模式”样式,并且通过VisitHairDef方法遇到代码循环5次的问题。每次此方法循环时,都会重新创建HairDef对象,并且在将其写入ColonistManager.Population[i].HairDef对象之前,每个循环只存储一条信息。因此,最终结果只有一个变量存储在ColonistManager.Population[i].HairDef中。我不知道为什么这个特殊的部分正在循环,我希望有更多经验的人可以为我揭示它。如果需要更多信息,我已将整个源代码上传到dropbox:https://www.dropbox.com/s/eeq8hwwaoa2ld0b/ColonistCreationMod%20Source.zip

2 个答案:

答案 0 :(得分:0)

使其Colonist.HairDef的构造函数中初始化Colonist。然后在VisitHairDef中,直接在ColonistManager.Population[i].HairDef上设置属性。

public class Colonist
{ 
    public HairDef HairDef { get; set; }

    public Colonist()
    {
        HairDef = new HairDef();
    }
}


private static void VisitHairDef(XmlTextReader reader, int i)
{
    //ColHairDef hairDef = new ColHairDef();

    while (reader.MoveToNextAttribute())
    {
        switch (reader.Name)
        {
            case "DefName":
                ColonistManager.Population[i].HairDef.DefName = reader.Value;
                break;

            case "GraphicPath":
                ColonistManager.Population[i].HairDef.GraphicPath = reader.Value;
                break;

            case "HairGender":
                string hair = reader.Value;
                int hairGender = 0;
                if (hair == "Any")
                {
                    hairGender = 2;
                }
                else if (hair == "Female")
                {
                    hairGender = 4;
                }
                else if (hair == "FemaleUsually")
                {
                    hairGender = 3;
                }
                else if (hair == "MaleUsually")
                {
                    hairGender = 1;
                }
                ColonistManager.Population[i].HairDef.HairGender = (HairGender)hairGender;
                break;

            case "Label":
                ColonistManager.Population[i].HairDef.Label = reader.Value;
                break;

            case "Tags":
                ColonistManager.Population[i].HairDef.HairTags = GetTags(reader.Value);
                //ColonistManager.Population[i].HairDef = hairDef;
                break;
        }
    }
}

答案 1 :(得分:0)

我发现这是xml文件本身的一个问题...... VisitOnSkin方法与方法中的Clothing clothing = new Clothing();完美配合,因为xml是这样的:

<OnSkin Layer="OnSkin" Label="Button-down shirt" GraphicPath="Things/Pawn/Humanoid/Apparel/ShirtButton/ShirtButton" Color="1,1,1,1" />

然而,HairDef的xml并没有很多属性嵌套在一个节点中......一旦我将所有属性设置在一个&#34; HairDef&#34;像这样的节点:

<HairDef DefName="Mop" GraphicPath="Things/Pawn/Humanoid/Hairs/Mop" HairGender="MaleUsually" Label="Mop" Tags="Urban,Rural" />

然后一切顺利:D