Click here to Skip to main content
15,899,314 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Sorry about the weirdly phrased title, but it was hard to convey my issue in one short sentence.

I'm writing a feature to import CSV-like data into XML. And I'm using a bit more complex code than the MSDN example, but it's essentially the same idea.

Example from MSDN:
C#
string[] source = File.ReadAllLines("customers.csv");
XElement customers = new XElement("Root",
    from str in source
    let fields = str.Split(',')
    select new XElement("Customer",
        new XAttribute("CustomerID", fields[0]),
        new XElement("CompanyName", fields[1]),
        new XElement("ContactName", fields[2]),
        new XElement("ContactTitle", fields[3]),
        new XElement("Phone", fields[4])
    )
);
Console.WriteLine(customers);


The problem is that the files to import have variable number of columns, and have their column names in first row, (I have isolated the first row as a separate array of course), and I would like to "loop through" the array containing column names and add XElements for each of them. However I can't get any standard "looping" to give me the result I want.

I might be missing an obvious solution, but I am fresh out of ideas

Any help would be much appreciated
Posted

1 solution

Do you need to treat one of the columns specially to be the XAttribute instead of XElement? If not, this can be simplified...
C#
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;

namespace ConsoleApplication6
{
  class Program
  {
    public static Dictionary<TKey, TValue> ZipIntoDictionary<TKey, TValue>(Dictionary<TKey, TValue> dict, IEnumerable<TKey> keys, IEnumerable<TValue> values)
    {
      dict = dict ?? new Dictionary<TKey, TValue>();
      var enumKeys = keys.GetEnumerator();
      var enumValues = values.GetEnumerator();
      while (enumKeys.MoveNext() && enumValues.MoveNext())
      {
        dict.Add(enumKeys.Current, enumValues.Current);
      }
      return dict;
    }

    static void Main(string[] args)
    {
      string filePath = "customers.csv";
      List<string> headers = null;
      const string idKey = "CustomerID";
      Dictionary<string, string> columns = null;
      XElement customers = new XElement("Root");
      using (StreamReader sr = new StreamReader(filePath))
      {
        string line;
        // Read and process lines from the file until the end of the file is reached.
        while ((line = sr.ReadLine()) != null)
        {
          if (string.IsNullOrWhiteSpace(line))
            continue; // ignore blank lines (we've already dealt with null above)
          string[] rawColumns = line.Split(',');
          if (headers == null)
          {
            headers = rawColumns.ToList();  // capture the first non-blank line as headers
            if (!headers.Contains(idKey))   // remove the idKey if there and report if it isn't
            {
              Console.WriteLine("Missing Identifier Key: " + idKey);
              return;
            }
            continue;                       // no more processing of this line
          }

          columns = ZipIntoDictionary(columns, headers, rawColumns);
          XElement thisCustomer = new XElement("Customer", new XAttribute(idKey, columns[idKey]));
          foreach (var pair in columns)
          {
            if (pair.Key != idKey)
              thisCustomer.Add(new XElement(pair.Key, pair.Value));
          }
          customers.Add(thisCustomer);
        }
      }
      Console.WriteLine(customers);
    }
  }
  
}

Most/all of the hard-coded strings could/should be passed as arguments.

[Edit: MTH]
Here it is a bit simplified for no attribute...
C#
static void Main(string[] args)
{
  string filePath = "customers.csv";
  XElement customers = CsvToXml(filePath, "Root", "Customer");
  Console.WriteLine(customers);
}
static XElement CsvToXml(string filePath, string rootName, string elementName)
{
  string[] headers = null;
  XElement root = new XElement(rootName);
  using (StreamReader sr = new StreamReader(filePath))
  {
    string line;
    // Read and process lines from the file until the end of the file is reached.
    while ((line = sr.ReadLine()) != null)
    {
      if (string.IsNullOrWhiteSpace(line))
        continue;           // ignore blank lines (we've already dealt with null above)
      string[] columns = line.Split(',');
      if (headers == null)
      {
        headers = columns;  // capture the first non-blank line as headers
        continue;           // no more processing of this line
      }

      XElement thisElement = new XElement(elementName);
      for (int i = 0; i < headers.Length; i++)
      {
        string value = string.Empty;
        if (i < columns.Length)
          value = columns[i];
        thisElement.Add(new XElement(headers[i], value));
      }
      root.Add(thisElement);
    }
  }
  return root;
}
 
Share this answer
 
v2
Comments
Frank R. Haugen 14-Jul-15 9:50am    
The XAttribute is from the MSDN Example I used. I have no attributes in my actual code

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900