简体   繁体   English

C#将XML元素读取到2个单独的列表中

[英]C# Reading XML elements into 2 separate lists

I am creating a quiz in C# as console app. 我正在使用C#作为控制台应用程序创建测验。

I have a single XML file that contains a) questions b) answers and c) incorrect answers. 我有一个XML文件,其中包含a)问题b)答案和c)错误的答案。

I can read questions from my XML File. 我可以从XML文件中读取问题。

However I cannot work out the logic I need to associate the incorrect and correct answers for each randomly generated read question. 但是,我无法弄清楚我需要为每个随机生成的阅读问题关联错误和正确答案的逻辑。

Here is a copy of my XML file. 这是我的XML文件的副本。

<?xml version="1.0" encoding="utf-8"?>
<Question xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <theQuestion>How many players in a football team?</theQuestion>
  <answerA>12</answerA>
  <answerB>10</answerB>
  <answerC>20</answerC>
  <answerD>11</answerD>
  <correctAnswer>11</correctAnswer>
  <theQuestion>How many minutes in a football game?</theQuestion>
  <answerA>90</answerA>
  <answerB>45</answerB>
  <answerC>60</answerC>
  <answerD>77</answerD>
  <correctAnswer>90</correctAnswer> 
</Question>

Here is part of my code: 这是我的代码的一部分:

  ProcessData data = new ProcessData();

  //load questions from XML file and store in list
  var questions =  data.LoadQuizQuestions();

  //create a question object
  Question q = new Question();

  //get a question randomly generated from questions list 
  int index = new Random().Next(questions.Count);

  //display the randomly generated question
  Console.WriteLine(questions[index]);

  Console.ReadLine();

Here is my LoadQuizQuestions() 这是我的LoadQuizQuestions()

    public List<string> LoadQuizQuestions()
    {
      //create empty list to store quiz questions read in from file
      List<string> questions = new List<string>();

      //load questions from file into list
      questions =
        XDocument.Load(@"C:\Development\Learning\Files\qsFile.xml").Descendants("theQuestion").Select(o => o.Value).ToList();

      //return list of questions
      return questions;
   }

I would like that when each random question is displayed the associated answers to that question are also displayed and the "correct answer" read into a variable that I can check the user input against. 我希望在显示每个随机问题时,也显示该问题的相关答案,并将“正确答案”读入一个变量,我可以根据该变量检查用户输入。

Please help me understand I know I am close to nailing this :-) 请帮助我了解我知道我将要钉牢这个:-)

Thank you 谢谢

  1. Read the xml into a List<Question> collection 将xml读入List<Question>集合
  2. Pick a random item 选择一个随机物品
    1. Show the question and the options 显示问题和选项
    2. Ask for the user input 要求用户输入
    3. Compare the user input with the correct answer 比较用户输入和正确答案
  3. Profit 利润

EDIT : Your XML input treats your data as sequential , not hierarchical; 编辑 :您的XML输入将您的数据视为顺序的 ,而不是分层的; this will lead to potential problems when you tried to read the questions. 当您尝试阅读问题时,这将导致潜在的问题。

You should consider a structure like this: 您应该考虑这样的结构:

<Questions>
    <Question>
        <Title>How many players in a football team?</Title>
        <Options>
            <Option>12</Option>
            <Option>10</Option>
            <Option>20</Option>
            <Option IsCorrect='true'>11</Option>
        </Options>
    </Question>
    <Question>
        <Title>How many minutes in a football game?</Title>
        <Options>
            <Option IsCorrect='true'>90</Option>
            <Option>45</Option>
            <Option>60</Option>
            <Option>77</Option>
        </Options>
    </Question>
</Questions>

This will make easier to read the XML manually, or deserialising it directly into a List<Question> collection. 这将使手动读取XML或将其直接反序列化为List<Question>集合变得更加容易。

I made the decision to keep in the option if it's a correct answer, as this can be flexible enough to multiple right answers. 我做保留的选项,如果这是一个正确的答案,因为这可能是足够的灵活性,多个正确答案的决定。

class Question
{
    public string Title         { get; private set; }
    public List<Option> Options { get; private set; }

    public Question()
    {
    }

    public Question(XmlElement question) : this()
    {
        this.Title   = question["Title"].InnerText;
        this.Options = question.SelectNodes("Options/Option")
            .OfType<XmlElement>()
            .Select(option => new Option(option))
            .ToList();
    }
}

Not a big deal here: we just read an XmlElement and delegates to the Option class the item deserialization. 在这里没什么大不了的:我们只读取一个XmlElement并将项目反序列化委托给Option类。

class Option
{
    public string Title         { get; private set; }
    public bool   IsCorrect     { get; private set; }

    public Option()
    {
    }

    public Option(XmlElement option) : this()
    {
        this.Title = option.InnerText;
        this.IsCorrect = option.GetAttribute("IsCorrect") == "true";
    }
}

Same deal. 同样的交易。

With this structure, you can do something like this: 通过这种结构,您可以执行以下操作:

var xml = new XmlDocument();
    xml.LoadXml(@"...");

var random = new Random();
var questions = xml.SelectNodes("//Question")
    .OfType<XmlElement>()
    .Select (question => new Question(question))
    .OrderBy(question => random.Next())
    .ToList();

foreach (var question in questions)
{
    Console.ForegroundColor = ConsoleColor.White;
    Console.WriteLine(question.Title);
    foreach (var option in question.Options)
    {
        Console.ForegroundColor = ConsoleColor.Gray;
        Console.WriteLine("\t{0}", option.Title);
    }
    Console.Write("Choose the right option: ");
    var answer = Console.ReadLine();

    if (question.Options.Any(option =>
        option.IsCorrect && answer.Equals(option.Title, 
            StringComparison.InvariantCultureIgnoreCase)))
    {
        Console.ForegroundColor = ConsoleColor.Green;
        Console.WriteLine("YOU HAVE CHOSEN... WISELY.");
    }
    else
    {
        Console.ForegroundColor = ConsoleColor.Red;
        Console.WriteLine("You have chosen poorly!");
    }
}

If you use a question object that contains a list of answers, like this: 如果您使用包含答案列表的问题对象,如下所示:

public class Question
{
    public int ID { get; set; }
    public string QuestionText { get; set; }

    public List<Answer> Answers { get; set; } 

    public string AnswerText { get; set; }
}

public class Answer
{
    public string ID { get; set; }
    public string AnswerText { get; set; }
}

Then you can read the questions and answers into discrete objects, something like the code below (disclaimer: did not test this so it may need to be tweaked to work) 然后,您可以将问题和答案读入离散的对象中,例如下面的代码(免责声明:未对此进行测试,因此可能需要对其进行调整才能起作用)

   public List<Question> GetQuestions(string xmlFile)
    {
        var questions = new List<Question>();

        var xDoc = XDocument.Load(xmlFile);

        var questionNodes = xDoc.Descendants("theQuestion");

        foreach (var questionNode in questionNodes)
        {

            var question = new Question();
            question.QuestionText = questionNode.Value;

            // do something like this for all the answers
            var answer = new Answer();
            answer.ID = "A";
            var answerA = questionNode.Descendants("answerA").FirstOrDefault();
            if (answerA != null)
                answer.AnswerText = answerA.Value;

            question.Answers = new List<Answer>();
            question.Answers.Add(answer);

            question.AnswerText =
                questionNode.Descendants("correctAnswer").FirstOrDefault().Value;
        }

        return questions;
    } 
}

Now that you have the questions and answers in a single object you can display the question, the answers, and then based on user input do a string comparison to check the user's answer. 现在,您已经在单个对象中包含了问题和答案,可以显示问题,答案,然后根据用户输入进行字符串比较以检查用户的答案。

You can check my logic to get value form XMLNode as you want. 您可以检查我的逻辑以根据需要从XMLNode获取值。

How to get node values in XML file using c# 如何使用C#获取XML文件中的节点值

If you can change your xml structure I'd do this: 如果您可以更改xml结构,请执行以下操作:

<?xml version="1.0" encoding="utf-8"?>
<Questions>
  <Question text="How many players in a football team?">
    <answerA>12</answerA>
    <answerB>10</answerB>
    <answerC>20</answerC>
    <answerD>11</answerD>
    <correctAnswer>11</correctAnswer>
  </Question>
  <Question text="How many minutes in a football game?">
    <answerA>90</answerA>
    <answerB>45</answerB>
    <answerC>60</answerC>
    <answerD>77</answerD>
    <correctAnswer>90</correctAnswer>
  </Question>
</Questions>

Then deserialize using these classes: 然后使用以下类反序列化:

public class Questions
{
    [XmlElement("Question")]
    public List<Question> QuestionList { get; set; } = new List<Question>();
}

public class Question
{
    [XmlAttribute("text")]
    public string Text { get; set; }

    public string answerA { get; set; }
    public string answerB { get; set; }
    public string answerC { get; set; }
    public string answerD { get; set; }
    public string correctAnswer { get; set; }
}

And this code: 这段代码:

string path = "yourxmlfile.xml";

XmlSerializer serializer = new XmlSerializer(typeof(Questions));

StreamReader reader = new StreamReader(path);
var qs = (Questions)serializer.Deserialize(reader);
reader.Close();

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

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