Skip to content

Commit 984081e

Browse files
Added sheet dimensions feature (#774)
* Code cleanup * Added capability for retrieving sheet dimensions data without having to perform a query
1 parent 695c50e commit 984081e

14 files changed

+567
-294
lines changed

samples/xlsx/TestMultiSheet.xlsx

-572 Bytes
Binary file not shown.

samples/xlsx/TestNoDimension.xlsx

15.5 KB
Binary file not shown.
17.8 KB
Binary file not shown.

src/MiniExcel/MiniExcel.cs

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
1-
namespace MiniExcelLibs
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Data;
5+
using System.Dynamic;
6+
using System.IO;
7+
using System.Linq;
8+
using MiniExcelLibs.OpenXml;
9+
using MiniExcelLibs.OpenXml.Models;
10+
using MiniExcelLibs.Picture;
11+
using MiniExcelLibs.Utils;
12+
using MiniExcelLibs.Zip;
13+
14+
namespace MiniExcelLibs
215
{
3-
using MiniExcelLibs.Picture;
4-
using OpenXml;
5-
using System;
6-
using System.Collections;
7-
using System.Collections.Generic;
8-
using System.Data;
9-
using System.Dynamic;
10-
using System.IO;
11-
using System.Linq;
12-
using Utils;
13-
using Zip;
14-
1516
public static partial class MiniExcel
1617
{
1718
public static void AddPicture(string path, params MiniExcelPicture[] images)
1819
{
1920
using (var stream = File.Open(path,FileMode.OpenOrCreate))
2021
MiniExcelPictureImplement.AddPicture(stream, images);
2122
}
23+
2224
public static void AddPicture(Stream excelStream, params MiniExcelPicture[] images)
2325
{
2426
MiniExcelPictureImplement.AddPicture(excelStream, images);
2527
}
28+
2629
public static MiniExcelDataReader GetReader(string path, bool useHeaderRow = false, string sheetName = null, ExcelType excelType = ExcelType.UNKNOWN, string startCell = "A1", IConfiguration configuration = null)
2730
{
2831
var stream = FileHelper.OpenSharedRead(path);
@@ -284,6 +287,28 @@ public static ICollection<string> GetColumns(this Stream stream, bool useHeaderR
284287
{
285288
return (Query(stream, useHeaderRow, sheetName, excelType, startCell, configuration).FirstOrDefault() as IDictionary<string, object>)?.Keys;
286289
}
290+
291+
public static IList<ExcelRange> GetSheetDimensions(string path)
292+
{
293+
using (var stream = FileHelper.OpenSharedRead(path))
294+
return GetSheetDimensions(stream);
295+
}
296+
297+
public static IList<ExcelRange> GetSheetDimensions(this Stream stream)
298+
{
299+
return new ExcelOpenXmlSheetReader(stream, null).GetDimensions();
300+
}
301+
302+
public static IList<ExcelRange> GetSheetsDimensions(string path)
303+
{
304+
using (var stream = FileHelper.OpenSharedRead(path))
305+
return GetSheetsDimensions(stream);
306+
}
307+
308+
public static IList<ExcelRange> GetSheetsDimensions(this Stream stream)
309+
{
310+
return new ExcelOpenXmlSheetReader(stream, null).GetDimensions();
311+
}
287312

288313
public static void ConvertCsvToXlsx(string csv, string xlsx)
289314
{

src/MiniExcel/OpenXml/ExcelOpenXmlSheetReader.cs

Lines changed: 253 additions & 114 deletions
Large diffs are not rendered by default.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
using System;
2+
3+
namespace MiniExcelLibs.OpenXml.Models
4+
{
5+
public class ExcelRangeElement
6+
{
7+
internal ExcelRangeElement(int startIndex, int endIndex)
8+
{
9+
if (startIndex > endIndex)
10+
throw new ArgumentException("StartIndex value cannot be greater than EndIndex value.");
11+
12+
StartIndex = startIndex;
13+
EndIndex = endIndex;
14+
}
15+
16+
public int StartIndex { get; }
17+
public int EndIndex { get; }
18+
19+
public int Count => EndIndex - StartIndex + 1;
20+
}
21+
22+
public class ExcelRange
23+
{
24+
public ExcelRange(int maxRow, int maxColumn)
25+
{
26+
Rows = new ExcelRangeElement(1, maxRow);
27+
Columns = new ExcelRangeElement(1, maxColumn);
28+
}
29+
30+
public string StartCell { get; internal set; }
31+
public string EndCell { get; internal set; }
32+
33+
public ExcelRangeElement Rows { get; }
34+
public ExcelRangeElement Columns { get; }
35+
}
36+
}

src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.Impl.cs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,12 @@ internal partial class ExcelOpenXmlTemplate
138138
private static readonly Regex _cellRegex = CellRegex();
139139
[GeneratedRegex(@"\{\{(.*?)\}\}")] private static partial Regex TemplateRegex();
140140
private static readonly Regex _templateRegex = TemplateRegex();
141-
141+
[GeneratedRegex(@".*?\{\{.*?\}\}.*?")] private static partial Regex NonTemplateRegex();
142+
private static readonly Regex _nonTemplateRegex = TemplateRegex();
142143
#else
143144
private static readonly Regex _cellRegex = new Regex("([A-Z]+)([0-9]+)", RegexOptions.Compiled);
144145
private static readonly Regex _templateRegex = new Regex(@"\{\{(.*?)\}\}", RegexOptions.Compiled);
146+
private static readonly Regex _nonTemplateRegex = new Regex(@".*?\{\{.*?\}\}.*?", RegexOptions.Compiled);
145147
#endif
146148

147149
private void GenerateSheetXmlImplByUpdateMode(ZipArchiveEntry sheetZipEntry, Stream stream, Stream sheetStream, IDictionary<string, object> inputMaps, IDictionary<int, string> sharedStrings, bool mergeCells = false)
@@ -174,7 +176,6 @@ private void GenerateSheetXmlImplByCreateMode(ZipArchiveEntry templateSheetZipEn
174176
}
175177

176178
//outputSheetStream.Dispose();
177-
178179
//sheetZipEntry.Delete(); // ZipArchiveEntry can't update directly, so need to delete then create logic
179180

180181
var worksheet = doc.SelectSingleNode("/x:worksheet", _ns);
@@ -445,7 +446,7 @@ private void WriteSheetXml(Stream outputFileStream, XmlDocument doc, XmlNode she
445446
var iEnumerableIndex = 0;
446447
enumrowstart = newRowIndex;
447448

448-
CellIEnumerableValuesGenerate(endPrefix, writer, ref rowIndexDiff, rowXml, ref headerDiff, ref prevHeader, mergeRowCount, isHeaderRow, ref currentHeader, rowInfo, row, groupingRowDiff, ref newRowIndex, innerXml, outerXmlOpen, ref isFirst, ref iEnumerableIndex, row);
449+
GenerateCellValues(endPrefix, writer, ref rowIndexDiff, rowXml, ref headerDiff, ref prevHeader, mergeRowCount, isHeaderRow, ref currentHeader, rowInfo, row, groupingRowDiff, ref newRowIndex, innerXml, outerXmlOpen, ref isFirst, ref iEnumerableIndex, row);
449450
enumrowend = newRowIndex - 1;
450451

451452
var conditionalFormats = conditionalFormatRanges.Where(cfr => cfr.Ranges.Any(r => r.ContainsRow(originRowIndex)));
@@ -479,9 +480,9 @@ private void WriteSheetXml(Stream outputFileStream, XmlDocument doc, XmlNode she
479480
.Append(outerXmlOpen)
480481
.AppendFormat(@" r=""{0}"">", newRowIndex)
481482
.Append(innerXml)
482-
.Replace($"{{{{$rowindex}}}}", newRowIndex.ToString())
483-
.Replace($"{{{{$enumrowstart}}}}", enumrowstart.ToString())
484-
.Replace($"{{{{$enumrowend}}}}", enumrowend.ToString())
483+
.Replace("{{$rowindex}}", newRowIndex.ToString())
484+
.Replace("{{$enumrowstart}}", enumrowstart.ToString())
485+
.Replace("{{$enumrowend}}", enumrowend.ToString())
485486
.AppendFormat("</{0}>", row.Name);
486487

487488
ProcessFormulas(rowXml, newRowIndex);
@@ -525,13 +526,13 @@ private void WriteSheetXml(Stream outputFileStream, XmlDocument doc, XmlNode she
525526
}
526527
}
527528

528-
private void CellIEnumerableValuesGenerate(string endPrefix, StreamWriter writer, ref int rowIndexDiff,
529+
//todo: refactor in a way that needs less parameters
530+
private void GenerateCellValues(string endPrefix, StreamWriter writer, ref int rowIndexDiff,
529531
StringBuilder rowXml, ref int headerDiff, ref string prevHeader, int mergeRowCount, bool isHeaderRow,
530532
ref string currentHeader, XRowInfo rowInfo, XmlElement row, int groupingRowDiff, ref int newRowIndex,
531533
string innerXml, StringBuilder outerXmlOpen, ref bool isFirst, ref int iEnumerableIndex, XmlElement rowElement)
532534
{
533535
// Just need to remove space string one time https://github.com/mini-software/MiniExcel/issues/751
534-
var cleanRowXml = CleanXml(rowXml, endPrefix);
535536
var cleanOuterXmlOpen = CleanXml(outerXmlOpen, endPrefix);
536537
var cleanInnerXml = CleanXml(innerXml, endPrefix);
537538

@@ -540,11 +541,10 @@ private void CellIEnumerableValuesGenerate(string endPrefix, StreamWriter writer
540541
foreach (XmlElement c in notFirstRowInnerXmlElement.SelectNodes("x:c", _ns))
541542
{
542543
var v = c.SelectSingleNode("x:v", _ns);
543-
if (v != null && !Regex.IsMatch(v.InnerText, @".*?\{\{.*?\}\}.*?"))
544+
if (v != null && !_nonTemplateRegex.IsMatch(v.InnerText))
544545
v.InnerText = string.Empty;
545546
}
546-
var cleannotFirstRowInnerXmlElementInnerXml = CleanXml(notFirstRowInnerXmlElement.InnerXml, endPrefix);
547-
547+
var cleanNotFirstRowInnerXmlElement = CleanXml(notFirstRowInnerXmlElement.InnerXml, endPrefix);
548548

549549
foreach (var item in rowInfo.CellIEnumerableValues)
550550
{
@@ -553,7 +553,7 @@ private void CellIEnumerableValuesGenerate(string endPrefix, StreamWriter writer
553553
.Append(cleanOuterXmlOpen)
554554
.AppendFormat(@" r=""{0}"">", newRowIndex)
555555
.Append(cleanInnerXml)
556-
.Replace($"{{{{$rowindex}}}}", newRowIndex.ToString())
556+
.Replace("{{$rowindex}}", newRowIndex.ToString())
557557
.AppendFormat("</{0}>", row.Name);
558558

559559
var rowXmlString = rowXml.ToString();
@@ -721,7 +721,7 @@ private void CellIEnumerableValuesGenerate(string endPrefix, StreamWriter writer
721721
if (isFirst)
722722
{
723723
// https://github.com/mini-software/MiniExcel/issues/771 Saving by template introduces unintended value replication in each row #771
724-
cleanInnerXml = cleannotFirstRowInnerXmlElementInnerXml;
724+
cleanInnerXml = cleanNotFirstRowInnerXmlElement;
725725

726726

727727
isFirst = false;
@@ -777,7 +777,7 @@ private void CellIEnumerableValuesGenerate(string endPrefix, StreamWriter writer
777777
}
778778
}
779779

780-
newRow.InnerXml = new StringBuilder(newRow.InnerXml).Replace($"{{{{$rowindex}}}}", mergeBaseRowIndex.ToString()).ToString();
780+
newRow.InnerXml = new StringBuilder(newRow.InnerXml).Replace("{{$rowindex}}", mergeBaseRowIndex.ToString()).ToString();
781781
writer.Write(CleanXml(newRow.OuterXml, endPrefix));
782782
}
783783
}
@@ -1007,6 +1007,7 @@ private void UpdateDimensionAndGetRowsInfo(IDictionary<string, object> inputMaps
10071007
//Type ienumerableGenricType = null;
10081008
//IDictionary<string, PropertyInfo> props = null;
10091009
//IEnumerable ienumerable = null;
1010+
10101011
var xRowInfo = new XRowInfo
10111012
{
10121013
Row = row
@@ -1040,8 +1041,8 @@ private void UpdateDimensionAndGetRowsInfo(IDictionary<string, object> inputMaps
10401041
.Distinct()
10411042
.ToArray();
10421043

1043-
var matchCnt = matches.Length;
1044-
var isMultiMatch = matchCnt > 1 || (matchCnt == 1 && v.InnerText != $"{{{{{matches[0]}}}}}");
1044+
var matchCount = matches.Length;
1045+
var isMultiMatch = matchCount > 1 || (matchCount == 1 && v.InnerText != $"{{{{{matches[0]}}}}}");
10451046

10461047
foreach (var formatText in matches)
10471048
{

0 commit comments

Comments
 (0)