0
<?xml version="1.0" encoding="utf-8" ?>
<root>
  <fileUploadSpecification>
    <DirectoryPath>C:\watchFolder</DirectoryPath>
    <Region>us-west-2</Region>
    <UploadBucket>configurationtestbucket</UploadBucket>
    <FileType>
      <type>*.txt</type>
      <type>*.OpticomCfg</type>
    </FileType>
  </fileUploadSpecification>
  <fileUploadSpecification>
    <DirectoryPath>C:\watchFolder</DirectoryPath>
    <Region>us-west-2</Region>
    <UploadBucket>loguploadbucket</UploadBucket>
    <FileType>
      <type>*.Xml</type>
      <type>*.Json</type>
    </FileType>
  </fileUploadSpecification>
</root>

This is the XML file I need to parse, I want to get each instance of fileUploadSpecification so that I can put each set of details into a list, I think some type of for loop would be appropriate, where I loop through and add the first set of upload details and then loop through and add the second. This is what I currently have, but it never gets to the second fileUploadSpecification element, it just returns the same one again. The idea would be to create a new SettingsData for every set of fileUploadSpecification elements, whether it be two like shown above, or 10.

public interface ISettingsEngine
{

    IEnumerable<SettingsData> GetSettings();
}

public class SettingsEngine : ISettingsEngine
{

    public IEnumerable<SettingsData> GetSettings()
    {
        List<SettingsData> dataList = new List<SettingsData>();
        try
        {

            var xDoc = XDocument.Load("File1.xml");

            var instancesToParse = xDoc.Root.Elements().Count();

            var fileCount = xDoc.Root.Elements("FileType").Count();


            for (int x = 0; x < instancesToParse; x++)
            {
                var newSettingsData = new SettingsData();

                newSettingsData.UploadBucket = xDoc.Root.Element("fileUploadSpecification").Element("UploadBucket").Value;
                newSettingsData.Region = xDoc.Root.Element("fileUploadSpecification").Element("Region").Value;
                newSettingsData.DirectoryPath = xDoc.Root.Element("fileUploadSpecification").Element("DirectoryPath").Value;
                var query = xDoc.Root.Descendants("FileType").Elements("type");

                foreach (XElement e in query)
                {
                    newSettingsData.FileType.Add(e.Value);
                }
dataList.Add(newSettingsData);

            }

            return dataList;
        }
        catch(Exception)
        {
            return dataList;
        }
    }
}

public class SettingsData
{

    public List<string> FileType { get; set; }
    public string DirectoryPath { get; set; }
    public string Region { get; set; }
    public string UploadBucket { get; set; }

    public SettingsData()
    {
        FileType = new List<string>();
    }
}
John
  • 11
  • 5
  • What do you think `xDoc.Root.Element("fileUploadSpecification").Element("UploadBucket").Value` does? What did you find when you read the documentation? – 15ee8f99-57ff-4f92-890c-b56153 Jul 06 '17 at 18:36
  • It gets the literal value of whatever is assigned to that element right? I think i understand that, because it shows that the value is "configurationtestbucket" , which is what i would expect. What I dont understand then, is how to loop through a second time, to return the second value of the "UploadBucket" -> "loguploadbucket" – John Jul 06 '17 at 18:38
  • I *know* you don't understand what it does, and I hope you know too. I hope you know that if what a method returns is *totally at odds with what you expected*, then you almost certainly don't understand what the method does. You don't have to reassure me on that point. Please read the documentation. – 15ee8f99-57ff-4f92-890c-b56153 Jul 06 '17 at 18:38
  • Here, I'll help: It returns the *first* child by that name. You're counting with `x`. What do you do with `x`? Nothing. – 15ee8f99-57ff-4f92-890c-b56153 Jul 06 '17 at 18:42
  • Right, Im saying it is returning exactly what I want it to the first time, but what I dont understand, is how to loop through a second time, or a third time etc. to return the next set of elements under the "fileUploadSpecification" element – John Jul 06 '17 at 18:44
  • I see, so you are saying that since I am returning the first child by that name, I will always return the first child by that name? – John Jul 06 '17 at 18:44
  • You're calling the wrong method. Hang on while I throw together a quick example. – 15ee8f99-57ff-4f92-890c-b56153 Jul 06 '17 at 18:45

2 Answers2

1
var dataList = (from fus in xDoc.Root.Elements("fileUploadSpecification")
             select new SettingsData
             {
                 UploadBucket = fus.Element("UploadBucket").Value,
                 Region = fus.Element("Region").Value,
                 DirectoryPath = fus.Element("DirectoryPath").Value,
                 FileType = fus.Element("FileType")
                               .Elements("type").Select(f =>f.Value).ToList()
             }).ToList();
James Curran
  • 101,701
  • 37
  • 181
  • 258
0

Each time through the loop, you're looking up the first fileUploadSpecification element all over again. You used the Elements() method already, in a few places. That's the one you want. Always favor foreach over for in C#, when you're looping over a collection. It's quicker (to code, not at runtime) and less error prone.

foreach (var uploadSpec in xDoc.Root.Elements("fileUploadSpecification"))
{
    var newSettingsData = new SettingsData();

    newSettingsData.UploadBucket = uploadSpec.Element("UploadBucket").Value;
    newSettingsData.Region = uploadSpec.Element("Region").Value;
    newSettingsData.DirectoryPath = uploadSpec.Element("DirectoryPath").Value;

    var types = uploadSpec.Descendants("FileType").Elements("type").Select(e => e.Value);

    foreach (var type in types)
    {
        newSettingsData.FileType.Add(type);
    }

    //  Or if newSettingsData.FileType is List<String>...
    //newSettingsData.FileType.AddRange(types);

    dataList.Add(newSettingsData);
}

James Curran's answer is functionally the same, but it's better form.

  • Yes, FileType is a list that contains strings which are the types of files to be uploaded. Thank you, this was very helpful and informative. I am new to C# and to XML/XDocument, do you know of any good resources for me to use to help understand it better? – John Jul 06 '17 at 19:00
  • Here's one that doesn't look too bad: http://www.dotnetcurry.com/linq/564/linq-to-xml-tutorials-examples – 15ee8f99-57ff-4f92-890c-b56153 Jul 06 '17 at 19:04