0

I'm having a difficult time looping through nodes of an XML document. I have a document that has the following hierarchy:

<?xml version="1.0" encoding="UTF-8"?>
<TEMPONDERZOEK xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

<TRIES>3</TRIES>
<RESULTATEN>
   <INSTRUMENT>
      <INSTRUMENT_CODE>SPOTCHEM EZ</INSTRUMENT_CODE>
      <TEST_CODE>0</TEST_CODE>
      <VLAG>1</VLAG>
      <ANALYSES>
         <ANALYSE>
            <AFKORTING>BUN</AFKORTING>
            <WAARDE>23.7</WAARDE>
            <EENHEID>MMOL/L</EENHEID>
         </ANALYSE>
         <ANALYSE>
            <AFKORTING>GLU</AFKORTING>
            <WAARDE>15.0</WAARDE>
            <EENHEID>MMOL/L</EENHEID>
         </ANALYSE>
      </ANALYSES>
   </INSTRUMENT>
   <INSTRUMENT>
      <INSTRUMENT_CODE>SPOTCHEM EL</INSTRUMENT_CODE>
      <TEST_CODE>1</TEST_CODE>
      <VLAG>1</VLAG>
      <ANALYSES>
         <ANALYSE>
            <AFKORTING>Na</AFKORTING>
            <WAARDE> 152</WAARDE>
            <EENHEID>mmol/L</EENHEID>
         </ANALYSE>
         <ANALYSE>
            <AFKORTING>K</AFKORTING>
            <WAARDE> 4.4</WAARDE>
            <EENHEID>mmol/L</EENHEID>
         </ANALYSE>
      </ANALYSES>
   </INSTRUMENT>
</RESULTATEN>
</TEMPONDERZOEK>

I have written the following C# code to iterate through the document:

 // Get all fraudulent XML files
        string[] fraudulentsArray = Directory.GetFiles(@"tempXML\fraudulent", "temp_*.xml");

        // Iterate through every XML file that has been collected
        foreach (var x in fraudulentsArray)
        {
            XmlDocument xml = new XmlDocument();
            xml.Load(x);

            // Get the first parent node
            XmlNode resultaten = xml.SelectSingleNode("//RESULTATEN");

            // Get all the INSTRUMENT nodes in RESULTATEN
            var instrumentNodes = resultaten.SelectNodes("//INSTRUMENT");

            // Loop through the instrument nodes
            for (int i = 0; i < instrumentNodes.Count; i++)
            {
                // Get the values from nodes inside parent node INSTRUMENT and store them
                xmlanalyse.INSTRUMENT_CODE = instrumentNodes[i].ChildNodes[0].InnerText;
                xmlanalyse.TEST_CODE = instrumentNodes[i].ChildNodes[1].InnerText.ToInt();
                xmlanalyse.VLAG = instrumentNodes[i].ChildNodes[2].InnerText.ToInt();

                // Get the ANALYSES parent node
                XmlNode analyses = instrumentNodes[i].SelectSingleNode("//ANALYSES");

                // Get all the ANALYSE nodes in parent node ANALYSES
                var analysesNodes = analyses.SelectNodes("//ANALYSE");

                // Loop through the ANALYSE nodes
                for (int j = 0; j < analysesNodes.Count; j++)
                {
                    // Store them..
                    ANALYSE tempresultaat = new ANALYSE();

                    tempresultaat.AFKORTING = analysesNodes[j].ChildNodes[0].InnerText;
                    tempresultaat.WAARDE = analysesNodes[j].ChildNodes[1].InnerText;
                    tempresultaat.EENHEID = analysesNodes[j].ChildNodes[2].InnerText;

                    xmlanalyse.ANALYSES.Add(tempresultaat);
                }

                onderzoek.RESULTATEN.Add(xmlanalyse);
            }
        }

The problem I have with this loop is that it does not make the distinction between the INSTRUMENT nodes. The result of this is that in the first loop I get all the values from ANALYSE from the first INSTRUMENT node but I also get the values from ANALYSE from the second INSTRUMENT node. This also happens in the second loop.

Cœur
  • 37,241
  • 25
  • 195
  • 267
IDJosh
  • 89
  • 9

1 Answers1

1

You'll need to indicate the current context (just a .) on your XPATHs expressions:

var instrumentNodes = resultaten.SelectNodes(".//INSTRUMENT");
var analyses = instrumentNodes[i].SelectSingleNode(".//ANALYSES");
var analysesNodes = analyses.SelectNodes(".//ANALYSE");

Ideally, you could get rid of all those // and use the default current context:

foreach (XmlElement instrument in xml.SelectNodes("//INSTRUMENT"))
{
    Console.WriteLine(instrument.SelectSingleNode("INSTRUMENT_CODE").InnerText);

    foreach (XmlElement analyse in instrument.SelectNodes("ANALYSES/ANALYSE"))
    {
        Console.WriteLine(analyse.SelectSingleNode("AFKORTING").InnerText);
    }
}

Another suggestion is to avoid the ChildNodes[n] syntax, as your code will break if the XML file changes. Consider the "AFKORTING" example above.

Are you trying to transform the XML file into business objects? Did you tried deserialize it?

Community
  • 1
  • 1
Rubens Farias
  • 57,174
  • 8
  • 131
  • 162