Skip to content

Commit 6f54d45

Browse files
Changing templating system from XmlDocument based to XDocument based (#946)
* Changed `OpenXmlZip` to make use of `ZipArchive`'s asynchronous APIs - Changed `OpenXmlZip` to make use of `ZipArchive`'s asynchronous `CreateAsync` and `DisposeAsync` methods by adding an asynchronous factory method and the IAsyncDisposable implementation - Updated all entry points for `OpenXmlZip` and `ZipArchive` in all methods across the codebase - Added `SynchronousHelper` with extension methods for ensuring compatibility with the SyncMethodGenerator - Other minor code cleanups * Added XDocument based implementation of templating system in place of the XmlDocument based one * Optimization of ProcessFormulas method, minor fixes and renamings
1 parent 1b9bcbe commit 6f54d45

18 files changed

Lines changed: 724 additions & 680 deletions
Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
namespace MiniExcelLib.Core.Helpers;
22

3+
#if NETSTANDARD2_0
4+
5+
/// <summary>
6+
/// Provides .NET Standard 2.0 polyfills for utility methods found in later framework versions.
7+
/// This enables a unified API surface across the codebase without the need for conditional compilation directives.
8+
/// </summary>
39
public static class NetStandardExtensions
410
{
5-
#if NETSTANDARD2_0
611
public static TValue? GetValueOrDefault<TKey, TValue>(this IReadOnlyDictionary<TKey, TValue> dictionary, TKey key, TValue? defaultValue = default)
712
{
813
return dictionary.TryGetValue(key, out var value) ? value : defaultValue;
914
}
10-
#endif
1115
}
16+
#endif
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System.IO.Compression;
2+
3+
namespace MiniExcelLib.Core.Helpers;
4+
5+
/// <summary>
6+
/// Supplements base classes with synchronous method counterparts, ensuring compatibility with the SyncMethodGenerator
7+
/// by providing missing entry points without requiring manual preprocessor directives (#if SYNC_ONLY)
8+
/// </summary>
9+
public static class SynchronousHelper
10+
{
11+
extension(ZipArchive)
12+
{
13+
public static ZipArchive Create(Stream stream, ZipArchiveMode mode, bool leaveOpen, Encoding? encoding = null)
14+
=> new(stream, mode, leaveOpen, encoding);
15+
}
16+
}

src/MiniExcel.OpenXml/Api/OpenXmlImporter.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -223,11 +223,11 @@ public async Task<List<string>> GetSheetNamesAsync(Stream stream, OpenXmlConfigu
223223
{
224224
config ??= OpenXmlConfiguration.Default;
225225

226-
using var archive = new OpenXmlZip(stream, leaveOpen: true);
227-
226+
var archive = await OpenXmlZip.CreateAsync(stream, leaveOpen: true, cancellationToken: cancellationToken).ConfigureAwait(false);
227+
await using var disposableArchive = archive.ConfigureAwait(false);
228228
using var reader = await OpenXmlReader.CreateAsync(stream, config, cancellationToken: cancellationToken).ConfigureAwait(false);
229-
var rels = await reader.GetWorkbookRelsAsync(archive.EntryCollection, cancellationToken).ConfigureAwait(false);
230229

230+
var rels = await reader.GetWorkbookRelsAsync(archive.EntryCollection, cancellationToken).ConfigureAwait(false);
231231
return rels?.Select(s => s.Name).ToList() ?? [];
232232
}
233233

@@ -248,10 +248,11 @@ public async Task<List<SheetInfo>> GetSheetInformationsAsync(Stream stream, Open
248248
{
249249
config ??= OpenXmlConfiguration.Default;
250250

251-
using var archive = new OpenXmlZip(stream);
251+
var archive = await OpenXmlZip.CreateAsync(stream, cancellationToken: cancellationToken).ConfigureAwait(false);
252+
await using var disposableArchve = archive.ConfigureAwait(false);
252253
using var reader = await OpenXmlReader.CreateAsync(stream, config, cancellationToken: cancellationToken).ConfigureAwait(false);
253-
var rels = await reader.GetWorkbookRelsAsync(archive.EntryCollection, cancellationToken).ConfigureAwait(false);
254254

255+
var rels = await reader.GetWorkbookRelsAsync(archive.EntryCollection, cancellationToken).ConfigureAwait(false);
255256
return rels?.Select((s, i) => s.ToSheetInfo((uint)i)).ToList() ?? [];
256257
}
257258

src/MiniExcel.OpenXml/Constants/Schemas.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
internal static class Schemas
44
{
5-
public const string SpreadsheetmlXmlNs = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
5+
public const string SpreadsheetmlXmlMain = "http://schemas.openxmlformats.org/spreadsheetml/2006/main";
66
public const string SpreadsheetmlXmlStrictNs = "http://purl.oclc.org/ooxml/spreadsheetml/main";
77

88
public const string OpenXmlPackageRelationships = "http://schemas.openxmlformats.org/package/2006/relationships";

src/MiniExcel.OpenXml/OpenXmlReader.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace MiniExcelLib.OpenXml;
1010

1111
internal partial class OpenXmlReader : IMiniExcelReader
1212
{
13-
private static readonly string[] Ns = [Schemas.SpreadsheetmlXmlNs, Schemas.SpreadsheetmlXmlStrictNs];
13+
private static readonly string[] Ns = [Schemas.SpreadsheetmlXmlMain, Schemas.SpreadsheetmlXmlStrictNs];
1414
private static readonly string[] RelationshiopNs = [Schemas.SpreadsheetmlXmlRelationships, Schemas.SpreadsheetmlXmlStrictRelationships];
1515
private readonly OpenXmlConfiguration _config;
1616

@@ -21,18 +21,20 @@ internal partial class OpenXmlReader : IMiniExcelReader
2121
internal readonly OpenXmlZip Archive;
2222
internal IDictionary<int, string> SharedStrings = new Dictionary<int, string>();
2323

24-
private OpenXmlReader(Stream stream, IMiniExcelConfiguration? configuration)
24+
private OpenXmlReader(OpenXmlZip openXmlZip, IMiniExcelConfiguration? configuration)
2525
{
26-
Archive = new OpenXmlZip(stream);
26+
Archive = openXmlZip;
2727
_config = (OpenXmlConfiguration?)configuration ?? OpenXmlConfiguration.Default;
2828
}
2929

3030
[CreateSyncVersion]
3131
internal static async Task<OpenXmlReader> CreateAsync(Stream stream, IMiniExcelConfiguration? configuration, CancellationToken cancellationToken = default)
3232
{
3333
ThrowHelper.ThrowIfInvalidOpenXml(stream);
34-
35-
var reader = new OpenXmlReader(stream, configuration);
34+
35+
var archive = await OpenXmlZip.CreateAsync(stream, cancellationToken: cancellationToken).ConfigureAwait(false);
36+
var reader = new OpenXmlReader(archive, configuration);
37+
3638
await reader.SetSharedStringsAsync(cancellationToken).ConfigureAwait(false);
3739
return reader;
3840
}
@@ -1149,7 +1151,7 @@ internal async Task<CommentResultSet> ReadCommentsAsync(string? sheetName, Cance
11491151

11501152
XNamespace nsRel = Schemas.OpenXmlPackageRelationships;
11511153
XNamespace ns18Tc = Schemas.SpreadsheetmlXmlX18Tc;
1152-
XNamespace nsMain = Schemas.SpreadsheetmlXmlNs;
1154+
XNamespace nsMain = Schemas.SpreadsheetmlXmlMain;
11531155
XNamespace ns14R = Schemas.SpreadsheetmlXmlX14R;
11541156

11551157
SetWorkbookRels(Archive.EntryCollection);

src/MiniExcel.OpenXml/OpenXmlWriter.DefaultOpenXml.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
namespace MiniExcelLib.OpenXml;
66

7-
internal partial class OpenXmlWriter : IMiniExcelWriter
7+
internal partial class OpenXmlWriter
88
{
99
private readonly Dictionary<string, ZipPackageInfo> _zipDictionary = [];
10-
private Dictionary<string, string> _cellXfIdMap;
10+
private Dictionary<string, string> _cellXfIdMap = [];
1111

1212
private IEnumerable<Tuple<SheetDto, object?>> GetSheets()
1313
{

src/MiniExcel.OpenXml/OpenXmlWriter.cs

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,31 +23,37 @@ internal partial class OpenXmlWriter : IMiniExcelWriter
2323

2424
private int _currentSheetIndex = 0;
2525

26-
private OpenXmlWriter(Stream stream, object? value, string? sheetName, IMiniExcelConfiguration? configuration, bool printHeader)
26+
private OpenXmlWriter(Stream stream, ZipArchive archive, object? value, string? sheetName, OpenXmlConfiguration configuration, bool printHeader)
2727
{
2828
_stream = stream;
2929

30-
// A. Why ZipArchiveMode.Update and not ZipArchiveMode.Create?
31-
// R. ZipArchiveEntry does not support seeking when Mode is Create.
32-
_configuration = configuration as OpenXmlConfiguration ?? OpenXmlConfiguration.Default;
33-
if (_configuration is { EnableAutoWidth: true, FastMode: false })
34-
throw new InvalidOperationException("Auto width requires fast mode to be enabled");
35-
36-
var archiveMode = _configuration.FastMode ? ZipArchiveMode.Update : ZipArchiveMode.Create;
37-
_archive = new ZipArchive(_stream, archiveMode, true, Utf8WithBom);
30+
_configuration = configuration;
31+
_archive = archive;
3832

3933
_value = value;
4034
_printHeader = printHeader;
4135
_defaultSheetName = sheetName;
4236
}
4337

4438
[CreateSyncVersion]
45-
internal static Task<OpenXmlWriter> CreateAsync(Stream stream, object? value, string? sheetName, bool printHeader, IMiniExcelConfiguration? configuration, CancellationToken cancellationToken = default)
39+
internal static async ValueTask<OpenXmlWriter> CreateAsync(Stream stream, object? value, string? sheetName, bool printHeader, IMiniExcelConfiguration? configuration, CancellationToken cancellationToken = default)
4640
{
4741
ThrowHelper.ThrowIfInvalidSheetName(sheetName);
4842

49-
var writer = new OpenXmlWriter(stream, value, sheetName, configuration, printHeader);
50-
return Task.FromResult(writer);
43+
var conf = configuration as OpenXmlConfiguration ?? OpenXmlConfiguration.Default;
44+
if (conf is { EnableAutoWidth: true, FastMode: false })
45+
throw new InvalidOperationException("Auto width requires fast mode to be enabled");
46+
47+
// A. Why ZipArchiveMode.Update and not ZipArchiveMode.Create?
48+
// R. ZipArchiveEntry does not support seeking when Mode is Create.
49+
var archiveMode = conf.FastMode ? ZipArchiveMode.Update : ZipArchiveMode.Create;
50+
51+
#if NET10_0_OR_GREATER
52+
var archive = await ZipArchive.CreateAsync(stream, archiveMode, true, Utf8WithBom, cancellationToken).ConfigureAwait(false);
53+
#else
54+
var archive = new ZipArchive(stream, archiveMode, true, Utf8WithBom);
55+
#endif
56+
return new OpenXmlWriter(stream, archive, value, sheetName, conf, printHeader);
5157
}
5258

5359
[CreateSyncVersion]

src/MiniExcel.OpenXml/Picture/OpenXmlPictureImplement.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,18 @@ private static XmlNamespaceManager GetRNamespaceManager(XmlDocument doc)
1717
public static async Task AddPictureAsync(Stream excelStream, CancellationToken cancellationToken = default, params MiniExcelPicture[] images)
1818
{
1919
// get sheets
20-
using var excelArchive = new OpenXmlZip(excelStream);
20+
var excelArchive = await OpenXmlZip.CreateAsync(excelStream, cancellationToken: cancellationToken).ConfigureAwait(false);
21+
await using var disposableExcelArchive = excelArchive.ConfigureAwait(false);
22+
2123
using var reader = await OpenXmlReader.CreateAsync(excelStream, null, cancellationToken).ConfigureAwait(false);
2224

2325
#if NET10_0_OR_GREATER
24-
var archive = new ZipArchive(excelStream, ZipArchiveMode.Update, true);
25-
await using var disposableArchive = archive.ConfigureAwait(false);
26+
var archive = await ZipArchive.CreateAsync(excelStream, ZipArchiveMode.Update, true, null, cancellationToken).ConfigureAwait(false);
27+
await using var disposableArchive = archive.ConfigureAwait(false);
2628
#else
2729
using var archive = new ZipArchive(excelStream, ZipArchiveMode.Update, true);
2830
#endif
29-
var rels = await reader.GetWorkbookRelsAsync(excelArchive.EntryCollection, cancellationToken).ConfigureAwait(false);
31+
var rels = await reader.GetWorkbookRelsAsync(excelArchive.EntryCollection, cancellationToken).ConfigureAwait(false);
3032
var sheetEntries = rels?.ToList() ?? [];
3133

3234
// Group images by sheet

src/MiniExcel.OpenXml/Styles/OpenXmlStyles.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ namespace MiniExcelLib.OpenXml.Styles;
55

66
internal class OpenXmlStyles
77
{
8-
private static readonly string[] Ns = [Schemas.SpreadsheetmlXmlNs, Schemas.SpreadsheetmlXmlStrictNs];
8+
private static readonly string[] Ns = [Schemas.SpreadsheetmlXmlMain, Schemas.SpreadsheetmlXmlStrictNs];
99

1010
private readonly Dictionary<int, StyleRecord> _cellXfs = new();
1111
private readonly Dictionary<int, StyleRecord> _cellStyleXfs = new();

0 commit comments

Comments
 (0)