Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.Impl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -701,6 +701,8 @@ private async Task<GenerateCellValuesContext> GenerateCellValuesAsync(
: tempReplacement;

replacements[key] = replacementValue;
AddFlattenedAndFormattedValues(replacements, key, cellValue, propInfo);

rowXml.Replace($"@header{{{{{key}}}}}", replacementValue);

if (isHeaderRow && row.Value.Contains(key))
Expand Down
41 changes: 31 additions & 10 deletions src/MiniExcel.OpenXml/Templates/OpenXmlTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,14 @@ public async Task SaveAsByTemplateAsync(byte[] templateBytes, object value, Canc
[CreateSyncVersion]
public async Task SaveAsByTemplateAsync(Stream templateStream, object value, CancellationToken cancellationToken = default)
{
if(!templateStream.CanSeek)
if (!templateStream.CanSeek)
throw new ArgumentException("The template stream must be seekable");

templateStream.Seek(0, SeekOrigin.Begin);
using var templateReader = await OpenXmlReader.CreateAsync(templateStream, null, cancellationToken: cancellationToken).ConfigureAwait(false);
var outputFileArchive = await OpenXmlZip.CreateAsync(_outputFileStream, mode: ZipArchiveMode.Create, true, Encoding.UTF8, isUpdateMode: false, cancellationToken: cancellationToken).ConfigureAwait(false);
await using var disposableOutputFileArchive = outputFileArchive.ConfigureAwait(false);

try
{
outputFileArchive.EntryCollection = templateReader.Archive.ZipFile.Entries; //TODO:need to remove
Expand All @@ -66,7 +66,7 @@ public async Task SaveAsByTemplateAsync(Stream templateStream, object value, Can
{
outputFileArchive.Entries.Add(entry.FullName.Replace('\\', '/'), entry);
}

// Create a new zip file for writing
templateStream.Position = 0;
#if NET10_0_OR_GREATER
Expand All @@ -75,14 +75,16 @@ public async Task SaveAsByTemplateAsync(Stream templateStream, object value, Can
#else
using var originalArchive = new ZipArchive(templateStream, ZipArchiveMode.Read);
#endif
// sheet name map
var sheetPathRealNameMap = GetRealSheetNameMap(originalArchive);

// Iterate through each entry in the original archive
foreach (var entry in originalArchive.Entries)
{
var entryName = entry.FullName.TrimStart('/');
if (entryName.StartsWith("xl/worksheets/sheet", StringComparison.OrdinalIgnoreCase) || entryName.Equals("xl/calcChain.xml"))
if (entryName.StartsWith("xl/worksheets/sheet", StringComparison.OrdinalIgnoreCase) || entryName.Equals("xl/calcChain.xml") || entryName.Equals("xl/workbook.xml") || entryName.Equals("xl/_rels/workbook.xml.rels"))
continue;

// Create a new entry in the new archive with the same name
var newEntry = outputFileArchive.ZipFile.CreateEntry(entry.FullName);

Expand All @@ -109,23 +111,33 @@ await originalEntryStream.CopyToAsync(newEntryStream
var templateSharedStrings = templateReader.SharedStrings;
templateStream.Position = 0;


//read all xlsx sheets
var templateSheets = templateReader.Archive.ZipFile.Entries
.Where(entry => entry.FullName
.TrimStart('/')
.StartsWith("xl/worksheets/sheet", StringComparison.OrdinalIgnoreCase));

int sheetIdx = 0;
// 全局收集所有工作表信息(单表/多表都在这里汇总)
var allSheetInfos = new List<(int Index, string Name)>();

foreach (var templateSheet in templateSheets)
{
// XRowInfos musy be cleared for every sheet or it'll cause duplicates: https://user-images.githubusercontent.com/12729184/115003101-0fcab700-9ed8-11eb-9151-ca4d7b86d59e.png
_xRowInfos.Clear();
_xMergeCellInfos.Clear();
_newXMergeCellInfos.Clear();
_calcChainCellRefs.Clear();

var templateFullName = templateSheet.FullName;
var inputValues = _inputValueExtractor.ToValueDictionary(value);
sheetPathRealNameMap.TryGetValue(templateFullName, out var realSheetName);


if (await HookSheetProcess(outputFileArchive, realSheetName, templateSharedStrings, sheetIdx, allSheetInfos, templateSheet, templateFullName, inputValues, cancellationToken).ConfigureAwait(false))
break;
Comment thread
michelebastione marked this conversation as resolved.
Outdated

var outputZipEntry = outputFileArchive.ZipFile.CreateEntry(templateFullName);

#if NET8_0_OR_GREATER
Expand All @@ -135,14 +147,22 @@ await originalEntryStream.CopyToAsync(newEntryStream
using var outputZipSheetEntryStream = outputZipEntry.Open();
#endif
await GenerateSheetByCreateModeAsync(templateSheet, outputZipSheetEntryStream, inputValues, templateSharedStrings, cancellationToken: cancellationToken).ConfigureAwait(false);

//doc.Save(zipStream); //don't do it because: https://user-images.githubusercontent.com/12729184/114361127-61a5d100-9ba8-11eb-9bb9-34f076ee28a2.png
// disposing writer disposes streams as well. read and parse calc functions before that

sheetIdx++;
allSheetInfos.Add((sheetIdx, realSheetName));
_calcChainContent.Append(CalcChainHelper.GetCalcChainContent(_calcChainCellRefs, sheetIdx));

}



// 【一次性写入所有配置】(修复覆盖BUG,表名生效)
await BatchAddSheetsToExcelConfigAsync(outputFileArchive.ZipFile, originalArchive, allSheetInfos, cancellationToken).ConfigureAwait(false);


// create mode we need to not create first then create here
var calcChain = outputFileArchive.EntryCollection.FirstOrDefault(e => e.FullName.Contains("xl/calcChain.xml"));
if (calcChain is not null)
Expand Down Expand Up @@ -194,4 +214,5 @@ await originalEntryStream.CopyToAsync(newEntryStream
outputFileArchive.ZipFile.Dispose();
#endif
}
}

}
Loading