Kamil Zadora
Kamil Zadora

Reputation: 2397

Trying to parse XML tree with Linq to XML (C#)

I would like to reflect the XML tree in my object structure, but I am quite a beginner in LINQ to XML

I have an XML with following structure:

<questions>
<question id="q1">
  <number>1</number>
  <text>some text11</text>
  <answers>
     <answer>
      <v>some text11</v>
    </answer>
    <answer>
      <v>some text11</v>
    </answer>
  </answers>
</question>
<question id="q2">
  <number>2</number>
  <text>some text2</text>

<answers>
    <answer>
      <v>some text22</v>
    </answer>
    <answer>
      <v>some text22</v>
    </answer>
  </answers>
</question>
<question id="q3">
  <number>3</number>
  <text>some text3</text>
  <answers>
    <answer>
      <v>some text33</v>
    </answer>
    <answer>
      <v>some text33</v>
    </answer>
    <answer>
      <v>some text33</v>
      <addDescription>some text333</addDescription>
      <textBox/>
    </answer>
  </answers>
</question>
</questions>

...and I have following classes:

public class Question
{
    public string text { get; set; }
    public IList<Anwser> anwsers = new List<Anwser>();
}

public class Anwser
{
    public string content { get; set; }
}

... and I have build a following (wrong) Linq query:

        List<Question> questions = (from xml in xdoc.Element("survey").Elements("questions").Elements("question")
                                    select new Question()
                                               {
                                                   text = xml.Element("text").Value,
                                                   anwsers =
                                                       (from anwsers in
                                                            xdoc.Element("survey").Elements("questions").Elements("question").Elements(
                                                            "answers").Elements(
                                                            "answer")
                                                        select new Anwser()
                                                                   {
                                                                       content = anwsers.Element("v").Value
                                                                   }

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

Of course this way I get each time all anwsers from all questions added to each list. How to solve this? I can imagine that this is simple but I have no idea :)

Thank you in advance!

Upvotes: 6

Views: 8744

Answers (3)

Alexander Kahoun
Alexander Kahoun

Reputation: 2488

You were very close. In the select new parts you don't need () after the class names. Also you want to use .Descendents() instead of .Elements(). The only other part was the answers should be using the xml var not going back to the original document, this gives you the answers associated with the question.

List<Question> questions = (from xml in xdoc.Descendants("question")
                                    select new Question
                                    {
                                        text = xml.Element("text").Value,
                                        answers =
                                            (from anwsers in xml.Descendants("answer")
                                             select new Answer
                                             {
                                                 Content = anwsers.Element("v").Value
                                             }

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

Upvotes: 4

Duncan
Duncan

Reputation: 2503

The problem appears to be you are starting with xdoc in your inner select if you were to change it to:

from answer in xml.Elements("answers").Elements("answer")

You should be fine. This should work because xml contains the question element.

Upvotes: 1

Samuel
Samuel

Reputation: 38346

Your code isn't working because you are getting back all the answer elements because you didn't restrict them based on the question they came from. You could add this restriction or instead of a subquery based on the document, you can make the subquery based on the question element itself.

List<Question> questions = (from question in xdoc.Element("survey").Element("questions").Elements("question")
         select new Question
         {
           text = question.Element("text").Value,
           anwsers = (from answer in question.Element("answers").Elements("answer")
                select new Anwser
                {
                  content = answer.Element("v").Value
                }).ToList()
         }).ToList();

Upvotes: 7

Related Questions