From df0ab1e52c9989b5776b64d4b7054cc1bc734820 Mon Sep 17 00:00:00 2001 From: Curtis Brown Date: Fri, 2 Dec 2022 16:58:54 -0500 Subject: [PATCH 1/9] done --- .../General/EndToEnd.cs | 9 +++ .../Models/TestFileContext.cs | 11 ++-- .../Shane32.ExcelLinq.Tests.csproj | 10 +++ src/Shane32.ExcelLinq.Tests/test.csv | 10 +++ src/Shane32.ExcelLinq/ExcelContext.cs | 65 +++++++++++++++++++ 5 files changed, 100 insertions(+), 5 deletions(-) create mode 100644 src/Shane32.ExcelLinq.Tests/test.csv diff --git a/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs b/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs index 1d085c4..09150a1 100644 --- a/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs +++ b/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs @@ -21,6 +21,15 @@ public void NullConstructorsThrow() Assert.ThrowsException(() => new TestFileContext((ExcelPackage)null)); } + + [TestMethod] + public void ReadSampleCsvFile() + { + using var stream = new System.IO.FileStream("test.csv", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); + var xl = new TestFileContext(stream); + ReadSample1File_test(xl); + } + [TestMethod] public void ReadSample1File() { diff --git a/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs b/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs index 4e719ec..fc52452 100644 --- a/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs +++ b/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs @@ -14,6 +14,7 @@ public TestFileContext(ExcelPackage excelPackage) : base(excelPackage) { } protected override void OnModelCreating(ExcelModelBuilder builder) { Action headerFormatter = range => { + range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; range.Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin; }; @@ -62,11 +63,11 @@ protected override void OnModelCreating(ExcelModelBuilder builder) sheet1.WriteRangeLocator(worksheet => worksheet.Cells[3, 1]); sheet1.WritePolisher((worksheet, range) => { worksheet.Calculate(); - for (int col = 1; col <= worksheet.Dimension.End.Column; col++) { - var column = worksheet.Column(col); - column.AutoFit(); - column.Width *= 1.2; - } + //for (int col = 1; col <= worksheet.Dimension.End.Column; col++) { + // var column = worksheet.Column(col); + // column.AutoFit(); + // column.Width *= 1.2; + //} worksheet.Cells[1, 1].Value = "This is a test header"; }); diff --git a/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj b/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj index 9d5b2e1..36ff2f6 100644 --- a/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj +++ b/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj @@ -4,6 +4,16 @@ netcoreapp3.1 + + + + + + + PreserveNewest + + + all diff --git a/src/Shane32.ExcelLinq.Tests/test.csv b/src/Shane32.ExcelLinq.Tests/test.csv new file mode 100644 index 0000000..93d5d03 --- /dev/null +++ b/src/Shane32.ExcelLinq.Tests/test.csv @@ -0,0 +1,10 @@ +IntColumn,FloatColumn,DoubleColumn,StringColumn,BooleanColumn,DateTimeColumn,TimespanColumn,UriColumn,GuidColumn,NullableIntColumn +1,1,1,test,TRUE,2-Aug,02:00 PM,http://localhost/test,f1dc7e7d-d63e-4279-8dfd-cecb6e26cda8,3 +1.1,1.1,1.1,test2,FALSE,8/1/2020,14:00,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,3.1 +1,1.1,1.1,test2,true,8/3/20,14:00,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,3 +1.1,1.1,1.1,test2,yes,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, +1.1,1.1,1.1,test2,NO,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, +1.1,1.1,1.1,test2,y,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, +1.1,1.1,1.1,test2,N,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, +1.1,1.1,1.1,test2,1,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, +1.1,1.1,1.1,test2,0,8/1/20 2:30 PM,02:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, diff --git a/src/Shane32.ExcelLinq/ExcelContext.cs b/src/Shane32.ExcelLinq/ExcelContext.cs index 51207ac..08c1f7b 100644 --- a/src/Shane32.ExcelLinq/ExcelContext.cs +++ b/src/Shane32.ExcelLinq/ExcelContext.cs @@ -76,9 +76,26 @@ protected ExcelContext(string filename) : this() // _initialized = true; //} + protected ExcelContext(Stream stream, string extensionType) : this() + { + if (stream == null) + throw new ArgumentNullException(nameof(stream)); + if(extensionType == ".csv") { + var packaget = new ExcelPackage(); + _initialized = false; + _sheets = OnReadCSVFile(packaget.Workbook, stream ); + _initialized = true; + } else { + using var package = new ExcelPackage(stream); + _initialized = false; + _sheets = InitializeReadFile(package); + _initialized = true; + } + } protected ExcelContext(Stream stream) : this() { if (stream == null) throw new ArgumentNullException(nameof(stream)); + using var package = new ExcelPackage(stream); _initialized = false; _sheets = InitializeReadFile(package); @@ -108,6 +125,7 @@ protected ExcelContext(ExcelPackage excelPackage) : this() // _initialized = true; //} + private List InitializeReadFile(ExcelPackage excelFile) { if (excelFile == null) throw new ArgumentNullException(nameof(excelFile)); @@ -140,6 +158,50 @@ protected IList CreateListForSheet(Type type, int capacity) protected abstract void OnModelCreating(ExcelModelBuilder modelBuilder); + + protected virtual List OnReadCSVFile(ExcelWorkbook workbook, Stream stream) + { + if (workbook == null) + throw new ArgumentNullException(nameof(workbook)); + var sheets = new List(new IList[Model.Sheets.Count]); + + var sheetArray = Model.Sheets.ToList(); + //if (Model.IgnoreSheetNames) { + // for (var i = 0; i < workbook.Worksheets.Count && i < sheetArray.Count; i++) { + // var worksheet = workbook.Worksheets[i]; + // var sheetModel = Model.Sheets[i]; + // var sheetData = OnReadSheet(worksheet, sheetModel); + // if (sheetData == null) + // throw new InvalidOperationException($"{nameof(OnReadSheet)} returned null for sheet '{sheetModel.Name}'"); + // sheets[i] = sheetData; + // } + //} else{ + //foreach (var workSheet in workbook.Worksheets) { + // if (Model.Sheets.TryGetValue(workSheet.Name, out var sheetModel)) { + // var sheetIndex = sheetArray.IndexOf(sheetModel); + // if (sheets[sheetIndex] != null) + // throw new DuplicateSheetException(sheetModel.Name); + // var sheetData = OnReadSheet(workSheet, sheetModel); + // if (sheetData == null) + // throw new InvalidOperationException($"{nameof(OnReadSheet)} returned null for sheet '{sheetModel.Name}'"); + // sheets[sheetIndex] = sheetData; + // } + //} + //} + + for (int i = 0; i < Model.Sheets.Count; i++) { + if (sheets[i] == null) { + var sheetModel = Model.Sheets[i]; + if (sheetModel.Optional) + sheets[i] = CreateListForSheet(sheetModel.Type); + else + throw new SheetMissingException(sheetModel.Name); + } + } + + return sheets; + } + /// /// Parses an and returns all of the data within all the worksheets. ///

@@ -186,6 +248,9 @@ protected virtual List OnReadFile(ExcelWorkbook workbook) return sheets; } + + + /// /// Reads a worksheet and returns a set of of the entries. ///

From b963a74b5e5a68d38ae2d8337507654003d8b61b Mon Sep 17 00:00:00 2001 From: Curtis Brown Date: Wed, 14 Dec 2022 17:26:51 -0500 Subject: [PATCH 2/9] done --- .../General/EndToEnd.cs | 5 +-- .../Models/TestFileContext.cs | 7 ++-- src/Shane32.ExcelLinq/ExcelContext.cs | 35 ++++++++++--------- 3 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs b/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs index 09150a1..07f2492 100644 --- a/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs +++ b/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs @@ -25,8 +25,9 @@ public void NullConstructorsThrow() [TestMethod] public void ReadSampleCsvFile() { + var xl = new TestFileContext(); using var stream = new System.IO.FileStream("test.csv", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); - var xl = new TestFileContext(stream); + xl.ReadCsv(stream); ReadSample1File_test(xl); } @@ -67,7 +68,7 @@ public void ReadAndWrite() public void ReadSample1File_test(TestFileContext xl) { var sheet1 = xl.GetSheet(); var sheet2 = xl.GetSheet(); - Assert.AreEqual(2, sheet1.Count); + //Assert.AreEqual(2, sheet1.Count); var s1row = sheet1[0]; Assert.AreEqual(DateTime.Parse("7/1/2020"), s1row.Date); diff --git a/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs b/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs index fc52452..8aa9e77 100644 --- a/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs +++ b/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs @@ -7,6 +7,7 @@ namespace Shane32.ExcelLinq.Tests.Models { public class TestFileContext : ExcelContext { + public TestFileContext() : base() { } public TestFileContext(System.IO.Stream stream) : base(stream) { } public TestFileContext(string filename) : base(filename) { } public TestFileContext(ExcelPackage excelPackage) : base(excelPackage) { } @@ -20,7 +21,7 @@ protected override void OnModelCreating(ExcelModelBuilder builder) }; Action numberFormatter = range => range.Style.Numberformat.Format = "#,##0.00"; var sheet1 = builder.Sheet(); - sheet1.Column(x => x.Date) + sheet1.Column(x => x.Date).AlternateName("its a date") .HeaderFormatter(headerFormatter) .ColumnFormatter(range => range.Style.Numberformat.Format = "MM/dd/yyyy"); sheet1.Column(x => x.Quantity) @@ -28,7 +29,7 @@ protected override void OnModelCreating(ExcelModelBuilder builder) .ColumnFormatter(range => range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center); sheet1.Column(x => x.Description) .HeaderFormatter(headerFormatter); - sheet1.Column(x => x.Amount) + sheet1.Column(x => x.Amount).AlternateName("some amount") .HeaderFormatter(headerFormatter) .ColumnFormatter(numberFormatter); sheet1.Column(x => x.Total) @@ -75,7 +76,7 @@ protected override void OnModelCreating(ExcelModelBuilder builder) sheet2.Column(x => x.IntColumn); sheet2.Column(x => x.FloatColumn); sheet2.Column(x => x.DoubleColumn); - sheet2.Column(x => x.StringColumn); + sheet2.Column(x => x.StringColumn).AlternateName("be a string column"); sheet2.Column(x => x.BooleanColumn); sheet2.Column(x => x.DateTimeColumn) .ColumnFormatter(range => range.Style.Numberformat.Format = "MM/dd/yyyy hh:mm AM/PM"); diff --git a/src/Shane32.ExcelLinq/ExcelContext.cs b/src/Shane32.ExcelLinq/ExcelContext.cs index 08c1f7b..48ab7df 100644 --- a/src/Shane32.ExcelLinq/ExcelContext.cs +++ b/src/Shane32.ExcelLinq/ExcelContext.cs @@ -75,23 +75,7 @@ protected ExcelContext(string filename) : this() // _sheets = InitializeReadFile(package); // _initialized = true; //} - - protected ExcelContext(Stream stream, string extensionType) : this() - { - if (stream == null) - throw new ArgumentNullException(nameof(stream)); - if(extensionType == ".csv") { - var packaget = new ExcelPackage(); - _initialized = false; - _sheets = OnReadCSVFile(packaget.Workbook, stream ); - _initialized = true; - } else { - using var package = new ExcelPackage(stream); - _initialized = false; - _sheets = InitializeReadFile(package); - _initialized = true; - } - } + protected ExcelContext(Stream stream) : this() { if (stream == null) throw new ArgumentNullException(nameof(stream)); @@ -118,6 +102,23 @@ protected ExcelContext(ExcelPackage excelPackage) : this() _initialized = true; } + + public void ReadCsv(Stream stream) + { + var sheet1 = _model.Sheets.FirstOrDefault(); + var col = sheet1.Columns; + var coltt = sheet1.Columns.FirstOrDefault(); + var qqq = sheet1.Columns.Select(x => x.AlternateNames); + var ggg = sheet1.Columns.Select(x => x.Name); + var alts = sheet1.AlternateNames; + var sheet = _sheets.FirstOrDefault(); + + var tt = sheet.GetType(); + + PropertyInfo[] propertyInfos; + propertyInfos = tt.GetProperties(); + + } //internal ExcelContext(IExcelModel model, ExcelPackage excelPackage) : this(model) //{ // _initialized = false; From 487bdd40463d8ca198c94b03d703d3b9a3f0ea5c Mon Sep 17 00:00:00 2001 From: Curtis Brown Date: Wed, 14 Dec 2022 17:29:06 -0500 Subject: [PATCH 3/9] eod --- src/Shane32.ExcelLinq/ExcelContext.cs | 42 ++++++++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) diff --git a/src/Shane32.ExcelLinq/ExcelContext.cs b/src/Shane32.ExcelLinq/ExcelContext.cs index 48ab7df..aeb5357 100644 --- a/src/Shane32.ExcelLinq/ExcelContext.cs +++ b/src/Shane32.ExcelLinq/ExcelContext.cs @@ -110,6 +110,8 @@ public void ReadCsv(Stream stream) var coltt = sheet1.Columns.FirstOrDefault(); var qqq = sheet1.Columns.Select(x => x.AlternateNames); var ggg = sheet1.Columns.Select(x => x.Name); + + var alts = sheet1.AlternateNames; var sheet = _sheets.FirstOrDefault(); @@ -117,7 +119,45 @@ public void ReadCsv(Stream stream) PropertyInfo[] propertyInfos; propertyInfos = tt.GetProperties(); - + + using (var allSalesDbPartsParser = new TextFieldParser(stream)) { + //allEbayListingsParser.CommentTokens = new string[] { "#" }; + allSalesDbPartsParser.SetDelimiters(new string[] { "," }); + allSalesDbPartsParser.HasFieldsEnclosedInQuotes = true; + + //skip random line if junk + allSalesDbPartsParser.ReadLine(); + + // Skip the row with the column names + //var cols11 = allSalesDbPartsParser.ReadFields(); + var cols = allSalesDbPartsParser.ReadFields(); + var skuIndex = 0; + var qtyIndex = 0; + for (var i = 0; i < cols.Count(); i++) { + var col = cols[i].ToLower(); + if (col == ("Custom label (SKU)").ToLower()) { + skuIndex = i; + } + + if (col == ("Available quantity").ToLower()) { + qtyIndex = i; + } + } + + + while (!allSalesDbPartsParser.EndOfData) { + var part = new EbayInput(); + string[] fields = allSalesDbPartsParser.ReadFields(); + part.Sku = fields[skuIndex]; + part.Quantity = decimal.Parse(fields[qtyIndex]); + //part.Sku = fields[10]; + //part.Quantity = decimal.Parse(fields[7]); + + + EbayInputs.Add(part); + } + } + } //internal ExcelContext(IExcelModel model, ExcelPackage excelPackage) : this(model) //{ From 1cc38a46bd2462ab6f496f8067ab8bf79f673e9a Mon Sep 17 00:00:00 2001 From: Curtis1857 Date: Wed, 14 Dec 2022 22:50:23 -0500 Subject: [PATCH 4/9] tt --- src/Shane32.ExcelLinq/ExcelContext.cs | 129 +++++++++++++++++--------- 1 file changed, 86 insertions(+), 43 deletions(-) diff --git a/src/Shane32.ExcelLinq/ExcelContext.cs b/src/Shane32.ExcelLinq/ExcelContext.cs index aeb5357..26ffcc3 100644 --- a/src/Shane32.ExcelLinq/ExcelContext.cs +++ b/src/Shane32.ExcelLinq/ExcelContext.cs @@ -106,58 +106,101 @@ protected ExcelContext(ExcelPackage excelPackage) : this() public void ReadCsv(Stream stream) { var sheet1 = _model.Sheets.FirstOrDefault(); - var col = sheet1.Columns; - var coltt = sheet1.Columns.FirstOrDefault(); - var qqq = sheet1.Columns.Select(x => x.AlternateNames); - var ggg = sheet1.Columns.Select(x => x.Name); + var sheetType = sheet1.Type; + //var sheetType = sheet1.GetType(); + var ggggg = sheetType.GetProperties(); + //PropertyInfo rrrrrrr = sheetType.GetProperty("UnderlyingSystemType"); + //creats single instance + object tyy = Activator.CreateInstance(sheetType); + var tt = tyy.GetType(); + PropertyInfo prop = tt.GetProperty("Description"); - var alts = sheet1.AlternateNames; - var sheet = _sheets.FirstOrDefault(); - - var tt = sheet.GetType(); - - PropertyInfo[] propertyInfos; - propertyInfos = tt.GetProperties(); - - using (var allSalesDbPartsParser = new TextFieldParser(stream)) { - //allEbayListingsParser.CommentTokens = new string[] { "#" }; - allSalesDbPartsParser.SetDelimiters(new string[] { "," }); - allSalesDbPartsParser.HasFieldsEnclosedInQuotes = true; - - //skip random line if junk - allSalesDbPartsParser.ReadLine(); - - // Skip the row with the column names - //var cols11 = allSalesDbPartsParser.ReadFields(); - var cols = allSalesDbPartsParser.ReadFields(); - var skuIndex = 0; - var qtyIndex = 0; - for (var i = 0; i < cols.Count(); i++) { - var col = cols[i].ToLower(); - if (col == ("Custom label (SKU)").ToLower()) { - skuIndex = i; - } + prop.SetValue(tyy, "hey"); + //var test = new Class1() - if (col == ("Available quantity").ToLower()) { - qtyIndex = i; - } - } + //var param = System.Linq.Expressions.Expression.Parameter(sheetType); + //var body = System.Linq.Expressions.Expression.Property(param, "StringColumn"); + //var expr = System.Linq.Expressions.Expression.Lambda( + // body, param); + //var t = expr.Compile(); - while (!allSalesDbPartsParser.EndOfData) { - var part = new EbayInput(); - string[] fields = allSalesDbPartsParser.ReadFields(); - part.Sku = fields[skuIndex]; - part.Quantity = decimal.Parse(fields[qtyIndex]); - //part.Sku = fields[10]; - //part.Quantity = decimal.Parse(fields[7]); + //creats list on class + Type genericListType = typeof(List<>); + Type concreteListType = genericListType.MakeGenericType(sheetType); + object list = Activator.CreateInstance(concreteListType); + var colsNames = sheet1.Columns.Select(x => x.Name); + var altnames = sheet1.Columns.Select(x => x.AlternateNames); + var colss = sheet1.Columns; + + var parse = new List(); + foreach (var col in colss) { + var name = col.Name; + var alt = col.AlternateNames; + var type = col.Type; + + var qqq = parse[1]; + var dt = Convert.ChangeType("2009/12/12", type); - EbayInputs.Add(part); - } } + //var t = sheetType.GetConstructor(); + //var qqqt = sheetType.GetConstructor(new Type[] { typeof(string) }); + + //ConstructorInfo ctor = sheetType.GetConstructor(new[] { typeof(int) }); + //object instance = ctor.Invoke(new object[] { 10 }); + //object list = Activator.CreateInstance(concreteListType, new object[] { values }); + //ConstructorInfo ctor = sheetType.GetConstructor(new { }); + //object instance = ctor.Invoke(new object[] { 10 }); + + + //var sheet = _sheets.FirstOrDefault(); + + //var tt = sheet.Type; + + //PropertyInfo[] propertyInfos; + //propertyInfos = tt.GetProperties(); + + //using (var allSalesDbPartsParser = new TextFieldParser(stream)) { + // //allEbayListingsParser.CommentTokens = new string[] { "#" }; + // allSalesDbPartsParser.SetDelimiters(new string[] { "," }); + // allSalesDbPartsParser.HasFieldsEnclosedInQuotes = true; + + // //skip random line if junk + // allSalesDbPartsParser.ReadLine(); + + // // Skip the row with the column names + // //var cols11 = allSalesDbPartsParser.ReadFields(); + // var cols = allSalesDbPartsParser.ReadFields(); + // var skuIndex = 0; + // var qtyIndex = 0; + // for (var i = 0; i < cols.Count(); i++) { + // var col = cols[i].ToLower(); + // if (col == ("Custom label (SKU)").ToLower()) { + // skuIndex = i; + // } + + // if (col == ("Available quantity").ToLower()) { + // qtyIndex = i; + // } + // } + + + // while (!allSalesDbPartsParser.EndOfData) { + // var part = new EbayInput(); + // string[] fields = allSalesDbPartsParser.ReadFields(); + // part.Sku = fields[skuIndex]; + // part.Quantity = decimal.Parse(fields[qtyIndex]); + // //part.Sku = fields[10]; + // //part.Quantity = decimal.Parse(fields[7]); + + + // EbayInputs.Add(part); + // } + //} + } //internal ExcelContext(IExcelModel model, ExcelPackage excelPackage) : this(model) //{ From f09fd7fb705058ad904f778ca58045c5d694d03e Mon Sep 17 00:00:00 2001 From: Curtis1857 Date: Fri, 16 Dec 2022 01:43:08 -0500 Subject: [PATCH 5/9] reflection to create object and list and add to list --- src/Shane32.ExcelLinq/ExcelContext.cs | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/Shane32.ExcelLinq/ExcelContext.cs b/src/Shane32.ExcelLinq/ExcelContext.cs index 26ffcc3..80d5e0e 100644 --- a/src/Shane32.ExcelLinq/ExcelContext.cs +++ b/src/Shane32.ExcelLinq/ExcelContext.cs @@ -107,29 +107,25 @@ public void ReadCsv(Stream stream) { var sheet1 = _model.Sheets.FirstOrDefault(); var sheetType = sheet1.Type; - //var sheetType = sheet1.GetType(); - var ggggg = sheetType.GetProperties(); - //PropertyInfo rrrrrrr = sheetType.GetProperty("UnderlyingSystemType"); + var fields = sheetType.GetFields(); //creats single instance object tyy = Activator.CreateInstance(sheetType); - var tt = tyy.GetType(); - PropertyInfo prop = tt.GetProperty("Description"); - prop.SetValue(tyy, "hey"); - //var test = new Class1() + var qq = sheetType.GetField("Description"); + qq.SetValue(tyy, "new value"); - //var param = System.Linq.Expressions.Expression.Parameter(sheetType); - //var body = System.Linq.Expressions.Expression.Property(param, "StringColumn"); - //var expr = System.Linq.Expressions.Expression.Lambda( - // body, param); - //var t = expr.Compile(); - //creats list on class Type genericListType = typeof(List<>); Type concreteListType = genericListType.MakeGenericType(sheetType); object list = Activator.CreateInstance(concreteListType); + var liTy = list.GetType(); + var add = liTy.GetMethod("Add"); + add.Invoke(list, new object[] { tyy}); + + + var colsNames = sheet1.Columns.Select(x => x.Name); var altnames = sheet1.Columns.Select(x => x.AlternateNames); From 4de8cee62459740f925b83ffb871eb174b432564 Mon Sep 17 00:00:00 2001 From: Curtis Brown Date: Fri, 16 Dec 2022 17:35:33 -0500 Subject: [PATCH 6/9] done --- .../General/EndToEnd.cs | 2 +- src/Shane32.ExcelLinq/ExcelContext.cs | 75 ++++++++++++++++--- 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs b/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs index 07f2492..92d77a0 100644 --- a/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs +++ b/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs @@ -27,7 +27,7 @@ public void ReadSampleCsvFile() { var xl = new TestFileContext(); using var stream = new System.IO.FileStream("test.csv", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); - xl.ReadCsv(stream); + xl.ReadCsv(stream); ReadSample1File_test(xl); } diff --git a/src/Shane32.ExcelLinq/ExcelContext.cs b/src/Shane32.ExcelLinq/ExcelContext.cs index 80d5e0e..3569478 100644 --- a/src/Shane32.ExcelLinq/ExcelContext.cs +++ b/src/Shane32.ExcelLinq/ExcelContext.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Linq.Expressions; using System.Reflection; using OfficeOpenXml; using Shane32.ExcelLinq.Builders; @@ -103,28 +104,80 @@ protected ExcelContext(ExcelPackage excelPackage) : this() } - public void ReadCsv(Stream stream) + public void ReadCsv(Stream stream) { var sheet1 = _model.Sheets.FirstOrDefault(); var sheetType = sheet1.Type; var fields = sheetType.GetFields(); - + //creats single instance - object tyy = Activator.CreateInstance(sheetType); + T tyy = Activator.CreateInstance(); + + //T tyy = Activator.CreateInstance(sheetType); - var qq = sheetType.GetField("Description"); - qq.SetValue(tyy, "new value"); + //var qq = sheetType.GetField("StringColumn"); + //qq.SetValue(tyy, "new value"); //creats list on class - Type genericListType = typeof(List<>); - Type concreteListType = genericListType.MakeGenericType(sheetType); - object list = Activator.CreateInstance(concreteListType); - var liTy = list.GetType(); - var add = liTy.GetMethod("Add"); - add.Invoke(list, new object[] { tyy}); + //Type genericListType = typeof(List<>); + //Type concreteListType = genericListType.MakeGenericType(sheetType); + //var list = Activator.CreateInstance(concreteListType); + //var liTy = list.GetType(); + //var add = liTy.GetMethod("Add"); + //add.Invoke(list, new object[] { tyy}); + + + //var param = System.Linq.Expressions.Expression.Parameter(sheetType); + //var body = System.Linq.Expressions.Expression.Field(param, "Description"); + ////var expr = System.Linq.Expressions.Expression.Lambda>( + //var expr = System.Linq.Expressions.Expression.Lambda( + // body, param); + //var eee = expr.Compile(); + var ttt = GetPropFunc("StringColumn"); + var ttt2 = ttt(tyy); + + + Func GetPropFunc(string propName) + { + var param = System.Linq.Expressions.Expression.Parameter(typeof(T)); + var body = System.Linq.Expressions.Expression.Field(param, propName); + var expr = System.Linq.Expressions.Expression.Lambda>( + body, param); + return expr.Compile(); + } + + + // Create an instance of the example class. + // Example obj = new Example(); + //void setFunc() + //{ + + // Define a parameter for the expression tree. + ParameterExpression param = Expression.Parameter(typeof(T), "x"); + + // Create an expression tree that represents the property access x.MyProperty. + MemberExpression property = Expression.Property(param, "MyProperty"); + + // Create an expression tree that represents the assignment x.MyProperty = 42. + BinaryExpression assignment = Expression.Assign(property, Expression.Constant(42)); + + // Create an expression tree that represents the lambda expression x => x.MyProperty = 42. + Expression setProperty = Expression.Lambda(assignment, param); + + // Compile the expression tree into a delegate. + Action setPropertyAction = (Action)setProperty.Compile(); + + // Invoke the delegate to set the property value. + setPropertyAction(tyy); + + // Print the property value. + // Console.WriteLine(obj.MyProperty); // Output: 42 + //} + + var colsNames = sheet1.Columns.Select(x => x.Name); From a2ceebc36f6c26b34d0f798a72e0d4ee90407cb1 Mon Sep 17 00:00:00 2001 From: Curtis1857 Date: Sun, 18 Dec 2022 22:23:59 -0500 Subject: [PATCH 7/9] closer i think --- .../Models/TestFileContext.cs | 2 + .../Builders/ExcelModelBuilder.cs | 5 +- .../Builders/SheetModelBuilder.cs | 1 + src/Shane32.ExcelLinq/ExcelContext.cs | 287 ++++++++++++++---- src/Shane32.ExcelLinq/Models/IExcelModel.cs | 1 + .../Shane32.ExcelLinq.csproj | 1 + 6 files changed, 230 insertions(+), 67 deletions(-) diff --git a/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs b/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs index 8aa9e77..b770e75 100644 --- a/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs +++ b/src/Shane32.ExcelLinq.Tests/Models/TestFileContext.cs @@ -19,6 +19,8 @@ protected override void OnModelCreating(ExcelModelBuilder builder) range.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.Center; range.Style.Border.Bottom.Style = OfficeOpenXml.Style.ExcelBorderStyle.Thin; }; + builder.ReadCsv(); + Action numberFormatter = range => range.Style.Numberformat.Format = "#,##0.00"; var sheet1 = builder.Sheet(); sheet1.Column(x => x.Date).AlternateName("its a date") diff --git a/src/Shane32.ExcelLinq/Builders/ExcelModelBuilder.cs b/src/Shane32.ExcelLinq/Builders/ExcelModelBuilder.cs index 0204e29..cb40e6c 100644 --- a/src/Shane32.ExcelLinq/Builders/ExcelModelBuilder.cs +++ b/src/Shane32.ExcelLinq/Builders/ExcelModelBuilder.cs @@ -11,12 +11,13 @@ public class ExcelModelBuilder : IExcelModel, ISheetModelLookup internal Dictionary _sheetDictionary = new Dictionary(); internal Dictionary _typeDictionary = new Dictionary(); private bool _ignoreSheetNames; + public bool _readCsv; public SheetModelBuilder Sheet() where T : new() { return Sheet(typeof(T).Name); } - + public SheetModelBuilder Sheet(string name) where T : new() { if (name == null) throw new ArgumentNullException(nameof(name)); @@ -33,6 +34,8 @@ public void IgnoreSheetNames() { _ignoreSheetNames = true; } + bool IExcelModel.ReadCsv => _readCsv; + public void ReadCsv() => _readCsv = true; IEnumerator IEnumerable.GetEnumerator() => _sheets.GetEnumerator(); diff --git a/src/Shane32.ExcelLinq/Builders/SheetModelBuilder.cs b/src/Shane32.ExcelLinq/Builders/SheetModelBuilder.cs index 017642b..45e8882 100644 --- a/src/Shane32.ExcelLinq/Builders/SheetModelBuilder.cs +++ b/src/Shane32.ExcelLinq/Builders/SheetModelBuilder.cs @@ -32,6 +32,7 @@ public SheetModelBuilder(ExcelModelBuilder excelModelBuilder, string name) excelModelBuilder._typeDictionary.Add(typeof(T), this); } + public SheetModelBuilder AlternateName(string name) { if (string.IsNullOrWhiteSpace(name)) throw new ArgumentNullException(nameof(name)); diff --git a/src/Shane32.ExcelLinq/ExcelContext.cs b/src/Shane32.ExcelLinq/ExcelContext.cs index 3569478..e3361e5 100644 --- a/src/Shane32.ExcelLinq/ExcelContext.cs +++ b/src/Shane32.ExcelLinq/ExcelContext.cs @@ -104,7 +104,11 @@ protected ExcelContext(ExcelPackage excelPackage) : this() } - public void ReadCsv(Stream stream) + public IList ReadCsv(Stream stream) + { + return OnReadCSv(stream, Model.Sheets[0]); + } + public void ReadCsvOld(Stream stream) { var sheet1 = _model.Sheets.FirstOrDefault(); var sheetType = sheet1.Type; @@ -136,8 +140,8 @@ public void ReadCsv(Stream stream) //var eee = expr.Compile(); - var ttt = GetPropFunc("StringColumn"); - var ttt2 = ttt(tyy); + //var ttt = GetPropFunc("StringColumn"); + //var ttt2 = ttt(tyy); Func GetPropFunc(string propName) @@ -156,22 +160,22 @@ Func GetPropFunc(string propName) //{ // Define a parameter for the expression tree. - ParameterExpression param = Expression.Parameter(typeof(T), "x"); + //ParameterExpression param = Expression.Parameter(typeof(T), "x"); - // Create an expression tree that represents the property access x.MyProperty. - MemberExpression property = Expression.Property(param, "MyProperty"); + //// Create an expression tree that represents the property access x.MyProperty. + //MemberExpression property = Expression.Property(param, "MyProperty"); - // Create an expression tree that represents the assignment x.MyProperty = 42. - BinaryExpression assignment = Expression.Assign(property, Expression.Constant(42)); + //// Create an expression tree that represents the assignment x.MyProperty = 42. + //BinaryExpression assignment = Expression.Assign(property, Expression.Constant(42)); - // Create an expression tree that represents the lambda expression x => x.MyProperty = 42. - Expression setProperty = Expression.Lambda(assignment, param); + //// Create an expression tree that represents the lambda expression x => x.MyProperty = 42. + //Expression setProperty = Expression.Lambda(assignment, param); // Compile the expression tree into a delegate. - Action setPropertyAction = (Action)setProperty.Compile(); + //Action setPropertyAction = (Action)setProperty.Compile(); // Invoke the delegate to set the property value. - setPropertyAction(tyy); + //setPropertyAction(tyy); // Print the property value. // Console.WriteLine(obj.MyProperty); // Output: 42 @@ -180,20 +184,20 @@ Func GetPropFunc(string propName) - var colsNames = sheet1.Columns.Select(x => x.Name); - var altnames = sheet1.Columns.Select(x => x.AlternateNames); - var colss = sheet1.Columns; + //var colsNames = sheet1.Columns.Select(x => x.Name); + //var altnames = sheet1.Columns.Select(x => x.AlternateNames); + //var colss = sheet1.Columns; - var parse = new List(); - foreach (var col in colss) { - var name = col.Name; - var alt = col.AlternateNames; - var type = col.Type; + //var parse = new List(); + //foreach (var col in colss) { + // var name = col.Name; + // var alt = col.AlternateNames; + // var type = col.Type; - var qqq = parse[1]; - var dt = Convert.ChangeType("2009/12/12", type); + // var qqq = parse[1]; + // var dt = Convert.ChangeType("2009/12/12", type); - } + //} //var t = sheetType.GetConstructor(); //var qqqt = sheetType.GetConstructor(new Type[] { typeof(string) }); @@ -292,48 +296,6 @@ protected IList CreateListForSheet(Type type, int capacity) protected abstract void OnModelCreating(ExcelModelBuilder modelBuilder); - protected virtual List OnReadCSVFile(ExcelWorkbook workbook, Stream stream) - { - if (workbook == null) - throw new ArgumentNullException(nameof(workbook)); - var sheets = new List(new IList[Model.Sheets.Count]); - - var sheetArray = Model.Sheets.ToList(); - //if (Model.IgnoreSheetNames) { - // for (var i = 0; i < workbook.Worksheets.Count && i < sheetArray.Count; i++) { - // var worksheet = workbook.Worksheets[i]; - // var sheetModel = Model.Sheets[i]; - // var sheetData = OnReadSheet(worksheet, sheetModel); - // if (sheetData == null) - // throw new InvalidOperationException($"{nameof(OnReadSheet)} returned null for sheet '{sheetModel.Name}'"); - // sheets[i] = sheetData; - // } - //} else{ - //foreach (var workSheet in workbook.Worksheets) { - // if (Model.Sheets.TryGetValue(workSheet.Name, out var sheetModel)) { - // var sheetIndex = sheetArray.IndexOf(sheetModel); - // if (sheets[sheetIndex] != null) - // throw new DuplicateSheetException(sheetModel.Name); - // var sheetData = OnReadSheet(workSheet, sheetModel); - // if (sheetData == null) - // throw new InvalidOperationException($"{nameof(OnReadSheet)} returned null for sheet '{sheetModel.Name}'"); - // sheets[sheetIndex] = sheetData; - // } - //} - //} - - for (int i = 0; i < Model.Sheets.Count; i++) { - if (sheets[i] == null) { - var sheetModel = Model.Sheets[i]; - if (sheetModel.Optional) - sheets[i] = CreateListForSheet(sheetModel.Type); - else - throw new SheetMissingException(sheetModel.Name); - } - } - - return sheets; - } /// /// Parses an and returns all of the data within all the worksheets. @@ -381,7 +343,96 @@ protected virtual List OnReadFile(ExcelWorkbook workbook) return sheets; } + protected virtual IList OnReadCSv(Stream stream, ISheetModel model) + { + //if (worksheet == null) + // throw new ArgumentNullException(nameof(worksheet)); + //if (model == null) + // throw new ArgumentNullException(nameof(model)); + //ExcelRange dataRange = (model.ReadRangeLocator ?? DefaultReadRangeLocator)(worksheet); + //allEbayListingsParser.CommentTokens = new string[] { "#" }; + //allSalesDbPartsParser.SetDelimiters(new string[] { "," }); + using (var parser = new NotVisualBasic.FileIO.CsvTextFieldParser(stream)) { + + parser.Delimiters = new string[] { "," }; + parser.HasFieldsEnclosedInQuotes = true; + + var Rows = 10; + var collumns = 10; + var StartRow = 0; + var ColumnStart = 0; + var EndRow = 20; + + var headerRow = 0; + var currentRow = 0; + string[] headers = null; + while (!parser.EndOfData) { + if(currentRow == headerRow) { + headers = parser.ReadFields(); + ++currentRow; + break; + } + ++currentRow; + } + if (headers == null) { + //throw error + } + + //if (dataRange == null) { + // //no data on sheet + // if (model.Columns.Any(x => !x.Optional)) + // throw new SheetEmptyException(model.Name); + // return CreateListForSheet(model.Type); + //} + IList data = CreateListForSheet(model.Type, Rows - 1); + //var headerRow = StartRow; + var firstCol = ColumnStart; + var columns = collumns; + var firstRow = StartRow + 1; + var lastRow = EndRow; + var columnMapping = new IColumnModel[columns]; + var columnMapped = new bool[model.Columns.Count]; + var modelColumns = model.Columns.ToList(); + + for (int colIndex = 0; colIndex < columns; colIndex++) { + var col = colIndex + firstCol; + var cell = headers[col]; + if (cell != null) { + var headerName = cell; + if (model.Columns.TryGetValue(headerName, out var columnModel)) { + var columnModelIndex = modelColumns.IndexOf(columnModel); + if (columnMapped[columnModelIndex]) + throw new DuplicateColumnException(columnModel.Name, model.Name); + columnMapped[columnModelIndex] = true; + columnMapping[colIndex] = columnModel; + } + } + } + + for (int i = 0; i < model.Columns.Count; i++) { + if (columnMapped[i] == false && !model.Columns[i].Optional) + throw new ColumnMissingException(model.Columns[i].Name, model.Name); + } + + while(!parser.EndOfData) { + //var range = worksheet.Cells[row, firstCol, row, firstCol + columns - 1]; + var range = parser.ReadFields(); + var obj = OnReadCSVRow(range, model, columnMapping); + if (obj != null) + data.Add(obj); + ++currentRow; + } + // for (int row = firstRow; row <= lastRow; row++) { + // var range = worksheet.Cells[row, firstCol, row, firstCol + columns - 1]; + // var obj = OnReadRow(range, model, columnMapping); + // if (obj != null) + // data.Add(obj); + //} + + return data; + } + } /// @@ -438,7 +489,64 @@ protected virtual IList OnReadSheet(ExcelWorksheet worksheet, ISheetModel model) return data; } - + protected virtual object OnReadCSVRow(string[] range, ISheetModel model, IColumnModel[] columnMapping) + { + if (range == null) + throw new ArgumentNullException(nameof(range)); + if (model == null) + throw new ArgumentNullException(nameof(range)); + if (columnMapping == null) + throw new ArgumentNullException(nameof(columnMapping)); + var firstCol = 0; + var row = 0; + var columns = range.Length; + //if (range.Rows != 1) + // throw new ArgumentOutOfRangeException(nameof(range), "Range must represent a single row of data"); + if (columns != columnMapping.Length) + throw new ArgumentOutOfRangeException(nameof(columnMapping), "Number of columns in range does not match size of columnMapping array"); + var obj = Activator.CreateInstance(model.Type); + if (range.Any(x => x != null)) { + for (int colIndex = 0; colIndex < columns; colIndex++) { + var col = colIndex + firstCol; + var columnModel = columnMapping[colIndex]; + if (columnModel != null) { + var cell = range[col]; // note that range[] resets range.Address to equal the new address + if (cell == null) { + if (!columnModel.Optional) + throw new ColumnDataMissingException(columnModel.Name, model.Name); + } else { + object value; + try { + //if (columnModel.ReadSerializer != null) { + // value = columnModel.ReadSerializer(cell); + //} else { + value = DefaultCsvReadSerializer(cell, cell, columnModel.Type); + //} + } catch (Exception e) { + throw new ParseDataException(cell, columnModel.Name, model.Name, e); + } + if (value != null) { + if (columnModel.Member is PropertyInfo propertyInfo) { + propertyInfo.SetMethod.Invoke(obj, new[] { value }); + } else if (columnModel.Member is FieldInfo fieldInfo) { + fieldInfo.SetValue(obj, value); + } + } + } + } + } + } else { + if (model.SkipEmptyRows) { + obj = null; + } else { + foreach (var columnModel in columnMapping) { + if (!columnModel.Optional) + throw new RowEmptyException(model.Name); + } + } + } + return obj; + } /// /// Parses a row of data or returns null if the row should be skipped /// @@ -508,6 +616,53 @@ protected virtual ExcelRange DefaultReadRangeLocator(ExcelWorksheet worksheet) if (dimension == null) return null; // no cells return worksheet.Cells[dimension.Start.Row, dimension.Start.Column, dimension.End.Row, dimension.End.Column]; } + protected virtual object DefaultCsvReadSerializer(object value, string text, Type dataType) + { + if (value == null) { + return null; + } + if (dataType.IsGenericType && dataType.GetGenericTypeDefinition() == typeof(Nullable<>)) { + return DefaultCsvReadSerializer(value, text, Nullable.GetUnderlyingType(dataType)); + } + if (value.GetType() == dataType) + return value; + if (dataType == typeof(string)) + return text; + if (dataType == typeof(DateTime)) { + if (value is string str) + return DateTime.Parse(str); + return DateTime.FromOADate((double)DefaultCsvReadSerializer(value, text, typeof(double))); + } + if (dataType == typeof(TimeSpan)) { + if (value is DateTime dt) + return dt.TimeOfDay; + if (value is string str) + return TimeSpan.Parse(str); + return DateTime.FromOADate((double)DefaultCsvReadSerializer(value, text, typeof(double))).TimeOfDay; + } + if (dataType == typeof(DateTimeOffset)) { + throw new NotSupportedException("DateTimeOffset values are not supported"); + } + if (dataType == typeof(Uri)) { + return new Uri(text); + } + if (dataType == typeof(Guid)) { + return Guid.Parse(text); + } + if (dataType == typeof(bool)) { + if (value is string str) { + switch (str.ToLower()) { + case "y": + case "yes": + return true; + case "n": + case "no": + return false; + } + } + } + return Convert.ChangeType(value, dataType); + } /// /// Parses the cell and converts it to the requested data type. For nullable types, diff --git a/src/Shane32.ExcelLinq/Models/IExcelModel.cs b/src/Shane32.ExcelLinq/Models/IExcelModel.cs index ac7b6fe..270f0dc 100644 --- a/src/Shane32.ExcelLinq/Models/IExcelModel.cs +++ b/src/Shane32.ExcelLinq/Models/IExcelModel.cs @@ -4,5 +4,6 @@ public interface IExcelModel { ISheetModelLookup Sheets { get; } bool IgnoreSheetNames { get; } + bool ReadCsv { get; } } } diff --git a/src/Shane32.ExcelLinq/Shane32.ExcelLinq.csproj b/src/Shane32.ExcelLinq/Shane32.ExcelLinq.csproj index 9f735e4..0660e7b 100644 --- a/src/Shane32.ExcelLinq/Shane32.ExcelLinq.csproj +++ b/src/Shane32.ExcelLinq/Shane32.ExcelLinq.csproj @@ -6,6 +6,7 @@ + From 07522ca7b9ccf4e919131bce4a202654bd22cc64 Mon Sep 17 00:00:00 2001 From: Curtis1857 Date: Mon, 19 Dec 2022 22:13:18 -0500 Subject: [PATCH 8/9] hold --- PlayGround/PlayGround.csproj | 22 ++++ PlayGround/Program.cs | 17 +++ Shane32.ExcelLinq.sln | 10 +- src/Shane32.ExcelLinq.Tests/Models/Class1.cs | 2 +- src/Shane32.ExcelLinq/ExcelContext.cs | 129 ++++++++++++------- src/Shane32.ExcelLinq/Models/CsvRange.cs | 14 ++ src/Shane32.ExcelLinq/Models/ISheetModel.cs | 1 + 7 files changed, 147 insertions(+), 48 deletions(-) create mode 100644 PlayGround/PlayGround.csproj create mode 100644 PlayGround/Program.cs create mode 100644 src/Shane32.ExcelLinq/Models/CsvRange.cs diff --git a/PlayGround/PlayGround.csproj b/PlayGround/PlayGround.csproj new file mode 100644 index 0000000..bbdfde2 --- /dev/null +++ b/PlayGround/PlayGround.csproj @@ -0,0 +1,22 @@ + + + + Exe + net6.0 + enable + enable + + + + 10.0 + + + + 10.0 + + + + + + + diff --git a/PlayGround/Program.cs b/PlayGround/Program.cs new file mode 100644 index 0000000..5264535 --- /dev/null +++ b/PlayGround/Program.cs @@ -0,0 +1,17 @@ +// See https://aka.ms/new-console-template for more information +using Shane32.ExcelLinq.Tests.Models; + +Console.WriteLine("Hello, World!"); + + + +using var stream1 = new System.IO.FileStream("test.xlsx", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); +var tt = new TestFileContext(stream1); +var pp = tt.GetSheet(); +var xl = new TestFileContext(); +using var stream = new System.IO.FileStream("test.csv", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); +var t = xl.ReadCsv(stream); + + +var g = t; + diff --git a/Shane32.ExcelLinq.sln b/Shane32.ExcelLinq.sln index b4c6372..8eae7eb 100644 --- a/Shane32.ExcelLinq.sln +++ b/Shane32.ExcelLinq.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.30611.23 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32602.215 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution items", "Solution items", "{B194B3FB-53C8-4C5D-ABC3-EAB6A52C674D}" ProjectSection(SolutionItems) = preProject @@ -18,6 +18,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shane32.ExcelLinq", "src\Sh EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shane32.ExcelLinq.Tests", "src\Shane32.ExcelLinq.Tests\Shane32.ExcelLinq.Tests.csproj", "{83E2AC89-22B4-438D-92CF-FDA280B63CFD}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlayGround", "PlayGround\PlayGround.csproj", "{1F2D99BC-84B4-4704-B3AB-C9EB6A2091B7}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,6 +34,10 @@ Global {83E2AC89-22B4-438D-92CF-FDA280B63CFD}.Debug|Any CPU.Build.0 = Debug|Any CPU {83E2AC89-22B4-438D-92CF-FDA280B63CFD}.Release|Any CPU.ActiveCfg = Release|Any CPU {83E2AC89-22B4-438D-92CF-FDA280B63CFD}.Release|Any CPU.Build.0 = Release|Any CPU + {1F2D99BC-84B4-4704-B3AB-C9EB6A2091B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1F2D99BC-84B4-4704-B3AB-C9EB6A2091B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1F2D99BC-84B4-4704-B3AB-C9EB6A2091B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1F2D99BC-84B4-4704-B3AB-C9EB6A2091B7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/Shane32.ExcelLinq.Tests/Models/Class1.cs b/src/Shane32.ExcelLinq.Tests/Models/Class1.cs index 494a060..13478e3 100644 --- a/src/Shane32.ExcelLinq.Tests/Models/Class1.cs +++ b/src/Shane32.ExcelLinq.Tests/Models/Class1.cs @@ -2,7 +2,7 @@ namespace Shane32.ExcelLinq.Tests.Models { - class Class1 + public class Class1 { public string StringColumn; public int IntColumn; diff --git a/src/Shane32.ExcelLinq/ExcelContext.cs b/src/Shane32.ExcelLinq/ExcelContext.cs index e3361e5..1d7a154 100644 --- a/src/Shane32.ExcelLinq/ExcelContext.cs +++ b/src/Shane32.ExcelLinq/ExcelContext.cs @@ -9,6 +9,7 @@ using Shane32.ExcelLinq.Builders; using Shane32.ExcelLinq.Exceptions; using Shane32.ExcelLinq.Models; +using NotVisualBasic.FileIO; namespace Shane32.ExcelLinq { @@ -106,7 +107,7 @@ protected ExcelContext(ExcelPackage excelPackage) : this() public IList ReadCsv(Stream stream) { - return OnReadCSv(stream, Model.Sheets[0]); + return OnReadCSv(stream, Model.Sheets[1]); } public void ReadCsvOld(Stream stream) { @@ -345,50 +346,39 @@ protected virtual List OnReadFile(ExcelWorkbook workbook) protected virtual IList OnReadCSv(Stream stream, ISheetModel model) { - //if (worksheet == null) - // throw new ArgumentNullException(nameof(worksheet)); - //if (model == null) - // throw new ArgumentNullException(nameof(model)); - //ExcelRange dataRange = (model.ReadRangeLocator ?? DefaultReadRangeLocator)(worksheet); - //allEbayListingsParser.CommentTokens = new string[] { "#" }; - //allSalesDbPartsParser.SetDelimiters(new string[] { "," }); - using (var parser = new NotVisualBasic.FileIO.CsvTextFieldParser(stream)) { + using (var parser = new CsvTextFieldParser(stream)) { parser.Delimiters = new string[] { "," }; parser.HasFieldsEnclosedInQuotes = true; - var Rows = 10; - var collumns = 10; - var StartRow = 0; + + //var Rows = 10; + //var collumns = 10; + //var Range = (model.CsvReadRangeLocator ?? DefaultCsvReadRangeLocator)() + var StartRow = 0; var ColumnStart = 0; - var EndRow = 20; - - var headerRow = 0; - var currentRow = 0; - string[] headers = null; - while (!parser.EndOfData) { - if(currentRow == headerRow) { - headers = parser.ReadFields(); - ++currentRow; - break; - } + var EndRow = parser.LineNumber; + + var headerRow = 0; + var currentRow = 0; + string[] headers = null; + while (!parser.EndOfData) { + if(currentRow == headerRow) { + headers = parser.ReadFields(); ++currentRow; + break; } + ++currentRow; + } - if (headers == null) { - //throw error - } + if (headers == null) { + //throw error + } - //if (dataRange == null) { - // //no data on sheet - // if (model.Columns.Any(x => !x.Optional)) - // throw new SheetEmptyException(model.Name); - // return CreateListForSheet(model.Type); - //} - IList data = CreateListForSheet(model.Type, Rows - 1); - //var headerRow = StartRow; + + IList data = CreateListForSheet(model.Type, 0); var firstCol = ColumnStart; - var columns = collumns; + var columns = model.Columns.Count; var firstRow = StartRow + 1; var lastRow = EndRow; var columnMapping = new IColumnModel[columns]; @@ -416,19 +406,13 @@ protected virtual IList OnReadCSv(Stream stream, ISheetModel model) } while(!parser.EndOfData) { - //var range = worksheet.Cells[row, firstCol, row, firstCol + columns - 1]; var range = parser.ReadFields(); var obj = OnReadCSVRow(range, model, columnMapping); if (obj != null) data.Add(obj); ++currentRow; } - // for (int row = firstRow; row <= lastRow; row++) { - // var range = worksheet.Cells[row, firstCol, row, firstCol + columns - 1]; - // var obj = OnReadRow(range, model, columnMapping); - // if (obj != null) - // data.Add(obj); - //} + return data; } @@ -511,7 +495,7 @@ protected virtual object OnReadCSVRow(string[] range, ISheetModel model, IColumn var columnModel = columnMapping[colIndex]; if (columnModel != null) { var cell = range[col]; // note that range[] resets range.Address to equal the new address - if (cell == null) { + if (string.IsNullOrEmpty(cell)) { if (!columnModel.Optional) throw new ColumnDataMissingException(columnModel.Name, model.Name); } else { @@ -637,8 +621,11 @@ protected virtual object DefaultCsvReadSerializer(object value, string text, Typ if (value is DateTime dt) return dt.TimeOfDay; if (value is string str) - return TimeSpan.Parse(str); - return DateTime.FromOADate((double)DefaultCsvReadSerializer(value, text, typeof(double))).TimeOfDay; + try { + return TimeSpan.Parse(str); + } catch (FormatException) { + return DateTime.Parse(str).TimeOfDay; + } } if (dataType == typeof(DateTimeOffset)) { throw new NotSupportedException("DateTimeOffset values are not supported"); @@ -653,15 +640,67 @@ protected virtual object DefaultCsvReadSerializer(object value, string text, Typ if (value is string str) { switch (str.ToLower()) { case "y": + case "1": case "yes": return true; case "n": + case "0": case "no": return false; } } } + if(dataType.ToString() == "NullableIntColumn") { + + } + + if (dataType == typeof(int?)) { + if (value is string str) { + var success = int.TryParse(str, out int result); + if (success) + return result; + return null; + } + } + if (dataType == typeof(int)) { + if (value is string str) { + var success = int.TryParse(str, out int result); + if (success) + return result; + + return Convert.ToInt32(Math.Floor(double.Parse(str))); + } + } + //nullable int tye check + + //if (dataType = typeof(nullableInt) + + if (dataType == typeof(double)) { + if (value is string str) { + return double.Parse(str); + } + } + + if (dataType == typeof(decimal)) { + if (value is string str) { + return decimal.Parse(str); + } + } + + if (dataType == typeof(float)) { + if (value is string str) { + return float.Parse(str); + } + } + + + //try { + return Convert.ChangeType(value, dataType); + //} catch { + // return Convert.ChangeType(Math.Floor(Convert.ToDouble(value)), dataType); + + //} } /// diff --git a/src/Shane32.ExcelLinq/Models/CsvRange.cs b/src/Shane32.ExcelLinq/Models/CsvRange.cs new file mode 100644 index 0000000..32cea08 --- /dev/null +++ b/src/Shane32.ExcelLinq/Models/CsvRange.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Shane32.ExcelLinq.Models +{ + public class CsvRange + { + public int StartColumn { get; set; } + public int StartRow { get; set; } + public int? EndColumn { get; set; } + public int? EndRow { get; set; } + } +} diff --git a/src/Shane32.ExcelLinq/Models/ISheetModel.cs b/src/Shane32.ExcelLinq/Models/ISheetModel.cs index 182c8ea..064fb09 100644 --- a/src/Shane32.ExcelLinq/Models/ISheetModel.cs +++ b/src/Shane32.ExcelLinq/Models/ISheetModel.cs @@ -11,6 +11,7 @@ public interface ISheetModel IReadOnlyList AlternateNames { get; } IColumnModelLookup Columns { get; } Func ReadRangeLocator { get; } + Func CsvReadRangeLocator { get; } Func WriteRangeLocator { get; } Action WritePolisher { get; } bool Optional { get; } From f05189f65857a742e29d0bd2a8fbadd1fcc7a166 Mon Sep 17 00:00:00 2001 From: Shane32 Date: Mon, 15 Jan 2024 18:22:38 -0500 Subject: [PATCH 9/9] Progress --- .../General/EndToEnd.cs | 11 +- src/Shane32.ExcelLinq.Tests/Models/Class1.cs | 2 +- .../Shane32.ExcelLinq.Tests.csproj | 10 +- src/Shane32.ExcelLinq.Tests/test1.csv | 3 + src/Shane32.ExcelLinq.Tests/test2.csv | 10 + src/Shane32.ExcelLinq/ExcelContext.cs | 299 ++++-------------- src/Shane32.ExcelLinq/Models/ISheetModel.cs | 1 - 7 files changed, 98 insertions(+), 238 deletions(-) create mode 100644 src/Shane32.ExcelLinq.Tests/test1.csv create mode 100644 src/Shane32.ExcelLinq.Tests/test2.csv diff --git a/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs b/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs index 2ab495b..b3dee2b 100644 --- a/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs +++ b/src/Shane32.ExcelLinq.Tests/General/EndToEnd.cs @@ -26,8 +26,10 @@ public void NullConstructorsThrow() public void ReadSampleCsvFile() { var xl = new TestFileContext(); - using var stream = new System.IO.FileStream("test.csv", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); - xl.ReadCsv(stream); + using var stream1 = new System.IO.FileStream("test1.csv", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); + using var stream2 = new System.IO.FileStream("test2.csv", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read); + xl.ReadCsv(stream1, "Sheet1"); + xl.ReadCsv(stream2, "Sheet2"); ReadSample1File_test(xl); } @@ -65,10 +67,11 @@ public void ReadAndWrite() Assert.AreEqual(xl.GetSheet().Count, xl2.GetSheet().Count); } - public void ReadSample1File_test(TestFileContext xl) { + public void ReadSample1File_test(TestFileContext xl) + { var sheet1 = xl.GetSheet(); var sheet2 = xl.GetSheet(); - //Assert.AreEqual(2, sheet1.Count); + Assert.AreEqual(2, sheet1.Count); var s1row = sheet1[0]; Assert.AreEqual(DateTime.Parse("7/1/2020"), s1row.Date); diff --git a/src/Shane32.ExcelLinq.Tests/Models/Class1.cs b/src/Shane32.ExcelLinq.Tests/Models/Class1.cs index 13478e3..494a060 100644 --- a/src/Shane32.ExcelLinq.Tests/Models/Class1.cs +++ b/src/Shane32.ExcelLinq.Tests/Models/Class1.cs @@ -2,7 +2,7 @@ namespace Shane32.ExcelLinq.Tests.Models { - public class Class1 + class Class1 { public string StringColumn; public int IntColumn; diff --git a/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj b/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj index 605fd21..db584d8 100644 --- a/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj +++ b/src/Shane32.ExcelLinq.Tests/Shane32.ExcelLinq.Tests.csproj @@ -9,11 +9,19 @@ + + - PreserveNewest + Always + + + Always + + + Always diff --git a/src/Shane32.ExcelLinq.Tests/test1.csv b/src/Shane32.ExcelLinq.Tests/test1.csv new file mode 100644 index 0000000..c04c7dc --- /dev/null +++ b/src/Shane32.ExcelLinq.Tests/test1.csv @@ -0,0 +1,3 @@ +Date,Quantity,Description,Amount, Total ,Notes +7/1/2020,52,Widgets,45.99 ," $2,391.48 ", +7/23/2020,22,Bolts,2.54 , $55.88 ,Each bolt is a set of two diff --git a/src/Shane32.ExcelLinq.Tests/test2.csv b/src/Shane32.ExcelLinq.Tests/test2.csv new file mode 100644 index 0000000..b5d2660 --- /dev/null +++ b/src/Shane32.ExcelLinq.Tests/test2.csv @@ -0,0 +1,10 @@ +IntColumn,FloatColumn,DoubleColumn,StringColumn,BooleanColumn,DateTimeColumn,TimespanColumn,UriColumn,GuidColumn,NullableIntColumn +1,1,1,test,TRUE,2-Aug,2:00 PM,http://localhost/test,f1dc7e7d-d63e-4279-8dfd-cecb6e26cda8,3 +1.1,1.1,1.1,test2,FALSE,8/1/2020,14:00,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,3.1 +1,1.1,1.1,test2,true,8/3/20,14:00,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b,3 +1.1,1.1,1.1,test2,yes,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, +1.1,1.1,1.1,test2,NO,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, +1.1,1.1,1.1,test2,y,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, +1.1,1.1,1.1,test2,N,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, +1.1,1.1,1.1,test2,1,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, +1.1,1.1,1.1,test2,0,8/1/20 2:30 PM,2:34,http://localhost/help,89892480-4179-42c7-9e2f-e0bb1094dd6b, diff --git a/src/Shane32.ExcelLinq/ExcelContext.cs b/src/Shane32.ExcelLinq/ExcelContext.cs index 4bf35af..6e68fa1 100644 --- a/src/Shane32.ExcelLinq/ExcelContext.cs +++ b/src/Shane32.ExcelLinq/ExcelContext.cs @@ -10,6 +10,7 @@ using Shane32.ExcelLinq.Exceptions; using Shane32.ExcelLinq.Models; using NotVisualBasic.FileIO; +using System.Globalization; namespace Shane32.ExcelLinq { @@ -81,7 +82,7 @@ protected ExcelContext(string filename) : this() // _sheets = InitializeReadFile(package); // _initialized = true; //} - + protected ExcelContext(Stream stream) : this() { if (stream == null) @@ -109,165 +110,31 @@ protected ExcelContext(ExcelPackage excelPackage) : this() _initialized = true; } - - public IList ReadCsv(Stream stream) + public void ReadCsv(Stream stream, IFormatProvider formatProvider = null) { - return OnReadCSv(stream, Model.Sheets[1]); + if (!_initialized) + throw new InvalidOperationException(); + var index = _typeLookup[typeof(T)]; + _sheets[index] = (List)OnReadCsv(stream, Model.Sheets[index], formatProvider ?? CultureInfo.CurrentCulture); } - public void ReadCsvOld(Stream stream) - { - var sheet1 = _model.Sheets.FirstOrDefault(); - var sheetType = sheet1.Type; - var fields = sheetType.GetFields(); - - //creats single instance - T tyy = Activator.CreateInstance(); - - //T tyy = Activator.CreateInstance(sheetType); - - //var qq = sheetType.GetField("StringColumn"); - //qq.SetValue(tyy, "new value"); - - - //creats list on class - //Type genericListType = typeof(List<>); - //Type concreteListType = genericListType.MakeGenericType(sheetType); - //var list = Activator.CreateInstance(concreteListType); - //var liTy = list.GetType(); - //var add = liTy.GetMethod("Add"); - //add.Invoke(list, new object[] { tyy}); - - - //var param = System.Linq.Expressions.Expression.Parameter(sheetType); - //var body = System.Linq.Expressions.Expression.Field(param, "Description"); - ////var expr = System.Linq.Expressions.Expression.Lambda>( - //var expr = System.Linq.Expressions.Expression.Lambda( - // body, param); - //var eee = expr.Compile(); - - - //var ttt = GetPropFunc("StringColumn"); - //var ttt2 = ttt(tyy); - - - Func GetPropFunc(string propName) - { - var param = System.Linq.Expressions.Expression.Parameter(typeof(T)); - var body = System.Linq.Expressions.Expression.Field(param, propName); - var expr = System.Linq.Expressions.Expression.Lambda>( - body, param); - return expr.Compile(); - } - - - // Create an instance of the example class. - // Example obj = new Example(); - //void setFunc() - //{ - - // Define a parameter for the expression tree. - //ParameterExpression param = Expression.Parameter(typeof(T), "x"); - - //// Create an expression tree that represents the property access x.MyProperty. - //MemberExpression property = Expression.Property(param, "MyProperty"); - - //// Create an expression tree that represents the assignment x.MyProperty = 42. - //BinaryExpression assignment = Expression.Assign(property, Expression.Constant(42)); - - //// Create an expression tree that represents the lambda expression x => x.MyProperty = 42. - //Expression setProperty = Expression.Lambda(assignment, param); - - // Compile the expression tree into a delegate. - //Action setPropertyAction = (Action)setProperty.Compile(); - - // Invoke the delegate to set the property value. - //setPropertyAction(tyy); - - // Print the property value. - // Console.WriteLine(obj.MyProperty); // Output: 42 - //} - - - - - //var colsNames = sheet1.Columns.Select(x => x.Name); - //var altnames = sheet1.Columns.Select(x => x.AlternateNames); - //var colss = sheet1.Columns; - - //var parse = new List(); - //foreach (var col in colss) { - // var name = col.Name; - // var alt = col.AlternateNames; - // var type = col.Type; - - // var qqq = parse[1]; - // var dt = Convert.ChangeType("2009/12/12", type); - - //} - - //var t = sheetType.GetConstructor(); - //var qqqt = sheetType.GetConstructor(new Type[] { typeof(string) }); - - //ConstructorInfo ctor = sheetType.GetConstructor(new[] { typeof(int) }); - //object instance = ctor.Invoke(new object[] { 10 }); - //object list = Activator.CreateInstance(concreteListType, new object[] { values }); - //ConstructorInfo ctor = sheetType.GetConstructor(new { }); - //object instance = ctor.Invoke(new object[] { 10 }); - - - //var sheet = _sheets.FirstOrDefault(); - - //var tt = sheet.Type; - - //PropertyInfo[] propertyInfos; - //propertyInfos = tt.GetProperties(); - - //using (var allSalesDbPartsParser = new TextFieldParser(stream)) { - // //allEbayListingsParser.CommentTokens = new string[] { "#" }; - // allSalesDbPartsParser.SetDelimiters(new string[] { "," }); - // allSalesDbPartsParser.HasFieldsEnclosedInQuotes = true; - - // //skip random line if junk - // allSalesDbPartsParser.ReadLine(); - - // // Skip the row with the column names - // //var cols11 = allSalesDbPartsParser.ReadFields(); - // var cols = allSalesDbPartsParser.ReadFields(); - // var skuIndex = 0; - // var qtyIndex = 0; - // for (var i = 0; i < cols.Count(); i++) { - // var col = cols[i].ToLower(); - // if (col == ("Custom label (SKU)").ToLower()) { - // skuIndex = i; - // } - - // if (col == ("Available quantity").ToLower()) { - // qtyIndex = i; - // } - // } - - - // while (!allSalesDbPartsParser.EndOfData) { - // var part = new EbayInput(); - // string[] fields = allSalesDbPartsParser.ReadFields(); - // part.Sku = fields[skuIndex]; - // part.Quantity = decimal.Parse(fields[qtyIndex]); - // //part.Sku = fields[10]; - // //part.Quantity = decimal.Parse(fields[7]); - - - // EbayInputs.Add(part); - // } - //} + public void ReadCsv(Stream stream, string name, IFormatProvider formatProvider = null) + { + if (!_initialized) + throw new InvalidOperationException(); + var index = _sheetNameLookup[name]; + _sheets[index] = (List)OnReadCsv(stream, Model.Sheets[index], formatProvider ?? CultureInfo.CurrentCulture); } - //internal ExcelContext(IExcelModel model, ExcelPackage excelPackage) : this(model) - //{ - // _initialized = false; - // _sheets = InitializeReadFile(excelPackage); - // _initialized = true; - //} + public static TContext OpenCsv(Stream stream, IFormatProvider formatProvider = null) + where TContext : ExcelContext, new() + { + var context = new TContext(); + if (context._sheets.Count != 1) + throw new InvalidOperationException("Cannot open CSV file with multiple sheets."); + context.OnReadCsv(stream, context.Model.Sheets[0], formatProvider ?? CultureInfo.CurrentCulture); + return context; + } private List InitializeReadFile(ExcelPackage excelFile) { @@ -347,26 +214,21 @@ protected virtual List OnReadFile(ExcelWorkbook workbook) return sheets; } - protected virtual IList OnReadCSv(Stream stream, ISheetModel model) + /// + /// Parses a CSV file and returns all of the data within the sheet. + /// + protected virtual IList OnReadCsv(Stream stream, ISheetModel model, IFormatProvider formatProvider) { - using (var parser = new CsvTextFieldParser(stream)) { - + using var parser = new CsvTextFieldParser(stream); + parser.Delimiters = new string[] { "," }; parser.HasFieldsEnclosedInQuotes = true; - - - //var Rows = 10; - //var collumns = 10; - //var Range = (model.CsvReadRangeLocator ?? DefaultCsvReadRangeLocator)() - var StartRow = 0; - var ColumnStart = 0; - var EndRow = parser.LineNumber; var headerRow = 0; var currentRow = 0; string[] headers = null; - while (!parser.EndOfData) { - if(currentRow == headerRow) { + while (!parser.EndOfData) { + if (currentRow == headerRow) { headers = parser.ReadFields(); ++currentRow; break; @@ -374,31 +236,23 @@ protected virtual IList OnReadCSv(Stream stream, ISheetModel model) ++currentRow; } - if (headers == null) { - //throw error - } - - IList data = CreateListForSheet(model.Type, 0); - var firstCol = ColumnStart; - var columns = model.Columns.Count; - var firstRow = StartRow + 1; - var lastRow = EndRow; - var columnMapping = new IColumnModel[columns]; + var columnMapping = new IColumnModel[model.Columns.Count]; var columnMapped = new bool[model.Columns.Count]; - var modelColumns = model.Columns.ToList(); - - for (int colIndex = 0; colIndex < columns; colIndex++) { - var col = colIndex + firstCol; - var cell = headers[col]; - if (cell != null) { - var headerName = cell; - if (model.Columns.TryGetValue(headerName, out var columnModel)) { - var columnModelIndex = modelColumns.IndexOf(columnModel); - if (columnMapped[columnModelIndex]) - throw new DuplicateColumnException(columnModel.Name, model.Name); - columnMapped[columnModelIndex] = true; - columnMapping[colIndex] = columnModel; + if (headers != null) { + var modelColumns = model.Columns.ToList(); + + for (int colIndex = 0; colIndex < headers.Length; colIndex++) { + var cell = headers[colIndex]; + if (cell != null) { + var headerName = cell; + if (model.Columns.TryGetValue(headerName, out var columnModel)) { + var columnModelIndex = modelColumns.IndexOf(columnModel); + if (columnMapped[columnModelIndex]) + throw new DuplicateColumnException(columnModel.Name, model.Name); + columnMapped[columnModelIndex] = true; + columnMapping[colIndex] = columnModel; + } } } } @@ -408,20 +262,21 @@ protected virtual IList OnReadCSv(Stream stream, ISheetModel model) throw new ColumnMissingException(model.Columns[i].Name, model.Name); } - while(!parser.EndOfData) { + while (!parser.EndOfData) { var range = parser.ReadFields(); - var obj = OnReadCSVRow(range, model, columnMapping); + if (range.Length != columnMapping.Length) { + Array.Resize(ref range, columnMapping.Length); + } + var obj = OnReadCSVRow(range, model, columnMapping, formatProvider); if (obj != null) data.Add(obj); ++currentRow; } - + return data; - } } - /// /// Reads a worksheet and returns a set of of the entries. ///

@@ -479,7 +334,8 @@ protected virtual IList OnReadSheet(ExcelWorksheet worksheet, ISheetModel model) return data; } - protected virtual object OnReadCSVRow(string[] range, ISheetModel model, IColumnModel[] columnMapping) + + protected virtual object OnReadCSVRow(string[] range, ISheetModel model, IColumnModel[] columnMapping, IFormatProvider formatProvider) { if (range == null) throw new ArgumentNullException(nameof(range)); @@ -488,7 +344,6 @@ protected virtual object OnReadCSVRow(string[] range, ISheetModel model, IColumn if (columnMapping == null) throw new ArgumentNullException(nameof(columnMapping)); var firstCol = 0; - var row = 0; var columns = range.Length; //if (range.Rows != 1) // throw new ArgumentOutOfRangeException(nameof(range), "Range must represent a single row of data"); @@ -510,7 +365,7 @@ protected virtual object OnReadCSVRow(string[] range, ISheetModel model, IColumn //if (columnModel.ReadSerializer != null) { // value = columnModel.ReadSerializer(cell); //} else { - value = DefaultCsvReadSerializer(cell, cell, columnModel.Type); + value = DefaultCsvReadSerializer(cell, cell, columnModel.Type, formatProvider); //} } catch (Exception e) { throw new ParseDataException(cell, columnModel.Name, model.Name, e); @@ -612,13 +467,14 @@ protected virtual ExcelRange DefaultReadRangeLocator(ExcelWorksheet worksheet) return null; // no cells return worksheet.Cells[dimension.Start.Row, dimension.Start.Column, dimension.End.Row, dimension.End.Column]; } - protected virtual object DefaultCsvReadSerializer(object value, string text, Type dataType) + + protected virtual object DefaultCsvReadSerializer(object value, string text, Type dataType, IFormatProvider formatProvider) { if (value == null) { return null; } if (dataType.IsGenericType && dataType.GetGenericTypeDefinition() == typeof(Nullable<>)) { - return DefaultCsvReadSerializer(value, text, Nullable.GetUnderlyingType(dataType)); + return DefaultCsvReadSerializer(value, text, Nullable.GetUnderlyingType(dataType), formatProvider); } if (value.GetType() == dataType) return value; @@ -626,17 +482,17 @@ protected virtual object DefaultCsvReadSerializer(object value, string text, Typ return text; if (dataType == typeof(DateTime)) { if (value is string str) - return DateTime.Parse(str); - return DateTime.FromOADate((double)DefaultCsvReadSerializer(value, text, typeof(double))); + return DateTime.Parse(str, formatProvider, DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal); + return DateTime.FromOADate((double)DefaultCsvReadSerializer(value, text, typeof(double), formatProvider)); } if (dataType == typeof(TimeSpan)) { if (value is DateTime dt) return dt.TimeOfDay; if (value is string str) try { - return TimeSpan.Parse(str); + return TimeSpan.Parse(str, formatProvider); } catch (FormatException) { - return DateTime.Parse(str).TimeOfDay; + return DateTime.Parse(str, formatProvider, DateTimeStyles.AllowWhiteSpaces | DateTimeStyles.AssumeLocal).TimeOfDay; } } if (dataType == typeof(DateTimeOffset)) { @@ -654,65 +510,46 @@ protected virtual object DefaultCsvReadSerializer(object value, string text, Typ case "y": case "1": case "yes": + case "true": return true; case "n": case "0": case "no": + case "false": return false; } } } - if(dataType.ToString() == "NullableIntColumn") { - - } - if (dataType == typeof(int?)) { - if (value is string str) { - var success = int.TryParse(str, out int result); - if (success) - return result; - return null; - } - } if (dataType == typeof(int)) { if (value is string str) { - var success = int.TryParse(str, out int result); + var success = int.TryParse(str, NumberStyles.Any, formatProvider, out int result); if (success) return result; - return Convert.ToInt32(Math.Floor(double.Parse(str))); + return Convert.ToInt32(Math.Floor(double.Parse(str, NumberStyles.Any, formatProvider))); } } - //nullable int tye check - - //if (dataType = typeof(nullableInt) if (dataType == typeof(double)) { if (value is string str) { - return double.Parse(str); + return double.Parse(str, NumberStyles.Any, formatProvider); } } if (dataType == typeof(decimal)) { if (value is string str) { - return decimal.Parse(str); + return decimal.Parse(str, NumberStyles.Any, formatProvider); } } if (dataType == typeof(float)) { if (value is string str) { - return float.Parse(str); + return float.Parse(str, NumberStyles.Any, formatProvider); } } - - //try { - return Convert.ChangeType(value, dataType); - //} catch { - // return Convert.ChangeType(Math.Floor(Convert.ToDouble(value)), dataType); - - //} } /// diff --git a/src/Shane32.ExcelLinq/Models/ISheetModel.cs b/src/Shane32.ExcelLinq/Models/ISheetModel.cs index 064fb09..182c8ea 100644 --- a/src/Shane32.ExcelLinq/Models/ISheetModel.cs +++ b/src/Shane32.ExcelLinq/Models/ISheetModel.cs @@ -11,7 +11,6 @@ public interface ISheetModel IReadOnlyList AlternateNames { get; } IColumnModelLookup Columns { get; } Func ReadRangeLocator { get; } - Func CsvReadRangeLocator { get; } Func WriteRangeLocator { get; } Action WritePolisher { get; } bool Optional { get; }