Jesper Evertsson
Jesper Evertsson

Reputation: 613

Parsing XML file with LINQ getting wrong information

Im trying to parse an XML file from my program and I'm basing my code off this answer.

However the XML I'm using now is a bit more complex where I need to fill several nested lists with classes. Here are my two classes

public class Picture
{
    private int mPicNumber;
    private int mPicDuration;
    private List<string> mToSay = new List<string>();

    public Picture(int picNumber, int picDuration, List<string> toSay){...}

}


public class Sequence
{
    string mName;
    int mNumber;
    List<Picture> mPictures = new List<Picture>();

    public Sequence(string name, int number, List<Picture> pictures){...}
}

The XML looks like this

<sequences>
<sequence>
    <name>Seq 2</name>
    <number>1</number>
        <picture>
            <number>1</number>
            <duration>5</duration>
            <rows>
                <text>text1</text>
                <text>text2</text>
                <text>text3</text>
            </rows>
        </picture>  
        <picture>
            <number>2</number>
            <duration>5</duration>
            <rows>
                <text>text1</text>
                <text>text2</text>
                <text>text3</text>
            </rows>
        </picture>
        <picture>
            <number>3</number>
            <duration>5</duration>
            <rows>
                <text>text1</text>
                <text>text2</text>
                <text>text3</text>
            </rows>
        </picture>
</sequence>
<sequence>
    <name>Seq 2</name>
    <number>1</number>
        <picture>
            <number>1</number>
            <duration>5</duration>
            <rows>
                <text>text1</text>
                <text>text2</text>
                <text>text3</text>
            </rows>
        </picture>  
        <picture>
            <number>2</number>
            <duration>5</duration>
            <rows>
                <text>text1</text>
                <text>text2</text>
                <text>text3</text>
            </rows>
        </picture>
        <picture>
            <number>3</number>
            <duration>5</duration>
            <rows>
                <text>text1</text>
                <text>text2</text>
                <text>text3</text>
            </rows>
        </picture>
</sequence>
</sequences>

Here is the code for parsing the XML

XDocument xmlDoc = XDocument.Load("Sequences.xml");
List<Picture> pictures;
List<string> toSay;

mSequences = xmlDoc.Descendants("sequence").
  Select(be => new Sequence(
    (string)be.Element("name"),
    (int)be.Element("number"),
    pictures = xmlDoc.Descendants("picture").
      Select(bf => new Picture(
        (int)bf.Element("number"),
        (int)bf.Element("duration"),
        toSay = xmlDoc.Descendants("rows").
          Select(bg =>
            (String)bg.Element("text")).ToList())).ToList())).ToList();

After I run this I get a list with 2 Sequences (which is correct) and the name and number is correct. However Each sequence contain all 6 pictures from the XML file and those pictures doesn't contain anything from within the rows tag. I tried changing Descendants to Elements on the two inner lists but then I got 0 pictures in all sequences instead. I will admit I'm not very good at LINQ and this is very confusing to me.

Upvotes: 0

Views: 53

Answers (2)

Rahul Singh
Rahul Singh

Reputation: 21825

The problem with your code is here pictures = xmlDoc.Descendants("picture"). & toSay = xmlDoc.Descendants("rows").. You are again querying the XML from the top rather you should be querying the already filtered data. You should use the instance variable be & bf respectively.

This will give you the expected output:-

var res = xdoc.Root.Elements("sequence")
              .Select(be => new Sequence(
                        (string)be.Element("name"),
                        (int)be.Element("number"),
               pictures = be.Elements("picture")
                            .Select(bf => new Picture(
                           (int)bf.Element("number"),
                           (int)bf.Element("duration"),
                            toSay = bf.Element("rows").Elements("text")
                               Select(bg =>
                                       (String)bg).ToList()))
                                   .ToList()))
                             .ToList();

Also, note how I have replaced Descendants with Elements. If you XML contains some inner node with same tag then you will get unexpected output.

Upvotes: 1

Robi_h
Robi_h

Reputation: 53

pictures = xmlDoc.Descendants("picture")

It looks like you get the Pics from the whole document xmlDoc.Decendants, but instead you need to get it for each be object I think. I can`t check it right now but i guess be.Decentans should be okay?

Upvotes: 1

Related Questions