diff --git a/README.md b/README.md
index 5b6ed4d8..f05055dc 100644
--- a/README.md
+++ b/README.md
@@ -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");
@@ -548,10 +549,18 @@ memoryStream.MergeSameCells(path);
File content before and after merge:
+Without merge limit:
+
+With merge limit:
+
+
+
+
+
#### 13. Skip null values
New explicit option to write empty cells for null values:
diff --git a/docs/README.md b/docs/README.md
index d9af5553..cd36e1cb 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -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)
diff --git a/samples/xlsx/TestMergeWithLimitTag.xlsx b/samples/xlsx/TestMergeWithLimitTag.xlsx
new file mode 100644
index 00000000..855493f2
Binary files /dev/null and b/samples/xlsx/TestMergeWithLimitTag.xlsx differ
diff --git a/src/MiniExcel/MiniExcelLibs.csproj b/src/MiniExcel/MiniExcelLibs.csproj
index 9989f014..4cb83861 100644
--- a/src/MiniExcel/MiniExcelLibs.csproj
+++ b/src/MiniExcel/MiniExcelLibs.csproj
@@ -1,7 +1,7 @@
net45;netstandard2.0
- 1.31.1
+ 1.31.2
MiniExcel
diff --git a/src/MiniExcel/OpenXml/ExcelOpenXmlTemplate.Impl.cs b/src/MiniExcel/OpenXml/ExcelOpenXmlTemplate.Impl.cs
index 462c4483..6d03b610 100644
--- a/src/MiniExcel/OpenXml/ExcelOpenXmlTemplate.Impl.cs
+++ b/src/MiniExcel/OpenXml/ExcelOpenXmlTemplate.Impl.cs
@@ -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)
{
@@ -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
lastMergeCellIndexes = new Dictionary();
@@ -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 &&
@@ -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:
}
}
}
diff --git a/tests/MiniExcelTests/MiniExcelTemplateTests.cs b/tests/MiniExcelTests/MiniExcelTemplateTests.cs
index fb7fef0c..da514193 100644
--- a/tests/MiniExcelTests/MiniExcelTemplateTests.cs
+++ b/tests/MiniExcelTests/MiniExcelTemplateTests.cs
@@ -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]);
+ }
+ }
}
}
diff --git a/tests/MiniExcelTests/MiniExcelTests.csproj b/tests/MiniExcelTests/MiniExcelTests.csproj
index 587cb82d..44d607ab 100644
--- a/tests/MiniExcelTests/MiniExcelTests.csproj
+++ b/tests/MiniExcelTests/MiniExcelTests.csproj
@@ -1,7 +1,7 @@
- net5.0
+ net5.0;
false
miniexcel.snk