简体   繁体   中英

Read from XML to an object using LINQ

I am trying to read from an XML and enter into an object list. My XML is

<User>
    <Name>John</Name>
    <Role>Admin</Role>
    <QAList>
        <QA>
            <Question> Question 1 </Question>
            <Answers>
                <Answer> Answer 1 </Answer>
                <Answer> Answer 2 </Answer>
                <Answer> Answer 3 </Answer>
            </Answers>
        </QA>
    </QAList>
</User>

This is my object class:

public class ListQuestionAnswers: INotifyPropertyChanged
{
    private List<QuestionAnswer> _questionAnswer;
    public List<QuestionAnswer> QuestionAnswerList
    {
        get { return _questionAnswer; }
        set { _questionAnswer = value; }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    private string _role;
    public string Role
    {
        get { return _role; }
        set { _role = value; }
    }
}

public class QuestionAnswer
{
    public string _question;
    public List<AnswerList> _answers;

    public string Question
    {
        get { return _question; }
        set { _question = value; }
    }

    public List<AnswerList> Answers
    {
        get { return _answers; }
        set { _answers = value; }
    }
}

public class AnswerList
{
    private string _answer;

    public string Answer
    {
        get { return _answer; }
        set {_answer = value; }
    }
}

I am able to get Name and Role, but how can I get QA List? I tried writing a select within the query but that didnt seem to work.

XDocument xmlDoc = XDocument.Load(@"C:\Test\Sample.xml");
var files = (from x in xmlDoc.Elements("User")
             select new TestCasesViewModel
             {
                 Name = (string)x.Element("Name").Value ?? string.Empty,
                 Role = (string)x.Element("Role").Value ?? string.Empty
             }).ToList();

You can do the following:

var files = (from x in xmlDoc.Elements("User")
             select
             new TestCasesViewModel
                  {
                      Name = (string)x.Element("Name") ?? string.Empty,
                      Role = (string)x.Element("Role") ?? string.Empty,
                      QuestionAnswerList = 
                          x.Descendants("QA")
                          .Select(q => new QuestionAnswer
                          {
                              Question = (string)q.Element("Question"),
                              Answers = q.Descendants("Answer").Select(a => new AnswerList { Answer = (string)a}).ToList()

                          }).ToList()
                   }).ToList();

Note that you don't need to access Value property if you are using explicit cast, whole point of using explicit cast is to avoid possible exceptions, if you use the Value property then explicit cast become redundant because if the element wasn't found it will throw the exception anyway...

In situations like this, I find it to be extremely helpful to split-up a complex LINQ expression into multiple sub-expressions, if only to help with development and debugging.

Without knowing more about the structure of your real xml data, here are some ideas:

XDocument xmlDoc = XDocument.Load(@"C:\Test\Sample.xml");

var users = xmlDoc.Elements("User");

foreach(var user in users)
{
    var qaList = user.Element("QAList");

    foreach(var qa in qaList.Elements("QA"))
    {
        //at this point, you should have access the <Question> node e.g.
        string question = qa.Element("Question").Value;

        //and the list of answers would be similar to before
        var answers = qa.Element("Answers");

        foreach(var answer in answers.Elements("Answer"))
        {
            //now answer.Value should be the text of the answer
        } 
    }        
}

Again, this isn't the "cleanest" approach, and certainly there are more concise ways to express this in LINQ. The point is, you have quite a few more options for break-points/debugging, allowing you explore the objects you are working with.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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