【问题标题】:XmlDocument.LoadXML NullReferenceExcpetion when it is assigned in the Unity InspectorXmlDocument.LoadXML NullReferenceExcpetion 在 Unity Inspector 中分​​配时
【发布时间】:2016-05-20 06:52:57
【问题描述】:

我有一个 XML 数据库(定制的),我正在尝试将其加载到 Unity3D 中。
我有一个公共 TextAsset,我在检查器中分配它以等于我的 XML 数据库。
当我运行我的脚本时,它会在 XMLDocument.loadxml() 线上抛出 NullReferenceException。
当我对此进行简化并仅使用 XML 格式的简单字符串并将其更改为 XMLDocument.Load() (具有相同的标签和数据)时,它就可以工作了。不过,这对于写作来说远远不够理想。

public TextAsset enemyXML;  
This one works--> //public string enemyXml = "<Enemy><EnemyName> Scale </EnemyName><EnemyID> 001 </EnemyID><EnemySpriteTag> Scale </EnemySpriteTag><EnemyBrawn>8  </EnemyBrawn><EnemyBrisk> 8 </EnemyBrisk><EnemyBrains>8</EnemyBrains>   <EnemyBravery> 10 </EnemyBravery><EnemyAbilitySet1> Scale </EnemyAbilitySet1>   <EnemyAbilitySet2> None </EnemyAbilitySet2><EnemyAbilitySet3> None    </EnemyAbilitySet3> <EnemyAbilitySet4> None </EnemyAbilitySet4></Enemy>"; 

XmlDocument xmlDoc = new XmlDocument();
This one works--> //xmlDoc.Load(new StringReader(enemyXml));
xmlDoc.LoadXml(enemyXml.text);
XmlNodeList enemyList = xmlDoc.GetElementsByTagName("Enemy");  
foreach (XmlNode enemyInfo in enemyList)
        {
        XmlNodeList EnemyContent = enemyInfo.ChildNodes;
        enemyDictionary = new Dictionary<string, string>(); //in Items tag, first tag, text associated with
        foreach (XmlNode content in EnemyContent)
        {
            switch(content.Name)//must contain all things for each item
            {
                case "EnemyName":
                    enemyDictionary.Add("EnemyName", content.InnerText);
                    break;
                case "EnemyID":
                    enemyDictionary.Add("EnemyID", content.InnerText);
                    break;
                case "EnemySpriteTag":
                    enemyDictionary.Add("EnemySpriteTag", content.InnerText);
                    break;
                case "EnemyBrawn":
                    enemyDictionary.Add("EnemyBrawn", content.InnerText);
                    break;
                case "EnemyBrisk":
                    enemyDictionary.Add("EnemyBrisk", content.InnerText);
                    break;
                case "EnemyBrains":
                    enemyDictionary.Add("EnemyBrains", content.InnerText);
                    break;
                case "EnemyBravery":
                    enemyDictionary.Add("EnemyBravery", content.InnerText);
                    break;
                case "EnemyAbilitySet1":
                    enemyDictionary.Add("EnemyAbilitySet1", content.InnerText);
                    break;
                case "EnemyAbilitySet2":
                    enemyDictionary.Add("EnemyAbilitySet2", content.InnerText);
                    break;
                case "EnemyAbilitySet3":
                    enemyDictionary.Add("EnemyAbilitySet3", content.InnerText);
                    break;
                case "EnemyAbilitySet4":
                    enemyDictionary.Add("EnemyAbilitySet4", content.InnerText);
                    break;
            }
        }
        EnemyDictionList.Add(enemyDictionary);
    }  

这就是我能想到的所有相关代码。 自定义 XML 文件被包裹在上面的字符串被推到中间。 我只是缺少拼写还是什么?这几天我一直很迷茫,也没有找到运气。

如果需要在编辑中,我可以包含类 BaseEnemy。

编辑: 这也适用于我的其余代码。

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(Path.Combine(Application.dataPath,"RPGEnemyDatabase.xml"));

但是,尝试在检查器中分配它,或者尝试说enemyXML.text,并没有。

【问题讨论】:

    标签: xml unity3d xml-parsing


    【解决方案1】:

    试试这个

    using System.IO;
    
    ...
    
    XmlDocument xmlDoc = new XmlDocument();
    
    string xmlContent = File.ReadAllText(enemyXML);
    
    xmlDoc.LoadXML(enemyXML);
    

    编辑:
    您可能想在这里看看我的解决方案:Unity C# How to set text as XML component?

    【讨论】:

    • 我玩了一下。到目前为止,无济于事。我发现有效的是不要在统一编辑器中分配它。如果我直接进入 xmlDoc.Load("FilePath");有用。这可能是 Unity 编辑器的问题吗?
    • 我不这么认为。我发布的另一个使用XmlSerializer 的解决方案(基本上是CloudSL 的版本)也使用通过检查器填充的public TextAsset。可能有问题的实际上是 XML 文件的结构。其他版本需要这种类型的嵌套结构才能工作 -> &lt;EnemyCollection&gt; &lt;Enemies&gt; &lt;Enemy&gt; stuff
    • 使用 CloudSL 的解决方案,我在 xml.text 行上收到 NullReferenceException。这包括在 Xml 文件中所做的更改。我在这里的困惑是,如果我只是输入文件的路径,并使用 xmldocument.load 它可以完美地工作。但是尝试将其加载为文本资产,我得到了错误。是否有理由不只是从那里获得路径和进步?
    • 对于您的解决方案来说,这可能没什么大不了的,但一般来说,通过检查器重新分配字段然后在重新构建文件夹时更改代码行会更容易。如果xml.text 给你一个 NullReferenceException ,这意味着公共字段为空(= 没有分配给它)。您确实将资产文件夹中的 xml 拖到了检查器中的该字段中吗?
    • 是的。它在插槽中有名称,以及所有内容。如果我点击播放它就在那里,当我退出播放模式时它仍然在那里。所以,我没有在播放模式下分配它。这对我来说是一个奇怪的错误。
    【解决方案2】:

    Xml 文件

    <EnemyCollection>
       <Enemies>
          <Enemy>
             <EnemyName>Scale</EnemyName>
             <EnemyID>001</EnemyID>
             <EnemySpriteTag>Scale</EnemySpriteTag>
             <EnemyBrawn>8</EnemyBrawn>
             <EnemyBrisk>8</EnemyBrisk>
             <EnemyBrains>8</EnemyBrains>   
             <EnemyBravery>10</EnemyBravery>
             <EnemyAbilitySet1>Scale</EnemyAbilitySet1>   
             <EnemyAbilitySet2>None</EnemyAbilitySet2>
             <EnemyAbilitySet3>None</EnemyAbilitySet3> 
             <EnemyAbilitySet4>None</EnemyAbilitySet4>
          </Enemy>
       </Enemies>
    </EnemyCollection>
    

    创建另一个类文件

    public class Enemy {
    
        public string EnemyName { get; set; }
        public string EnemyID { get; set; }
        public string EnemySpriteTag { get; set; }
        public string EnemyBrawn { get; set; }
        public string EnemyBrisk { get; set; }
        public string EnemyBrains { get; set; }
        public string EnemyBravery { get; set; }
        public string EnemyAbilitySet1 { get; set; }
        public string EnemyAbilitySet2 { get; set; }
        public string EnemyAbilitySet3 { get; set; }
        public string EnemyAbilitySet4 { get; set; }
    }
    
    [XmlRoot("EnemyCollection")]
    public class EnemiesContainer
    {
        [XmlArray("Enemies"), XmlArrayItem("Enemy")]
        public Enemy[] enemies;
    
        public static EnemiesContainer LoadFromText(string text)
        {
           var serializer = new XmlSerializer(typeof(EnemiesContainer));
           return serializer.Deserialize(new StringReader(text)) as EnemiesContainer;
        }
    
    }
    

    最后在您检索 xml 数据的主类中,您仍然会从 TextAsset 中读取 xml

    public TextAsset xml;
    
    void Start () {
    
        string xmlContent = xml.text;
        var enemyData = EnemiesContainer.LoadFromText(xmlContent);
    
    
        foreach (var enemy in enemyData.enemies)
        {
            Debug.Log(enemy.EnemyName);
            Debug.Log(enemy.EnemyID);
            Debug.Log(enemy.EnemySpriteTag);
            Debug.Log(enemy.EnemyBrawn);
            Debug.Log(enemy.EnemyBrisk);
            Debug.Log(enemy.EnemyBrains);
            //...
        }
    
    }
    

    供进一步参考 http://wiki.unity3d.com/index.php?title=Saving_and_Loading_Data:_XmlSerializer

    【讨论】:

    • 感谢您提供参考链接。我自己找不到那个。不知道为什么,也许我在我的 Google-fu 中很具体。此方法似乎为标签 Enemies 中的每个标签 Enemy 返回一个敌人对象。那是对的吗?还是我必须将每一个解析为一个 Enemy(Class) 对象?
    • 正确,这将返回一个敌人对象数组,其中将包含 Enemies 标签内的所有 Enemy 标签。
    • 回答为什么 NullReferenceException 如果你使用 textAsset 和从检查器分配的 xml 的问题,你是否偶然将 Start() 的 textAsset 初始化为 textAsset = new TextAsset() 如果是这样,这将覆盖你的 xmlfile从检查器添加为 null 新对象。如果您删除此特定行,它应该可以工作。
    • 遗憾的是,我从未将其重置为默认值。那将是一个很好的解决方案。我有另一个脚本,它几乎完全按照我在做的事情,只是带有不同的标签,并且那个有效。沿着小路走有什么特别的缺点吗?
    • 在检查器中将xml分配给textasset后,进入播放模式并再次检查检查器以查看文件是否仍然分配或None (Text Asset)
    猜你喜欢
    • 2019-07-08
    • 2022-12-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-10-18
    • 1970-01-01
    • 2020-09-29
    • 2016-12-10
    相关资源
    最近更新 更多