【问题标题】:Use only parts of an xml-file仅使用 xml 文件的一部分
【发布时间】:2020-05-01 05:05:01
【问题描述】:

我对 Unity 和 C# 比较陌生。其实我主要是看应用代码,试着学一点。这很有趣。

现在我偶然发现了一个问题。

我正在尝试读取 XML 文件并继续使用其中的数据。这甚至有效。但是现在我不想使用 XML 文件的所有记录,而只想使用那些具有特定 ID 的记录。

目前我是这样做的:

public class Data
{
    public frage[] fragen = new frage[0];

    public Data () { }

    public static void Write(Data data)
    {
        XmlSerializer serializer = new XmlSerializer(typeof(Data));
        using (Stream stream = new FileStream (GameUtility.XmlFilePath, FileMode.Create))
        {
            serializer.Serialize(stream, data);
        }
    }
    public static Data Fetch ()
    {
        return Fetch(out bool result);
    }
    public static Data Fetch(out bool result)
    {
        if (!File.Exists(GameUtility.XmlFilePath)) { result = false; return new Data(); }

        XmlSerializer deserializer = new XmlSerializer(typeof(Data));
        using (Stream stream = new FileStream(GameUtility.XmlFilePath, FileMode.Open))
        {
            var data = (Data)deserializer.Deserialize(stream);
            result = true;

            return data;
        }
    }
}

我认为这导致所有数据都存储在相应的变量(数据)中。但是现在我只想传输那些 ID 为 5 的数据集。这是否可以通过简单的调整来实现,还是我必须考虑所有问题?

我的数据集是通过 XML 创建的,如下所示:

<?xml version="1.0"?>
<Data xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <fragen>
    <frage>
      <info>IRGENDEINTEXT1</info>
      <antworten>
        <antwort>
          <info>1</info>
          <korrekt>true</korrekt>
        </antwort>
        <antwort>
          <info>2</info>
          <korrekt>false</korrekt>
        </antwort>
        <antwort>
          <info>3</info>
          <korrekt>false</korrekt>
        </antwort>
        <antwort>
          <info>4</info>
          <korrekt>false</korrekt>
        </antwort>
      </antworten>
      <id>5</id>
    </frage>
    <frage>
      <info>IRGENDEINTEXT2</info>
      <antworten>
        <antwort>
          <info>1</info>
          <korrekt>false</korrekt>
        </antwort>
        <antwort>
          <info>2</info>
          <korrekt>false</korrekt>
        </antwort>
        <antwort>
          <info>3</info>
          <korrekt>false</korrekt>
        </antwort>
        <antwort>
          <info>4</info>
          <korrekt>true</korrekt>
        </antwort>
      </antworten>
      <id>7</id>
    </frage>
  </fragen>
</Data>

谢谢 - 我希望我的问题是有意义的,而不是太不清楚。原谅我不正确的英语。

【问题讨论】:

    标签: c# xml unity3d serialization


    【解决方案1】:

    你可以有,但我建议不要一直只读取部分文件,因为那是一个持续的 IO 命中。每次您需要获取一个新问题时,您都会在磁盘上获得另一个读取 IO。除非您的问题集很庞大(例如数百 MB),否则您可以在游戏开始时将所有数据读入您的 Data 对象,然后只需在您的 Data 类中添加一个帮助函数,为您提供相关信息。例如

    class Data {
       private Frage[] fragen;   
    
       // Read a Frage by ID
       public Frage QuestionById(string id) {
           return this.fragen.First(it => it.id == id);
       }
    
    }
    

    答案相同:

    class Frage {
        private Antwort[] antworten;
        public Antwort GetCorrectAnswer() {
           return antworten.First(it => it.korrekt);
        }
    }
    

    然后在你的游戏逻辑中你可以调用:

    var aFrage = data.QuestionById("4711");
    var anAntwort = aFrage.GetCorrectAnswer();
    

    理论上,您也可以使用 XPath 来选择您需要的 XML 节点,但要使其工作,您仍然需要将整个 XML 文档加载到内存中以便在其上运行您的 XPath(我不知道有任何适用于流的 .net 的 XPath 实现)。因此,您也可以使用自己的数据结构,就像我已经列出的那样。

    如果您确实需要一个庞大的数据集并且无法将所有内容都加载到内存中,您可能应该查看一些数据库解决方案,例如SQLite 来存储你的数据。这将允许您执行 SQL DB 查询,并且不需要您将所有数据加载到内存中。

    【讨论】:

    • 这是一个难以置信的帮助。按照您的建议,我可以通过一些调整来解决我的问题。
    【解决方案2】:

    我同意 Jan Thomä 的观点。您所做的称为反序列化(当您从对象创建 xml 或 json 时,您会进行序列化)。因此,您只需从您的 xml 文件创建一个对象(当然,从技术上讲,您需要读取该文件以对其进行反序列化,但当然,您使用一个库来处理它)。获得数据后,您应该能够更改对象或使用正确的数据创建修改后的副本。

    通常我更喜欢 json,所以我不知道如何使用 XmlSerializer 库(与编辑部分中的示例链接)但你应该创建一个 bean 对象,它是你的 xml 文件的表示 (例如 antwort 是基本对象之一,它应该有一个 int info 变量和一个 korrekt 布尔变量,而 antwort 是一个仅包含 antwort 列表的对象,依此类推,直到您到达包含所有基本对象的主要对象 fragen描述要反序列化的 xml bean(要创建一个 bean,只需声明您的变量和这些变量的 Getter/Setter))

    之后,您只需将 xml 反序列化为 Fragen 而不是 Data 类型,然后您就可以轻松地更改对象。

    编辑。为了更好地理解它,只需查看此处的示例: https://docs.microsoft.com/it-it/dotnet/api/system.xml.serialization.xmlserializer.deserialize?view=netframework-4.8

    你得到了代表对象 OrderedItem 的 xml 和类(注意:命名空间应该是可选的,但是你需要在你的 xml 中调用具有相同名称的变量,并且你应该需要在 OrderedItem 类中使用 getter 和 setter )。一旦你得到了 OrderedItem 项,就很容易读取/写入对象的新值,用新数据序列化新的 xml,或者只是创建对象的修改副本。 你应该做同样的事情。

    链接示例:

    using System;
    using System.IO;
    using System.Xml.Serialization;
    
    // This is the class that will be deserialized.
    public class OrderedItem
    {
        [XmlElement(Namespace = "http://www.cpandl.com")]
        public string ItemName;
        [XmlElement(Namespace = "http://www.cpandl.com")]
        public string Description;
        [XmlElement(Namespace="http://www.cohowinery.com")]
        public decimal UnitPrice;
        [XmlElement(Namespace = "http://www.cpandl.com")]
        public int Quantity;
        [XmlElement(Namespace="http://www.cohowinery.com")]
        public decimal LineTotal;
        // A custom method used to calculate price per item.
        public void Calculate()
        {
            LineTotal = UnitPrice * Quantity;
        }
    }
    
    public class Test
    {
        public static void Main()
        {
            Test t = new Test();
            // Read a purchase order.
            t.DeserializeObject("simple.xml");
        }
    
        private void DeserializeObject(string filename)
        {   
            Console.WriteLine("Reading with Stream");
            // Create an instance of the XmlSerializer.
            XmlSerializer serializer = 
            new XmlSerializer(typeof(OrderedItem));
    
            // Declare an object variable of the type to be deserialized.
            OrderedItem i;
    
            using (Stream reader = new FileStream(filename, FileMode.Open))
            {
                // Call the Deserialize method to restore the object's state.
                i = (OrderedItem)serializer.Deserialize(reader);          
            }
    
            // Write out the properties of the object.
            Console.Write(
            i.ItemName + "\t" +
            i.Description + "\t" +
            i.UnitPrice + "\t" +
            i.Quantity + "\t" +
            i.LineTotal);
        }
    }
    

    xml

    <?xml version="1.0"?>
     <OrderedItem xmlns:inventory="http://www.cpandl.com" xmlns:money="http://www.cohowinery.com">
       <inventory:ItemName>Widget</inventory:ItemName>
       <inventory:Description>Regular Widget</inventory:Description>
       <money:UnitPrice>2.3</money:UnitPrice>
       <inventory:Quantity>10</inventory:Quantity>
       <money:LineTotal>23</money:LineTotal>
     </OrderedItem>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-09-08
      • 2011-01-02
      • 2017-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-15
      • 1970-01-01
      相关资源
      最近更新 更多