0

I am trying to read the nested elements in the xml below. So far I have been able to read data in chantier/data element, but now the problem lies in how can I read the data inside <questions><sitePreparation> and <ctm>? Xml file and code have been shorted a bit because they are too long. Any help is much appreciated.

<?xml version="1.0" encoding="UTF-8"?>
<Audit>
    <controls>
        <guid>
           0001
        </guid>
        <templateVersion>
                    1.0
        </templateVersion>
    </controls>
    <chantier>
        <data>
            <V2>V2</V2>
            <V3>V3</V3>
            <V3_1>V3_1</V3_1>
            <V4>V4</V4>
            <oresTiersPanel>
                <S1_2>S1_2</S1_2>
            </oresTiersPanel>
            <agentsTiersPanel>
                <S1_2_2>S1_2_2</S1_2_2>
            </agentsTiersPanel>
        </data>
        <questions>
            <sitePreparation>
                <P1_Question>P1_Q</P1_Question>
                <P6_Question>P6_Q</P6_Question>
            </sitePreparation>
            <ctm>
                <C1_Question>C1_Q</C1_Question>
                <C2_Question>C2_Q</C2_Question>
                <C2_1>C2_1</C2_1>
            </ctm>
        </questions>
    </chantier>
</Audit>

private static void ReadXml()
{
    XDocument xdoc = XDocument.Load("sipp.xml");

    if (xdoc.Root != null)
    {
        var chantier = from ch in xdoc.Root.Elements("chantier").Elements("data")
                       let agentsTiersPanel = ch.Element("agentsTiersPanel")
                       where agentsTiersPanel != null
                       select new
            {
                v2 = (string)ch.Element("V2"),
                v3 = (string)ch.Element("V3"),
                v3_1 = (string)ch.Element("V3_1"),
                v4 = (string)ch.Element("V4"),
                S1_2_2 = (string)agentsTiersPanel.Element("S1_2_2"),
                S1_2_2_1 = (string)agentsTiersPanel.Element("S1_2_2_1"),
                S1_2_3 = (string)agentsTiersPanel.Element("S1_2_3"),
                S3 = (string)ch.Element("S3"),
               S3_1 = (string)ch.Element("S3_1"),
                P1_Question = (string)ch.Element("P1_Question")
            };

        foreach (var item in chantier)
        {
            Console.WriteLine(item.v2 + " " + item.v3);
        }
    }
}
Imir Hoxha
  • 1,674
  • 6
  • 31
  • 56

2 Answers2

0

Sample of reading questions elements:

var questions = xdoc.Root.Elements("chantier")
                    .Elements("questions").FirstOrDefault();

if (questions != null)
{
    var sitePreparation = questions.Element("sitePreparation");
    if (sitePreparation != null)
    {
        Console.WriteLine((string)sitePreparation.Element("P1_Question"));
        Console.WriteLine((string)sitePreparation.Element("P6_Question"));
    }
}

If you want return P1 and P6 questions as part of your anonymous object, then keep in mind, that ch is a data element of chantier, not chantier element itself. That's why ch.Element("P1_Question") returns null. With skipping null elements query should look like:

var chantiers = 
   from chantier in xdoc.Root.Elements("chantier")
   let data = chantier.Element("data")
   let questions = chantier.Element("questions")
   where data != null && questions != null
   select new {
      V2 = (string)data.Element("V2"),
      V3 = (string)data.Element("V3"),
      V3_1 = (string)data.Element("V3_1"),
      V4 = (string)data.Element("V4"),
      S1_2_2 = (string)data.Element("agentsTiersPanel").Element("S1_2_2"),
      P1_Question = (string)questions.Element("sitePreparation")
                                     .Element("P1_Question")
   };

Output:

[
  {
     V2: "V2",
     V3: "V3",
     V3_1: "V3_1",
     V4: "V4",
     S1_2_2: "S1_2_2",
     P1_Question: "P1_Q"
  }
]
Sergey Berezovskiy
  • 232,247
  • 41
  • 429
  • 459
  • is it possible to read the elements in the first loop without creating a second one? I would like to know if it is possible to navigate up the elements and then navigate down to the right element? – Imir Hoxha Jun 06 '14 at 08:20
  • 1
    Thanks Sergey, your example helped me understand how Linq reads the xml. – Imir Hoxha Jun 06 '14 at 08:42
0

It might be easier to deserialize it into an object. You can use the Paste special feature within VS to get a class representation of your XML structure. From there, it is pretty straightforward as far as deserialization goes:

private Audit GetAuditNodes()
{
    Audit audit = null;
    XmlSerializer serializer = new XmlSerializer(typeof(Audit));
    string uri = "data.xml";

    try
    {
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.CheckCharacters = false;
        settings.CloseInput = true;
        settings.DtdProcessing = DtdProcessing.Ignore;
        settings.IgnoreComments = true;
        settings.IgnoreWhitespace = true;

        using (XmlReader reader = XmlReader.Create(uri, settings))
        {
            audit = (Audit)serializer.Deserialize(reader);
        }
    }
    catch (Exception exc)
    {
         //log an error or something
    }

    return audit;
}

You have much cleaner code and can also work with a strongly typed object

DGibbs
  • 14,316
  • 7
  • 44
  • 83