mirror of
https://gitee.com/dotnetchina/MiniExcel.git
synced 2024-12-02 03:47:41 +08:00
Add supprt for if/elseif/else statements inside cell (#487)
* add support for grouped cells * fix for rows after endgroup * minor fix for text after grouping * fix unit tests * fix unit tests and docs * minor fix * Add support to vertical merge cells * minor fixes in merge cells * minor fix * fix complex scenario * finalize changes * Add support for if/elseif/else statements
This commit is contained in:
parent
1bd853affe
commit
0559847ecc
31
README.md
31
README.md
@ -808,8 +808,35 @@ After
|
||||
|
||||
![without_group_after](https://user-images.githubusercontent.com/38832863/218646974-4a3c0e07-7c66-4088-ad07-b4ad3695b7e1.PNG)
|
||||
|
||||
#### 8. If/ElseIf/Else Statements inside cell
|
||||
|
||||
#### 8. DataTable as parameter
|
||||
Rules:
|
||||
1. Supports DateTime, Double, Int with ==, !=, >, >=, <, <= operators.
|
||||
2. Supports String with ==, != operators.
|
||||
3. Each statement should be new line.
|
||||
4. Single space should be added before and after operators.
|
||||
5. There shouldn't be new line inside of statements.
|
||||
6. Cell should be in exact format as below.
|
||||
|
||||
```csharp
|
||||
@if(name == Jack)
|
||||
{{employees.name}}
|
||||
@elseif(name == Neo)
|
||||
Test {{employees.name}}
|
||||
@else
|
||||
{{employees.department}}
|
||||
@endif
|
||||
```
|
||||
|
||||
Before
|
||||
|
||||
![if_before](https://user-images.githubusercontent.com/38832863/235360606-ca654769-ff55-4f5b-98d2-d2ec0edb8173.PNG)
|
||||
|
||||
After
|
||||
|
||||
![if_after](https://user-images.githubusercontent.com/38832863/235360609-869bb960-d63d-45ae-8d64-9e8b0d0ab658.PNG)
|
||||
|
||||
#### 9. DataTable as parameter
|
||||
|
||||
```csharp
|
||||
var managers = new DataTable();
|
||||
@ -828,7 +855,7 @@ MiniExcel.SaveAsByTemplate(path, templatePath, value);
|
||||
```
|
||||
|
||||
|
||||
#### 9. Other
|
||||
#### 10. Other
|
||||
|
||||
##### 1. Checking template parameter key
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
---
|
||||
|
||||
### 1.30.3
|
||||
- [New] support if/else if/else statements inside cell (via @eynarhaji)
|
||||
|
||||
### 1.30.2
|
||||
- [New] support grouped rows (via @eynarhaji)
|
||||
|
BIN
samples/xlsx/TestTemplateBasicIEmumerableFillConditional.xlsx
Normal file
BIN
samples/xlsx/TestTemplateBasicIEmumerableFillConditional.xlsx
Normal file
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
|
||||
<Version>1.30.2</Version>
|
||||
<Version>1.30.3</Version>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<AssemblyName>MiniExcel</AssemblyName>
|
||||
|
@ -351,9 +351,51 @@ namespace MiniExcelLibs.OpenXml
|
||||
.Replace($"{{{{$rowindex}}}}", newRowIndex.ToString())
|
||||
.AppendFormat(@"</{0}>", row.Name);
|
||||
|
||||
var rowXmlString = rowXml.ToString();
|
||||
var extract = "";
|
||||
var newCellValue = "";
|
||||
|
||||
var ifIndex = rowXmlString.IndexOf("@if", StringComparison.Ordinal);
|
||||
var endifIndex = rowXmlString.IndexOf("@endif", StringComparison.Ordinal);
|
||||
|
||||
if (ifIndex != -1 && endifIndex != -1)
|
||||
{
|
||||
extract = rowXmlString.Substring(ifIndex, endifIndex - ifIndex + 6);
|
||||
}
|
||||
|
||||
var lines = extract.Split('\n');
|
||||
|
||||
if (rowInfo.IsDictionary)
|
||||
{
|
||||
var dic = item as IDictionary<string, object>;
|
||||
|
||||
for(var i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if(lines[i].Contains("@if") || lines[i].Contains("@elseif"))
|
||||
{
|
||||
var newLines = lines[i].Replace("@elseif(", "").Replace("@if(", "").Replace(")", "").Split(' ');
|
||||
|
||||
var value = dic[newLines[0]];
|
||||
var evaluation = EvaluateStatement(value, newLines[1], newLines[2]);
|
||||
|
||||
if (evaluation)
|
||||
{
|
||||
newCellValue += lines[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(lines[i].Contains("@else"))
|
||||
{
|
||||
newCellValue += lines[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(newCellValue))
|
||||
{
|
||||
rowXml.Replace(extract, newCellValue);
|
||||
}
|
||||
|
||||
foreach (var propInfo in rowInfo.PropsMap)
|
||||
{
|
||||
var key = $"{{{{{rowInfo.IEnumerablePropName}.{propInfo.Key}}}}}";
|
||||
@ -396,6 +438,34 @@ namespace MiniExcelLibs.OpenXml
|
||||
else if (rowInfo.IsDataTable)
|
||||
{
|
||||
var datarow = item as DataRow;
|
||||
|
||||
for(var i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if(lines[i].Contains("@if") || lines[i].Contains("@elseif"))
|
||||
{
|
||||
var newLines = lines[i].Replace("@elseif(", "").Replace("@if(", "").Replace(")", "").Split(' ');
|
||||
|
||||
var value = datarow[newLines[0]];
|
||||
var evaluation = EvaluateStatement(value, newLines[1], newLines[2]);
|
||||
|
||||
if (evaluation)
|
||||
{
|
||||
newCellValue += lines[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(lines[i].Contains("@else"))
|
||||
{
|
||||
newCellValue += lines[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(newCellValue))
|
||||
{
|
||||
rowXml.Replace(extract, newCellValue);
|
||||
}
|
||||
|
||||
foreach (var propInfo in rowInfo.PropsMap)
|
||||
{
|
||||
var key = $"{{{{{rowInfo.IEnumerablePropName}.{propInfo.Key}}}}}";
|
||||
@ -437,6 +507,33 @@ namespace MiniExcelLibs.OpenXml
|
||||
}
|
||||
else
|
||||
{
|
||||
for(var i = 0; i < lines.Length; i++)
|
||||
{
|
||||
if(lines[i].Contains("@if") || lines[i].Contains("@elseif"))
|
||||
{
|
||||
var newLines = lines[i].Replace("@elseif(", "").Replace("@if(", "").Replace(")", "").Split(' ');
|
||||
|
||||
var value = rowInfo.PropsMap[newLines[0]].PropertyInfo.GetValue(item);
|
||||
var evaluation = EvaluateStatement(value, newLines[1], newLines[2]);
|
||||
|
||||
if (evaluation)
|
||||
{
|
||||
newCellValue += lines[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(lines[i].Contains("@else"))
|
||||
{
|
||||
newCellValue += lines[i + 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(newCellValue))
|
||||
{
|
||||
rowXml.Replace(extract, newCellValue);
|
||||
}
|
||||
|
||||
foreach (var propInfo in rowInfo.PropsMap)
|
||||
{
|
||||
var prop = propInfo.Value.PropertyInfo;
|
||||
@ -900,5 +997,100 @@ namespace MiniExcelLibs.OpenXml
|
||||
dimension.SetAttribute("ref", $"A1:{letter}{digit + maxRowIndexDiff}");
|
||||
}
|
||||
}
|
||||
|
||||
private static bool EvaluateStatement(object tagValue, string comparisonOperator, string value)
|
||||
{
|
||||
var checkStatement = false;
|
||||
|
||||
switch (tagValue)
|
||||
{
|
||||
case double dtg when double.TryParse(value, out var doubleNumber):
|
||||
switch (comparisonOperator)
|
||||
{
|
||||
case "==":
|
||||
checkStatement = dtg.Equals(doubleNumber);
|
||||
break;
|
||||
case "!=":
|
||||
checkStatement = !dtg.Equals(doubleNumber);
|
||||
break;
|
||||
case ">":
|
||||
checkStatement = dtg > doubleNumber;
|
||||
break;
|
||||
case "<":
|
||||
checkStatement = dtg < doubleNumber;
|
||||
break;
|
||||
case ">=":
|
||||
checkStatement = dtg >= doubleNumber;
|
||||
break;
|
||||
case "<=":
|
||||
checkStatement = dtg <= doubleNumber;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case int itg when int.TryParse(value, out var intNumber):
|
||||
switch (comparisonOperator)
|
||||
{
|
||||
case "==":
|
||||
checkStatement = itg.Equals(intNumber);
|
||||
break;
|
||||
case "!=":
|
||||
checkStatement = !itg.Equals(intNumber);
|
||||
break;
|
||||
case ">":
|
||||
checkStatement = itg > intNumber;
|
||||
break;
|
||||
case "<":
|
||||
checkStatement = itg < intNumber;
|
||||
break;
|
||||
case ">=":
|
||||
checkStatement = itg >= intNumber;
|
||||
break;
|
||||
case "<=":
|
||||
checkStatement = itg <= intNumber;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case DateTime dttg when DateTime.TryParse(value, out var date):
|
||||
switch (comparisonOperator)
|
||||
{
|
||||
case "==":
|
||||
checkStatement = dttg.Equals(date);
|
||||
break;
|
||||
case "!=":
|
||||
checkStatement = !dttg.Equals(date);
|
||||
break;
|
||||
case ">":
|
||||
checkStatement = dttg > date;
|
||||
break;
|
||||
case "<":
|
||||
checkStatement = dttg < date;
|
||||
break;
|
||||
case ">=":
|
||||
checkStatement = dttg >= date;
|
||||
break;
|
||||
case "<=":
|
||||
checkStatement = dttg <= date;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
case string stg:
|
||||
switch (comparisonOperator)
|
||||
{
|
||||
case "==":
|
||||
checkStatement = stg == value;
|
||||
break;
|
||||
case "!=":
|
||||
checkStatement = stg != value;
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return checkStatement;
|
||||
}
|
||||
}
|
||||
}
|
@ -693,6 +693,80 @@ namespace MiniExcelTests
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TestIEnumerableConditional()
|
||||
{
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
|
||||
var templatePath = @"../../../../../samples/xlsx/TestTemplateBasicIEmumerableFillConditional.xlsx";
|
||||
|
||||
//1. By POCO
|
||||
var value = new
|
||||
{
|
||||
employees = new[] {
|
||||
new {name="Jack",department="HR"},
|
||||
new {name="Lisa",department="HR"},
|
||||
new {name="John",department="HR"},
|
||||
new {name="Mike",department="IT"},
|
||||
new {name="Neo",department="IT"},
|
||||
new {name="Loan",department="IT"}
|
||||
}
|
||||
};
|
||||
await MiniExcel.SaveAsByTemplateAsync(path, templatePath, value);
|
||||
|
||||
var demension = Helpers.GetFirstSheetDimensionRefValue(path);
|
||||
Assert.Equal("A1:B18", demension);
|
||||
}
|
||||
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
|
||||
var templatePath = @"../../../../../samples/xlsx/TestTemplateBasicIEmumerableFillConditional.xlsx";
|
||||
|
||||
//2. By Dictionary
|
||||
var value = new Dictionary<string, object>()
|
||||
{
|
||||
["employees"] = new[] {
|
||||
new {name="Jack",department="HR"},
|
||||
new {name="Jack",department="HR"},
|
||||
new {name="John",department="HR"},
|
||||
new {name="John",department="IT"},
|
||||
new {name="Neo",department="IT"},
|
||||
new {name="Loan",department="IT"}
|
||||
}
|
||||
};
|
||||
await MiniExcel.SaveAsByTemplateAsync(path, templatePath, value);
|
||||
|
||||
var demension = Helpers.GetFirstSheetDimensionRefValue(path);
|
||||
Assert.Equal("A1:B18", demension);
|
||||
}
|
||||
|
||||
{
|
||||
var path = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
|
||||
var templatePath = @"../../../../../samples/xlsx/TestTemplateBasicIEmumerableFillConditional.xlsx";
|
||||
|
||||
//3. By DataTable
|
||||
var dt = new DataTable();
|
||||
{
|
||||
dt.Columns.Add("name");
|
||||
dt.Columns.Add("department");
|
||||
dt.Rows.Add("Jack", "HR");
|
||||
dt.Rows.Add("Lisa", "HR");
|
||||
dt.Rows.Add("John", "HR");
|
||||
dt.Rows.Add("Mike", "IT");
|
||||
dt.Rows.Add("Neo", "IT");
|
||||
dt.Rows.Add("Loan", "IT");
|
||||
}
|
||||
var value = new Dictionary<string, object>()
|
||||
{
|
||||
["employees"] = dt
|
||||
};
|
||||
await MiniExcel.SaveAsByTemplateAsync(path, templatePath, value);
|
||||
|
||||
var demension = Helpers.GetFirstSheetDimensionRefValue(path);
|
||||
Assert.Equal("A1:B18", demension);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task TemplateTest()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user