Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README-V2.md
Original file line number Diff line number Diff line change
Expand Up @@ -1411,7 +1411,7 @@ var data = new TestEntity
Points = 123
};

var termplater = MiniExcel.Templaters.GetMappingExporter(registry);
var termplater = MiniExcel.Templaters.GetMappingTemplater(registry);
await termplater.ApplyTemplateAsync(outputPath, templatePath, new[] { data });
```

Expand Down
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,6 @@ If you do, make sure to also check out the [new docs](README-V2.md) and the [upg

- [Excel Column Name/Index/Ignore Attribute](#getstart4)

- [Fluent Cell Mapping](#getstart4.5)

- [Examples](#getstart5)


Expand Down
Binary file added samples/xlsx/TestIssue409.xlsx
Binary file not shown.
Binary file added samples/xlsx/TestIssue881.xlsx
Binary file not shown.
32 changes: 27 additions & 5 deletions src/MiniExcel.Core/Reflection/MiniExcelMapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,17 @@ public static partial class MiniExcelMapper
try
{
object? newValue = null;

if (pInfo.Nullable && string.IsNullOrWhiteSpace(itemValue?.ToString()))
{
// value is null, no transformation required
}

else if (pInfo.ExcludeNullableType == typeof(Guid))
{
newValue = Guid.Parse(itemValue?.ToString() ?? Guid.Empty.ToString());
}

else if (pInfo.ExcludeNullableType == typeof(DateTimeOffset))
{
var vs = itemValue?.ToString();
Expand All @@ -110,6 +114,7 @@ public static partial class MiniExcelMapper
throw new InvalidCastException($"{vs} cannot be cast to DateTime");
}
}

else if (pInfo.ExcludeNullableType == typeof(DateTime))
{
// fix issue 257 https://github.com/mini-software/MiniExcel/issues/257
Expand Down Expand Up @@ -141,7 +146,8 @@ public static partial class MiniExcelMapper
else
throw new InvalidCastException($"{vs} cannot be cast to DateTime");
}
#if NET6_0_OR_GREATER

#if NET6_0_OR_GREATER
else if (pInfo.ExcludeNullableType == typeof(DateOnly))
{
if (itemValue is DateOnly)
Expand Down Expand Up @@ -178,7 +184,8 @@ public static partial class MiniExcelMapper
else
throw new InvalidCastException($"{vs} cannot be cast to DateOnly");
}
#endif
#endif

else if (pInfo.ExcludeNullableType == typeof(TimeSpan))
{
if (itemValue is TimeSpan)
Expand All @@ -205,11 +212,22 @@ public static partial class MiniExcelMapper
else
throw new InvalidCastException($"{vs} cannot be cast to TimeSpan");
}
else if (pInfo.ExcludeNullableType == typeof(double)) // && (!Regex.IsMatch(itemValue.ToString(), @"^-?\d+(\.\d+)?([eE][-+]?\d+)?$") || itemValue.ToString().Trim().Equals("NaN")))

else if (pInfo.ExcludeNullableType == typeof(double))
{
var invariantString = Convert.ToString(itemValue, CultureInfo.InvariantCulture);
newValue = double.TryParse(invariantString, NumberStyles.Any, CultureInfo.InvariantCulture, out var value) ? value : double.NaN;
if (double.TryParse(Convert.ToString(itemValue, config.Culture), NumberStyles.Any, config.Culture, out var doubleValue))
{
newValue = doubleValue;
}
else
{
var invariantString = Convert.ToString(itemValue, CultureInfo.InvariantCulture);
newValue = double.TryParse(invariantString, NumberStyles.Any, CultureInfo.InvariantCulture, out var value)
? value
: throw new InvalidCastException();
}
}

else if (pInfo.ExcludeNullableType == typeof(bool))
{
var vs = itemValue?.ToString();
Expand All @@ -220,23 +238,27 @@ public static partial class MiniExcelMapper
_ => bool.TryParse(vs, out var parsed) ? parsed : null
};
}

else if (pInfo.Property.Info.PropertyType == typeof(string))
{
newValue = XmlHelper.DecodeString(itemValue?.ToString());
}

else if (pInfo.ExcludeNullableType.IsEnum)
{
var fieldInfo = pInfo.ExcludeNullableType.GetFields().FirstOrDefault(e => e.GetCustomAttribute<DescriptionAttribute>(false)?.Description == itemValue?.ToString());
var value = fieldInfo?.Name ?? itemValue?.ToString() ?? "";
newValue = Enum.Parse(pInfo.ExcludeNullableType, value, true);
}

else if (pInfo.ExcludeNullableType == typeof(Uri))
{
var rawValue = itemValue?.ToString();
if (!Uri.TryCreate(rawValue, UriKind.RelativeOrAbsolute, out var uri))
throw new InvalidCastException($"Value \"{rawValue}\" cannot be converted to Uri");
newValue = uri;
}

else
{
// Use pInfo.ExcludeNullableType to resolve : https://github.com/mini-software/MiniExcel/issues/138
Expand Down
21 changes: 12 additions & 9 deletions tests/MiniExcel.Core.Tests/MiniExcelIssueAsyncTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1326,12 +1326,13 @@ public async Task Issue153()
/// https://github.com/mini-software/MiniExcel/issues/137
/// </summary>
[Fact]
public async Task Issue137()
public void Issue137()
{
var path = "../../../../../samples/xlsx/TestIssue137.xlsx";

const string path = "../../../../../samples/xlsx/TestIssue137.xlsx";
var config = new OpenXmlConfiguration { Culture = new CultureInfo("it")};

{
var q = _excelImporter.QueryAsync(path).ToBlockingEnumerable();
var q = _excelImporter.QueryAsync(path, configuration: config).ToBlockingEnumerable();
var rows = q.ToList();
var first = rows[0] as IDictionary<string, object>; // https://user-images.githubusercontent.com/12729184/113266322-ba06e400-9307-11eb-9521-d36abfda75cc.png
Assert.Equal(["A", "B", "C", "D", "E", "F", "G", "H"], first?.Keys.ToArray());
Expand Down Expand Up @@ -1367,7 +1368,7 @@ public async Task Issue137()

// dynamic query with head
{
var q = _excelImporter.QueryAsync(path, true).ToBlockingEnumerable();
var q = _excelImporter.QueryAsync(path, true, configuration: config).ToBlockingEnumerable();
var rows = q.ToList();
var first = rows[0] as IDictionary<string, object>; // https://user-images.githubusercontent.com/12729184/113266322-ba06e400-9307-11eb-9521-d36abfda75cc.png
Assert.Equal(["比例", "商品", "滿倉口數", "0", "1為港幣 0為台幣"], first?.Keys.ToArray());
Expand All @@ -1389,7 +1390,7 @@ public async Task Issue137()
}

{
var q = _excelImporter.QueryAsync<Issue137ExcelRow>(path).ToBlockingEnumerable();
var q = _excelImporter.QueryAsync<Issue137ExcelRow>(path, configuration: config).ToBlockingEnumerable();
var rows = q.ToList();
Assert.Equal(10, rows.Count);

Expand Down Expand Up @@ -1419,11 +1420,13 @@ private class Issue137ExcelRow
/// https://github.com/mini-software/MiniExcel/issues/138
/// </summary>
[Fact]
public async Task Issue138()
public void Issue138()
{
const string path = "../../../../../samples/xlsx/TestIssue138.xlsx";
var config = new OpenXmlConfiguration { Culture = new CultureInfo("it") };

{
var q = _excelImporter.QueryAsync(path, true).ToBlockingEnumerable();
var q = _excelImporter.QueryAsync(path, true, configuration: config).ToBlockingEnumerable();
var rows = q.ToList();
Assert.Equal(6, rows.Count);

Expand All @@ -1449,7 +1452,7 @@ public async Task Issue138()
}
{

var q = _excelImporter.QueryAsync<Issue138ExcelRow>(path).ToBlockingEnumerable();
var q = _excelImporter.QueryAsync<Issue138ExcelRow>(path, configuration: config).ToBlockingEnumerable();
var rows = q.ToList();
Assert.Equal(6, rows.Count);
Assert.Equal(new DateTime(2021, 3, 1), rows[0].Date);
Expand Down
47 changes: 42 additions & 5 deletions tests/MiniExcel.Core.Tests/MiniExcelIssueTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2527,9 +2527,10 @@ public void Issue153()
public void Issue137()
{
const string path = "../../../../../samples/xlsx/TestIssue137.xlsx";
var config = new OpenXmlConfiguration { Culture = new CultureInfo("it") };

{
var rows = _excelImporter.Query(path).ToList();
var rows = _excelImporter.Query(path, configuration: config).ToList();
var first = rows[0] as IDictionary<string, object>; // https://user-images.githubusercontent.com/12729184/113266322-ba06e400-9307-11eb-9521-d36abfda75cc.png
Assert.Equal(["A", "B", "C", "D", "E", "F", "G", "H"], first?.Keys.ToArray());
Assert.Equal(11, rows.Count);
Expand Down Expand Up @@ -2563,7 +2564,7 @@ public void Issue137()

// dynamic query with head
{
var rows = _excelImporter.Query(path, true).ToList();
var rows = _excelImporter.Query(path, true, configuration: config).ToList();
var first = rows[0] as IDictionary<string, object>; //![image](https://user-images.githubusercontent.com/12729184/113266322-ba06e400-9307-11eb-9521-d36abfda75cc.png)
Assert.Equal(["比例", "商品", "滿倉口數", "0", "1為港幣 0為台幣"], first?.Keys.ToArray());
Assert.Equal(10, rows.Count);
Expand All @@ -2583,7 +2584,7 @@ public void Issue137()
}

{
var rows = _excelImporter.Query<Issue137ExcelRow>(path).ToList();
var rows = _excelImporter.Query<Issue137ExcelRow>(path, configuration: config).ToList();
Assert.Equal(10, rows.Count);
{
var row = rows[0];
Expand Down Expand Up @@ -2614,8 +2615,11 @@ private class Issue137ExcelRow
public void Issue138()
{
const string path = "../../../../../samples/xlsx/TestIssue138.xlsx";
var config = new OpenXmlConfiguration { Culture = new CultureInfo("zh") };
config.Culture.NumberFormat.NumberDecimalSeparator = ",";

{
var rows = _excelImporter.Query(path, true).ToList();
var rows = _excelImporter.Query(path, true, configuration: config).ToList();
Assert.Equal(6, rows.Count);

foreach (var index in new[] { 0, 2, 5 })
Expand All @@ -2640,7 +2644,7 @@ public void Issue138()
}
{

var rows = _excelImporter.Query<Issue138ExcelRow>(path).ToList();
var rows = _excelImporter.Query<Issue138ExcelRow>(path, configuration: config).ToList();
Assert.Equal(6, rows.Count);
Assert.Equal(new DateTime(2021, 3, 1), rows[0].Date);

Expand Down Expand Up @@ -2723,6 +2727,30 @@ public void IssueI50VD5()
}
}

private class Issues409_881
{
public string Units { get; set; }
public double Quantity { get; set; }
}

[Fact]
public void TestIssue409()
{
var path = PathHelper.GetFile("xlsx/TestIssue409.xlsx");
var config = new OpenXmlConfiguration { Culture = new CultureInfo("ru") };
config.Culture.NumberFormat.NumberDecimalSeparator = ",";

var query = _excelImporter.Query<Issues409_881>(path, configuration: config).ToList();

Assert.Equal(0.002886, query[0].Quantity);
Assert.Equal(4.1E-05, query[1].Quantity);
Assert.Equal(0.02586, query[2].Quantity);
Assert.Equal(0.000217, query[3].Quantity);
Assert.Equal(17.4024812, query[4].Quantity);
Assert.Equal(1.43E-06, query[5].Quantity);
Assert.Equal(9.9E-06, query[6].Quantity);
}

private class Issue422Enumerable(IEnumerable inner) : IEnumerable
{
private readonly IEnumerable _inner = inner;
Expand Down Expand Up @@ -3728,4 +3756,13 @@ public void TestIssue880_ShouldThrowNotSerializableException()
_excelExporter.Export(ms, toExport);
});
}

[Fact]
public void TestIssue881()
{
Assert.Throws<MiniExcelInvalidCastException>(() =>
{
_ = _excelImporter.Query<Issues409_881>(PathHelper.GetFile("xlsx/TestIssue881.xlsx")).ToList();
});
}
}
Loading
Loading