Skip to content

Commit 65fd7e8

Browse files
authored
#163 Multiple ranges support for Named Ranges (#164)
* #163 Multiple ranges support for Named Ranges * #163 added test
1 parent cf67e13 commit 65fd7e8

File tree

5 files changed

+59
-44
lines changed

5 files changed

+59
-44
lines changed

ClosedXML.Report/RangeInterpreter.cs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -165,27 +165,32 @@ string EvalString(string str)
165165
}
166166

167167
foreach (var nr in innerRanges)
168+
foreach (var rng in nr.Ranges)
168169
{
169-
if (!(_variables[nr.Name] is IEnumerable datas))
170-
continue;
171-
172-
var items = datas as object[] ?? datas.Cast<object>().ToArray();
173-
var tplt = RangeTemplate.Parse(nr, _errors, _variables);
174-
var nrng = nr.Ranges.First();
175-
using (var buff = tplt.Generate(items))
176170
{
177-
var trgtRng = buff.CopyTo(nrng);
178-
nr.SetRefersTo(trgtRng);
171+
if (!(_variables[nr.Name] is IEnumerable datas))
172+
continue;
179173

180-
tplt.RangeTagsApply(trgtRng, items);
181-
}
174+
var items = datas as object[] ?? datas.Cast<object>().ToArray();
175+
var tplt = RangeTemplate.Parse(nr.Name, rng, _errors, _variables);
176+
using (var buff = tplt.Generate(items))
177+
{
178+
var ranges = nr.Ranges;
179+
var trgtRng = buff.CopyTo(rng);
180+
ranges.Remove(rng);
181+
ranges.Add(trgtRng);
182+
nr.SetRefersTo(ranges);
182183

183-
// refresh ranges for pivot tables
184-
foreach (var pt in range.Worksheet.Workbook.Worksheets.SelectMany(sh => sh.PivotTables))
185-
{
186-
if (pt.SourceRange.Intersects(nrng))
184+
tplt.RangeTagsApply(trgtRng, items);
185+
}
186+
187+
// refresh ranges for pivot tables
188+
foreach (var pt in range.Worksheet.Workbook.Worksheets.SelectMany(sh => sh.PivotTables))
187189
{
188-
pt.SourceRange = nrng.Offset(-1, 1, nrng.RowCount() + 1, nrng.ColumnCount() - 1);
190+
if (pt.SourceRange.Intersects(rng))
191+
{
192+
pt.SourceRange = rng.Offset(-1, 1, rng.RowCount() + 1, rng.ColumnCount() - 1);
193+
}
189194
}
190195
}
191196
}

ClosedXML.Report/RangeTemplate.cs

Lines changed: 37 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ public class RangeTemplate
3434
public string Source { get; private set; }
3535
public string Name { get; }
3636

37-
internal RangeTemplate(IXLNamedRange range, TempSheetBuffer buff, TemplateErrors errors, IDictionary<string, object> globalVariables)
37+
internal RangeTemplate(string name, IXLRange range, TempSheetBuffer buff, TemplateErrors errors, IDictionary<string, object> globalVariables)
3838
{
39-
_rowRange = range.Ranges.First();
39+
_rowRange = range;
4040
_cells = new TemplateCells(this);
4141
_tagsEvaluator = new TagsEvaluator();
4242
var wb = _rowRange.Worksheet.Workbook;
@@ -45,40 +45,48 @@ internal RangeTemplate(IXLNamedRange range, TempSheetBuffer buff, TemplateErrors
4545
_globalVariables = globalVariables;
4646
_tags = new TagsList(_errors);
4747
_rangeTags = new TagsList(_errors);
48-
Name = range.Name;
49-
Source = range.Name;
50-
wb.NamedRanges.Add(range.Name + "_tpl", range.Ranges);
48+
Name = name;
49+
Source = name;
50+
var rangeName = name + "_tpl";
51+
if (wb.NamedRanges.TryGetValue(rangeName, out var namedRange))
52+
{
53+
namedRange.Add(range);
54+
}
55+
else
56+
{
57+
wb.NamedRanges.Add(rangeName, range);
58+
}
59+
5160
_evaluator = new FormulaEvaluator();
5261
}
5362

54-
internal RangeTemplate(IXLNamedRange range, TempSheetBuffer buff, int rowCnt, int colCnt, TemplateErrors errors, IDictionary<string, object> globalVariables) : this(range, buff, errors, globalVariables)
63+
internal RangeTemplate(string name, IXLRange range, TempSheetBuffer buff, int rowCnt, int colCnt, TemplateErrors errors, IDictionary<string, object> globalVariables) : this(name, range, buff, errors, globalVariables)
5564
{
5665
_rowCnt = rowCnt;
5766
_colCnt = colCnt;
5867
}
5968

6069

61-
public static RangeTemplate Parse(IXLNamedRange range, TemplateErrors errors, IDictionary<string, object> globalVariables)
70+
public static RangeTemplate Parse(string name, IXLRange range, TemplateErrors errors, IDictionary<string, object> globalVariables)
6271
{
63-
var wb = range.Ranges.First().Worksheet.Workbook;
64-
return Parse(range, new TempSheetBuffer(wb), errors, globalVariables);
72+
var wb = range.Worksheet.Workbook;
73+
return Parse(name, range, new TempSheetBuffer(wb), errors, globalVariables);
6574
}
6675

67-
private static RangeTemplate Parse(IXLNamedRange range, TempSheetBuffer buff, TemplateErrors errors, IDictionary<string, object> globalVariables)
76+
private static RangeTemplate Parse(string name, IXLRange range, TempSheetBuffer buff, TemplateErrors errors, IDictionary<string, object> globalVariables)
6877
{
69-
var prng = range.Ranges.First();
70-
var result = new RangeTemplate(range, buff,
71-
prng.RowCount(), prng.ColumnCount(), errors, globalVariables);
78+
var result = new RangeTemplate(name, range, buff,
79+
range.RowCount(), range.ColumnCount(), errors, globalVariables);
7280

73-
var innerRanges = GetInnerRanges(prng).ToArray();
81+
var innerRanges = GetInnerRanges(range).ToArray();
7482

75-
var sheet = prng.Worksheet;
83+
var sheet = range.Worksheet;
7684

7785
for (int iRow = 1; iRow <= result._rowCnt; iRow++)
7886
{
7987
for (int iColumn = 1; iColumn <= result._colCnt; iColumn++)
8088
{
81-
var xlCell = prng.Cell(iRow, iColumn);
89+
var xlCell = range.Cell(iRow, iColumn);
8290
if (innerRanges.Any(x => x.Ranges.Cells().Contains(xlCell)))
8391
xlCell = null;
8492
result._cells.Add(iRow, iColumn, xlCell);
@@ -87,29 +95,30 @@ private static RangeTemplate Parse(IXLNamedRange range, TempSheetBuffer buff, Te
8795
result._cells.AddNewRow();
8896
}
8997

90-
result._mergedRanges = sheet.MergedRanges.Where(x => prng.Contains(x) && !innerRanges.Any(nr=>nr.Ranges.Any(r=>r.Contains(x)))).ToArray();
98+
result._mergedRanges = sheet.MergedRanges.Where(x => range.Contains(x) && !innerRanges.Any(nr=>nr.Ranges.Any(r=>r.Contains(x)))).ToArray();
9199
sheet.MergedRanges.RemoveAll(result._mergedRanges.Contains);
92100

93-
result.ParseTags(prng);
101+
result.ParseTags(range);
94102

95103
if (result._rowCnt > 1 && !result.IsHorizontal)
96104
{
97105
// Exclude special row
98106
result._rowCnt--;
99107

100-
result._rowRange = prng.Offset(0, 0, result._rowCnt, result._colCnt);
101-
result._optionsRow = prng.LastRow();
108+
result._rowRange = range.Offset(0, 0, result._rowCnt, result._colCnt);
109+
result._optionsRow = range.LastRow();
102110
result._optionsRowIsEmpty = !result._optionsRow.CellsUsed(XLCellsUsedOptions.AllContents | XLCellsUsedOptions.MergedRanges).Any();
103111
}
104112

105-
result._subranges = innerRanges.Select(rng =>
106-
{
107-
var tpl = Parse(rng, buff, errors, globalVariables);
108-
tpl._buff = result._buff;
109-
tpl._isSubrange = true;
110-
tpl._globalVariables = globalVariables;
111-
return tpl;
112-
}).ToArray();
113+
result._subranges = innerRanges.SelectMany(nrng => nrng.Ranges,
114+
(nr, rng) =>
115+
{
116+
var tpl = Parse(nr.Name, rng, buff, errors, globalVariables);
117+
tpl._buff = result._buff;
118+
tpl._isSubrange = true;
119+
tpl._globalVariables = globalVariables;
120+
return tpl;
121+
}).ToArray();
113122

114123
if (result._rangeOption != null)
115124
{

tests/ClosedXML.Report.Tests/GroupTagTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public void EmptyDataSource(string templateFile)
6868
InlineData("GroupTagTests_NestedGroups.xlsx"),
6969
InlineData("GroupTagTests_DisableOutline.xlsx"),
7070
InlineData("GroupTagTests_FormulasInGroupRow.xlsx"),
71+
InlineData("GroupTagTests_MultiRanges.xlsx"),
7172
]
7273
public void Customers(string templateFile)
7374
{
38.5 KB
Binary file not shown.
21.3 KB
Binary file not shown.

0 commit comments

Comments
 (0)