Использовать только части xml -файла - PullRequest
3 голосов
/ 14 января 2020

Я относительно новичок в Unity и C#. На самом деле, я в основном смотрю на код приложения и стараюсь немного научиться. И это забавно.

Теперь я наткнулся на проблему.

Я пытаюсь прочитать файл XML и продолжить использовать данные из него. Это даже работает. Но теперь я не хочу использовать все записи файла XML, а только те, которые имеют определенный идентификатор.

В настоящее время я делаю это так:

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;
        }
    }
}

This вызывает, я думаю, что все данные хранятся в соответствующей переменной (data). Но теперь я хочу, чтобы передавались только те наборы данных, которые имеют идентификатор 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>

Спасибо - надеюсь, мой вопрос значим и не слишком неясен. Прости мой неверный англи sh.

Ответы [ 2 ]

2 голосов
/ 14 января 2020

Можно, но я бы не советовал постоянно читать только частичные файлы, потому что это постоянный удар ввода-вывода. Каждый раз, когда вам нужно будет получить новый вопрос, вы получаете еще один прочитанный ввод-вывод на диске. Если ваш набор вопросов не слишком велик (например, несколько сотен МБ), вы можете прочитать все данные в вашем 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);
    }
}

Тогда в вашей игровой логи c вы можете просто позвонить:

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

Теоретически вы также можете используйте XPath, чтобы просто выбрать необходимые XML узлы, но чтобы это работало, вам все равно потребуется загрузить весь документ XML в память, чтобы запустить ваш XPath поверх него (я не знаю о какой-либо реализации XPath для . net это будет работать на потоках). Так что вы также можете просто использовать свою собственную структуру данных, как я изложил.

Если вам действительно нужен огромный набор данных и вы не можете загрузить все в память, вам, возможно, стоит взглянуть на какое-то решение для базы данных, например SQLite для хранить ваши данные. Это позволит вам выполнять SQL запросов к БД и не потребует загрузки всех данных в память.

0 голосов
/ 14 января 2020

Я согласен с Яном Тома. То, что вы делаете, называется десериализацией (когда вы создаете xml или json из объекта, вы делаете сериализацию). Таким образом, вы просто создаете объект из файла xml (конечно, технически вам нужно прочитать файл, чтобы десериализовать его, но, конечно, вы используете библиотеку для его обработки). Получив данные, вы сможете изменить свой объект или создать измененную копию с правильными данными.

Обычно я предпочитаю json, поэтому я не уверен, как это сделать с библиотекой XmlSerializer (ссылка с примером в части редактирования), но вы должны создать объект bean, представляющий ваш файл xml (пример antwort - один из объектов basi c, и он должен иметь переменную int info и логическую переменную korrekt , в то время как antworten - это объект, который содержит только список antwort и т. д., пока вы не достигнете своего основного объекта fragen, который содержит все ваши базовые представления вашего компонента xml для десериализации (для создания компонента просто объявите свои переменные и Getter / Setters для этих переменных))

После этого вы просто десериализуете ваш xml как Fragen, а не как тип данных, и вы можете легко изменить свой объект.

EDIT , Чтобы понять это лучше, просто посмотрите пример здесь: https://docs.microsoft.com/it-it/dotnet/api/system.xml.serialization.xmlserializer.deserialize?view=netframework-4.8

вы получили xml и класс, который представляет объект OrderedItem (примечание: пространство имен должно быть необязательным, но вам нужно чтобы вызвать переменную с тем же именем переменной в вашем xml, и вам понадобятся getter и setter в классе OrderedItem). После того, как вы получили элемент 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...