Skip to content

Commit

Permalink
Add support for merge limit (#521)
Browse files Browse the repository at this point in the history
* 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

* add merge tag

* add merge-tag

* update readme

* minor fix

* minor fix

* minor fix

* Update MiniExcelLibs.csproj

* Add support for merge limit

* update test cases

* rollback

---------

Co-authored-by: Wei Lin <shps951002@gmail.com>
  • Loading branch information
eynarhaji and shps951023 authored Aug 9, 2023
1 parent 9811ef9 commit ee2b198
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 14 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@ Since 1.22.0, when value type is `byte[]` then system will save file path at cel
#### 12. Merge same cells vertically

This functionality is only supported in `xlsx` format and merges cells vertically between @merge and @endmerge tags.
You can use @mergelimit to limit boundaries of merging cells vertically.

```csharp
var mergedFilePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");
Expand All @@ -548,10 +549,18 @@ memoryStream.MergeSameCells(path);

File content before and after merge:

Without merge limit:

<img width="318" alt="Screenshot 2023-08-07 at 11 59 24" src="https://github.com/mini-software/MiniExcel/assets/38832863/49cc96b9-6c35-4bf3-8d43-a9752a15b22e">

<img width="318" alt="Screenshot 2023-08-07 at 11 59 57" src="https://github.com/mini-software/MiniExcel/assets/38832863/3fbd529b-3ae6-4bbe-b4d8-2793a5a58010">

With merge limit:

<img width="346" alt="Screenshot 2023-08-08 at 18 21 00" src="https://github.com/mini-software/MiniExcel/assets/38832863/04049d28-84d5-4c2a-bcff-5847547df5e1">

<img width="346" alt="Screenshot 2023-08-08 at 18 21 40" src="https://github.com/mini-software/MiniExcel/assets/38832863/f5cf8957-b0b0-4831-b8fc-8556299235c2">

#### 13. Skip null values

New explicit option to write empty cells for null values:
Expand Down
5 changes: 3 additions & 2 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@

---

### 1.31.1
- [New] support automatic merge for same vertical cells between @merge and @endmerge tags (via @eynarhaji)
### 1.31.2
- [New] Support automatic merge for same vertical cells between @merge and @endmerge tags (via @eynarhaji)
- [New] Limit merge tagged columns with @mergelimit column. First merge limited column and then merge other columns accordingly. (via @eynarhaji)

### 1.31.1
- [OPT] Support property cache #23 (via @RRQM_Home)
Expand Down
Binary file added samples/xlsx/TestMergeWithLimitTag.xlsx
Binary file not shown.
2 changes: 1 addition & 1 deletion src/MiniExcel/MiniExcelLibs.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netstandard2.0</TargetFrameworks>
<Version>1.31.1</Version>
<Version>1.31.2</Version>
</PropertyGroup>
<PropertyGroup>
<AssemblyName>MiniExcel</AssemblyName>
Expand Down
31 changes: 21 additions & 10 deletions src/MiniExcel/OpenXml/ExcelOpenXmlTemplate.Impl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,11 @@ private void WriteSheetXml(Stream stream, XmlDocument doc, XmlNode sheetData, bo
ColIndex = StringHelper.GetLetter(att),
RowIndex = StringHelper.GetNumber(att)
};
}).ToList();
}).OrderBy(x=>x.RowIndex).ToList();

var mergeColumns = columns.Where(s => s.InnerText.Contains("@merge")).OrderBy(s => s.RowIndex)
.ToList();
var endMergeColumns = columns.Where(s => s.InnerText.Contains("@endmerge")).OrderBy(s => s.RowIndex)
.ToList();
var mergeColumns = columns.Where(s => s.InnerText.Contains("@merge")).ToList();
var endMergeColumns = columns.Where(s => s.InnerText.Contains("@endmerge")).ToList();
var mergeLimitColumn = mergeColumns.FirstOrDefault(x=>x.InnerText.Contains("@mergelimit"));

foreach (var mergeColumn in mergeColumns)
{
Expand All @@ -227,8 +226,7 @@ private void WriteSheetXml(Stream stream, XmlDocument doc, XmlNode sheetData, bo
x.ColIndex == taggedColumn.Key.ColIndex && x.RowIndex > taggedColumn.Key.RowIndex &&
x.RowIndex < taggedColumn.Value.RowIndex));
}



Dictionary<int, MergeCellIndex>
lastMergeCellIndexes = new Dictionary<int, MergeCellIndex>();

Expand All @@ -240,16 +238,29 @@ private void WriteSheetXml(Stream stream, XmlDocument doc, XmlNode sheetData, bo

foreach (var childNode in childNodes)
{
var childNodeAtt = StringHelper.GetLetter(childNode.GetAttribute("r"));
var att = childNode.GetAttribute("r");
var childNodeLetter = StringHelper.GetLetter(att);
var childNodeNumber = StringHelper.GetNumber(att);

if(!string.IsNullOrEmpty(childNode.InnerText))
{
var xmlNodes = calculatedColumns
.Where(j => j.InnerText == childNode.InnerText && j.ColIndex == childNodeAtt)
.Where(j => j.InnerText == childNode.InnerText && j.ColIndex == childNodeLetter)
.OrderBy(s => s.RowIndex).ToList();

if (xmlNodes.Count > 1)
{
if (mergeLimitColumn != null)
{
var limitedNode = calculatedColumns.First(j =>
j.ColIndex == mergeLimitColumn.ColIndex && j.RowIndex == childNodeNumber);

var limitedMaxNode = calculatedColumns.Last(j =>
j.ColIndex == mergeLimitColumn.ColIndex && j.InnerText == limitedNode.InnerText);

xmlNodes = xmlNodes.Where(j => j.RowIndex >= limitedNode.RowIndex && j.RowIndex <= limitedMaxNode.RowIndex).ToList();
}

var firstRow = xmlNodes.FirstOrDefault();
var lastRow = xmlNodes.LastOrDefault(s =>
s.RowIndex <= firstRow?.RowIndex + xmlNodes.Count &&
Expand Down Expand Up @@ -280,7 +291,7 @@ private void WriteSheetXml(Stream stream, XmlDocument doc, XmlNode sheetData, bo
}
}

childNode.SetAttribute("r", $"{childNodeAtt}{{{{$rowindex}}}}"); //TODO:
childNode.SetAttribute("r", $"{childNodeLetter}{{{{$rowindex}}}}"); //TODO:
}
}
}
Expand Down
17 changes: 17 additions & 0 deletions tests/MiniExcelTests/MiniExcelTemplateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -857,5 +857,22 @@ public void MergeSameCellsWithTagTest()
Assert.Equal("A7:A8", mergedCells[2]);
}
}

[Fact]
public void MergeSameCellsWithLimitTagTest()
{
var mergedFilePath = Path.Combine(Path.GetTempPath(), $"{Guid.NewGuid().ToString()}.xlsx");

var path = @"../../../../../samples/xlsx/TestMergeWithLimitTag.xlsx";

MiniExcel.MergeSameCells(mergedFilePath, path);
{
var mergedCells = Helpers.GetFirstSheetMergedCells(mergedFilePath);

Assert.Equal("A3:A4", mergedCells[0]);
Assert.Equal("C3:C6", mergedCells[1]);
Assert.Equal("A5:A6", mergedCells[2]);
}
}
}
}
2 changes: 1 addition & 1 deletion tests/MiniExcelTests/MiniExcelTests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net5.0</TargetFrameworks>
<TargetFrameworks>net5.0;</TargetFrameworks>

<IsPackable>false</IsPackable>
<AssemblyOriginatorKeyFile>miniexcel.snk</AssemblyOriginatorKeyFile>
Expand Down

0 comments on commit ee2b198

Please sign in to comment.