Search code examples
c#choetl

How do I map CSV header to propertyname at runtime with ChoETL


Using choETL I found that I can map csv position to property name like this

        public class Emp
        {
            public string Name { get; set; }
            public string Other{ get; set; }


            public string MyId { get; set; }
        }

        [Test]
        public void TestMapping()
        {
            ChoCSVRecordConfiguration config = new ChoCSVRecordConfiguration();
            config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("MyId", 1));
            config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("Name", 2));
            config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("Other", 3));
            config.WithFirstLineHeader(true);

            string csv = @"Id, Name, 
1, Tom, NY
2, Mark, NJ
3, Lou, FL
4, Smith, PA
5, Raj, DC
";

            using (var p = ChoCSVReader<Emp>.LoadText(csv, Encoding.ASCII,config)
//                .WithFirstLineHeader(true)
            )
            {
                Console.WriteLine(p.ToList().DumpAsJson());
            }

        }

However what I really want is to be able to map at runtime. Using the following pseudo code:

    config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("MyId", "Id"));
    config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("Name", "Name"));
    config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("Other", "City"));


    string csv1 = @"Id, Name, City
1, Tom, NY
2, Mark, NJ
3, Lou, FL
4, Smith, PA
5, Raj, DC
";

    string csv2 = @"Name, Id, City
Tom, 1, NY
Mark, 2, NJ
Lou, 3, FL
Smith, 4, PA
Raj, 5, DC
";

So I can use the same configuration for both csv file. They are almost identical except that the position has been swapped. Is this possible with choETL?


Solution

  • UPDATE: This is how you can setup the configuration to meet your requirement

    ChoCSVRecordConfiguration config = new ChoCSVRecordConfiguration();
    config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("MyId", 0) { FieldName = "Id" });
    config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("Name", 0) { FieldName = "Name" });
    config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("Other", 0) { FieldName = "City" });
    config.WithFirstLineHeader(false);
    

    Hope this helps.


    Yes, it is possible and you started your code correctly. After reviewing your sample code, noticed that you input CSV is missing 3rd field name City. This may be caused the parser to fail.

    Here is the working sample.

    public class Emp
    {
        public string Name { get; set; }
        public string Other { get; set; }
    
    
        public string MyId { get; set; }
    }
    
    public static void TestMapping()
    {
        ChoCSVRecordConfiguration config = new ChoCSVRecordConfiguration();
        config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("MyId", 1));
        config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("Name", 2));
        config.CSVRecordFieldConfigurations.Add(new ChoCSVRecordFieldConfiguration("Other", 3));
        config.WithFirstLineHeader(true);
    
        string csv = @"Id, Name, City
    1, Tom, NY
    2, Mark, NJ
    3, Lou, FL
    4, Smith, PA
    5, Raj, DC
    ";
    
        using (var p = ChoCSVReader<Emp>.LoadText(csv, Encoding.ASCII, config))
        {
            Console.WriteLine(p.ToList().Dump());
        }
    }
    

    Output:

    [Count: 5]
    -- CoinCount.Program+Emp State --
            Name: Tom
            Other: NY
            MyId: 1
    
    
    -- CoinCount.Program+Emp State --
            Name: Mark
            Other: NJ
            MyId: 2
    
    
    -- CoinCount.Program+Emp State --
            Name: Lou
            Other: FL
            MyId: 3
    
    
    -- CoinCount.Program+Emp State --
            Name: Smith
            Other: PA
            MyId: 4
    
    
    -- CoinCount.Program+Emp State --
            Name: Raj
            Other: DC
            MyId: 5
    

    Here is another way, to completely manage the CSV parsing with just with POCO class

    [ChoCSVFileHeader(IgnoreHeader = true)]
    public class Emp
    {
        [ChoCSVRecordField(2)]
        public string Name { get; set; }
        [ChoCSVRecordField(3)]
        public string Other { get; set; }
        [ChoCSVRecordField(1)]
        public string MyId { get; set; }
    }
    
    public static void TestMapping()
    {
        string csv = @"Id, Name, City
    1, Tom, NY
    2, Mark, NJ
    3, Lou, FL
    4, Smith, PA
    5, Raj, DC
    ";
    
        using (var p = ChoCSVReader<Emp>.LoadText(csv))
        {
            Console.WriteLine(p.ToList().Dump());
        }
    }