Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrieving Data From XML File

Tags:

c#

.net

xml

I seem to be having a problem with retrieving XML values with C#, which I know it is due to my very limited knowledge of C# and .XML.

I was given the following XML file

<PowerBuilderRunTimes>
    <PowerBuilderRunTime>
        <Version>12</Version>
        <Files>
            <File>EasySoap110.dll</File>
            <File>exPat110.dll</File>
            <File>pbacc110.dll</File>
        </File>
     </PowerBuilderRunTime>
</PowerBuilderRunTimes>

I am to process the XML file and make sure that each of the files in the exist in the folder (that's the easy part). It's the processing of the XML file that I have having a hard time with. Here is what I have done thus far:

var runtimeXml = File.ReadAllText(string.Format("{0}\\{1}", configPath, Resource.PBRuntimes));

var doc = XDocument.Parse(runtimeXml);
var topElement = doc.Element("PowerBuilderRunTimes");
var elements = topElement.Elements("PowerBuilderRunTime");

foreach (XElement section in elements)
{
    //pbVersion is grabbed earlier. It is the version of PowerBuilder
    if( section.Element("Version").Value.Equals(string.Format("{0}", pbVersion ) ) )
    {
        var files = section.Elements("Files");

        var fileList = new List<string>();

        foreach (XElement area in files)
        {
            fileList.Add(area.Element("File").Value);
        }
    }
}

My issue is that the String List is only ever populated with one value, "EasySoap110.dll", and everything else is ignored. Can someone please help me, as I am at a loss.

like image 443
Christopher MacKinnon Avatar asked Jun 21 '11 19:06

Christopher MacKinnon


2 Answers

Look at this bit:

var files = section.Elements("Files");

var fileList = new List<string>();

foreach (XElement area in files)
{
    fileList.Add(area.Element("File").Value);
}

You're iterating over each Files element, and then finding the first File element within it. There's only one Files element - you need to be iterating over the File elements within that.

However, there are definitely better ways of doing this. For example:

var doc = XDocument.Load(Path.Combine(configPath, Resource.PBRuntimes));
var fileList = (from runtime in doc.Root.Elements("PowerBuilderRunTime")
                where (int) runtime.Element("Version") == pbVersion
                from file in runtime.Element("Files").Elements("File")
                select file.Value)
               .ToList();

Note that if there are multiple matching PowerBuilderRunTime elements, that will create a list with all the files of all those elements. That may not be what you want. For example, you might want:

var doc = XDocument.Load(Path.Combine(configPath, Resource.PBRuntimes));
var runtime = doc.Root
                 .Elements("PowerBuilderRunTime")
                 .Where(r => (int) r.Element("Version") == pbVersion)
                 .Single();

var fileList = runtime.Element("Files")
                      .Elements("File")
                      .Select(x => x.Value)
                      .ToList();

That will validate that there's exactly one matching runtime.

like image 104
Jon Skeet Avatar answered Oct 01 '22 14:10

Jon Skeet


The problem is, there's only one element in your XML, with multiple children. You foreach loop only executes once, for the single element, not for its children.

Do something like this:

var fileSet = files.Elements("File");
foreach (var file in fileSet) {
    fileList.Add(file.Value);
}

which loops over all children elements.

like image 34
retrodrone Avatar answered Oct 01 '22 16:10

retrodrone