简体   繁体   English

XNA:加载和读取XML文件的最佳方式?

[英]XNA: Best way to load and read a XML file?

I'm having difficulty doing this seemingly simple task. 我在完成这个看似简单的任务时遇到了困难。 I want to load XML files with the same ease of loading art assets: 我想加载XML文件,同样容易加载艺术资产:

        content  = new ContentManager(Services);
        content.RootDirectory = "Content";
        Texture2d background = content.Load<Texture2D>("images\\ice");

I'm not sure how to do this. 我不知道该怎么做。 This tutorial seems helpful, but how do I get a StorageDevice instance? 教程似乎很有帮助,但我如何获得StorageDevice实例?

I do have something working now, but it feels pretty hacky: 我现在有一些工作,但感觉非常hacky:

public IDictionary<string, string> Get(string typeName)
        {
            IDictionary<String, String> result = new Dictionary<String, String>();
            xmlReader.Read(); // get past the XML declaration

            string element = null;
            string text = null;

            while (xmlReader.Read())
            {

                switch (xmlReader.NodeType)
                {
                    case XmlNodeType.Element:
                        element = xmlReader.Name;
                        break;
                    case XmlNodeType.Text:
                        text = xmlReader.Value;
                        break;
                }

                if (text != null && element != null)
                {
                    result[element] = text;
                    text = null;
                    element = null;
                }

            }
            return result;
        }

I apply this to the following XML file: 我将其应用于以下XML文件:

<?xml version="1.0" encoding="utf-8" ?>
<zombies>
  <zombie>
    <health>100</health>
    <positionX>23</positionX>
    <positionY>12</positionY>
    <speed>2</speed>
  </zombie>
</zombies>

And it is able to pass this unit test: 它能够通过这个单元测试:

    internal virtual IPersistentState CreateIPersistentState(string fullpath)
    {
        IPersistentState target = new ReadWriteXML(File.Open(fullpath, FileMode.Open));
        return target;
    }

    /// <summary>
    ///A test for Get with one zombie.
    ///</summary>
    //[TestMethod()]
    public void SimpleGetTest()
    {
        string fullPath = "C:\\pathTo\\Data\\SavedZombies.xml";
        IPersistentState target = CreateIPersistentState(fullPath);
        string typeName = "zombie"; 

        IDictionary<string, string> expected = new Dictionary<string, string>();
        expected["health"] = "100";
        expected["positionX"] = "23";
        expected["positionY"] = "12";
        expected["speed"] = "2";

        IDictionary<string, string> actual = target.Get(typeName);

        foreach (KeyValuePair<string, string> entry in expected)
        {
            Assert.AreEqual(entry.Value, expected[entry.Key]);
        }
    }

Downsides to the current approach: file loading is done poorly, and matching keys to values seems like it's way more effort than necessary. 当前方法的缺点是:文件加载效果不佳,并且将值与值匹配似乎比不必要的更省力。 Also, I suspect this approach would fall apart with more than one entry in the XML. 此外,我怀疑这种方法会因XML中的多个条目而分崩离析。

I can't imagine that this is the optimal implementation. 我无法想象这是最佳实现。

UPDATE : Following the advice of @Peter Lillevold, I've changed this a bit: 更新 :根据@Peter Lillevold的建议,我改变了一点:

    public IDictionary<string, string> Get(string typeName)
    {
        IDictionary<String, String> result = new Dictionary<String, String>();

        IEnumerable<XElement> zombieValues = root.Element(@typeName).Elements();

        //result["health"] = zombie.Element("health").ToString();

        IDictionary<string, XElement> nameToElement = zombieValues.ToDictionary(element => element.Name.ToString());

        foreach (KeyValuePair<string, XElement> entry in nameToElement)
        {
            result[entry.Key] = entry.Value.FirstNode.ToString();
        }

        return result;
    }

    public ReadWriteXML(string uri)
    {
        root = XElement.Load(uri);
    }

    internal virtual IPersistentState CreateIPersistentState(string fullpath)
    {
        return new ReadWriteXML(fullpath);
    }

    /// <summary>
    ///A test for Get with one zombie.
    ///</summary>
    [TestMethod()]
    public void SimpleGetTest()
    {
        IPersistentState target = CreateIPersistentState("../../../path/Data/SavedZombies.xml");
        string typeName = "zombie"; 

        IDictionary<string, string> expected = new Dictionary<string, string>();
        expected["health"] = "100";
        expected["positionX"] = "23";
        expected["positionY"] = "12";
        expected["speed"] = "2";

        IDictionary<string, string> actual = target.Get(typeName);

        foreach (KeyValuePair<string, string> entry in expected)
        {
            Assert.AreEqual(entry.Value, actual[entry.Key]);
        }
    }

The loading is still pretty crappy, and somehow I wasn't able to get the one-line ToDictionary to work with those two lambdas. 加载仍然非常糟糕,不知怎的,我无法让单行ToDictionary与这两个lambdas一起工作。 I had to resort to that foreach loop. 我不得不求助于那个foreach循环。 What am I doing wrong there? 我在那里做错了什么?

There is also the new and shiny XElement (which sports Linq to XML ). 还有新的闪亮的XElement (将Linq转换为XML )。 This sample will load an xml file, look up the zombie and dump the values into a dictionary: 此示例将加载xml文件,查找僵尸并将值转储到字典中:

var doc = XElement.Load("filename");
var zombieValues = doc.Element("zombie").Elements();
var zombieDictionary = 
    zombieValues.ToDictionary(
        element => element.Name.ToString(), 
        element => element.Value);

If you'd rather pick each value explicitly (and use casting for automatically converting into proper value types) you can do: 如果您更愿意明确选择每个值(并使用强制转换为自动转换为正确的值类型),您可以执行以下操作:

var zombie = doc.Element("zombie");
var health = (int)zombie.Element("health");
var positionX = (int)zombie.Element("positionX");
var positionY = (int)zombie.Element("positionY");
var speed = (int)zombie.Element("speed");

Update: fixing some typos and cleaning up a bit, your Get method should look like this: 更新:修复一些拼写错误并清理一下,你的Get方法应如下所示:

public IDictionary<string, string> Get(string typeName)
{
    var zombie = root.Element(typeName);
    return zombie.Elements()
          .ToDictionary(
                  element => element.Name.ToString(),
                  element => element.Value);
}
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(xmlString);

string health = doc["zombies"]["zombie"]["health"].InnerText;
// etc..

// or looping

foreach( XmlNode node in doc["zombies"].ChildNodes )
{
    string health = node["health"].InnerText;
    // etc...
}

Or does that not work in XNA? 或者这在XNA中不起作用?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM