Skip to content

Commit

Permalink
fix(Insert Sheet): Added insert sheet feature about ContentTypesXml
Browse files Browse the repository at this point in the history
… processing (#728)

* Added insert sheet feature about `ContentTypesXml` processing

* adjust the order of attributes
  • Loading branch information
izanhzh authored Feb 23, 2025
1 parent 1021b08 commit ca78480
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 31 deletions.
53 changes: 39 additions & 14 deletions src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace MiniExcelLibs.OpenXml
{
Expand Down Expand Up @@ -65,19 +66,18 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToken can
{
currentSheetIndex = existSheetDto.SheetIdx;
_archive.Entries.Single(s => s.FullName == existSheetDto.Path).Delete();
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(currentSheetIndex))?.Delete();
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Drawing(currentSheetIndex))?.Delete();
await CreateSheetXmlAsync(_value, existSheetDto.Path, cancellationToken);
}

await AddFilesToZipAsync(cancellationToken);

await GenerateDrawinRelXmlAsync(currentSheetIndex, cancellationToken);
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(currentSheetIndex - 1))?.Delete();
await GenerateDrawinRelXmlAsync(currentSheetIndex - 1, cancellationToken);

await GenerateDrawingXmlAsync(currentSheetIndex, cancellationToken);
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Drawing(currentSheetIndex - 1))?.Delete();
await GenerateDrawingXmlAsync(currentSheetIndex - 1, cancellationToken);

GenerateWorkBookXmls(out StringBuilder workbookXml, out StringBuilder workbookRelsXml, out Dictionary<int, string> sheetsRelsXml);

foreach (var sheetRelsXml in sheetsRelsXml)
{
var sheetRelsXmlPath = ExcelFileNames.SheetRels(sheetRelsXml.Key);
Expand All @@ -91,6 +91,8 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToken can
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.WorkbookRels)?.Delete();
await CreateZipEntryAsync(ExcelFileNames.WorkbookRels, null, ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString()), cancellationToken);

await InsertContentTypesXmlAsync(cancellationToken);

_archive.Dispose();
}

Expand Down Expand Up @@ -382,9 +384,6 @@ private async Task AddFilesToZipAsync(CancellationToken cancellationToken)
}
}

/// <summary>
/// styles.xml
/// </summary>
private async Task GenerateStylesXmlAsync(CancellationToken cancellationToken)
{
using (var context = new SheetStyleBuildContext(_zipDictionary, _archive, _utf8WithBom, _configuration.DynamicColumns))
Expand Down Expand Up @@ -440,9 +439,6 @@ await CreateZipEntryAsync(
cancellationToken);
}

/// <summary>
/// workbook.xml 、 workbookRelsXml
/// </summary>
private async Task GenerateWorkbookXmlAsync(CancellationToken cancellationToken)
{
GenerateWorkBookXmls(
Expand Down Expand Up @@ -472,16 +468,45 @@ await CreateZipEntryAsync(
cancellationToken);
}

/// <summary>
/// [Content_Types].xml
/// </summary>
private async Task GenerateContentTypesXmlAsync(CancellationToken cancellationToken)
{
var contentTypes = GetContentTypesXml();

await CreateZipEntryAsync(ExcelFileNames.ContentTypes, null, contentTypes, cancellationToken);
}

private async Task InsertContentTypesXmlAsync(CancellationToken cancellationToken)
{
var contentTypesZipEntry = _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.ContentTypes);
if (contentTypesZipEntry == null)
{
await GenerateContentTypesXmlAsync(cancellationToken);
return;
}
using (var stream = contentTypesZipEntry.Open())
{
var doc = XDocument.Load(stream);
var ns = doc.Root.GetDefaultNamespace();
var typesElement = doc.Descendants(ns + "Types").Single();
var partNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
foreach (var partName in typesElement.Elements(ns + "Override").Select(s => s.Attribute("PartName").Value))
{
partNames.Add(partName);
}
foreach (var p in _zipDictionary)
{
var partName = $"/{p.Key}";
if (!partNames.Contains(partName))
{
var newElement = new XElement(ns + "Override", new XAttribute("ContentType", p.Value.ContentType), new XAttribute("PartName", partName));
typesElement.Add(newElement);
}
}
stream.Position = 0;
doc.Save(stream);
}
}

private async Task CreateZipEntryAsync(string path, string contentType, string content, CancellationToken cancellationToken)
{
ZipArchiveEntry entry = _archive.CreateEntry(path, CompressionLevel.Fastest);
Expand Down
58 changes: 41 additions & 17 deletions src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
using MiniExcelLibs.WriteAdapter;
using MiniExcelLibs.Zip;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace MiniExcelLibs.OpenXml
{
Expand Down Expand Up @@ -101,32 +101,33 @@ public void Insert(bool overwriteSheet = false)
{
currentSheetIndex = existSheetDto.SheetIdx;
_archive.Entries.Single(s => s.FullName == existSheetDto.Path).Delete();
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(currentSheetIndex))?.Delete();
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Drawing(currentSheetIndex))?.Delete();
CreateSheetXml(_value, existSheetDto.Path);
}

AddFilesToZip();

GenerateDrawinRelXml(currentSheetIndex);
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(currentSheetIndex - 1))?.Delete();
GenerateDrawinRelXml(currentSheetIndex - 1);

GenerateDrawingXml(currentSheetIndex);
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Drawing(currentSheetIndex - 1))?.Delete();
GenerateDrawingXml(currentSheetIndex - 1);

GenerateWorkBookXmls(out StringBuilder workbookXml, out StringBuilder workbookRelsXml, out Dictionary<int, string> sheetsRelsXml);

foreach (var sheetRelsXml in sheetsRelsXml)
{
var sheetRelsXmlPath = ExcelFileNames.SheetRels(sheetRelsXml.Key);
_archive.Entries.SingleOrDefault(s => s.FullName == sheetRelsXmlPath)?.Delete();
CreateZipEntry(sheetRelsXmlPath, null, ExcelXml.DefaultSheetRelXml.Replace("{{format}}", sheetRelsXml.Value));
}

_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Workbook)?.Delete();
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Workbook).Delete();
CreateZipEntry(ExcelFileNames.Workbook, ExcelContentTypes.Workbook, ExcelXml.DefaultWorkbookXml.Replace("{{sheets}}", workbookXml.ToString()));

_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.WorkbookRels)?.Delete();
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.WorkbookRels).Delete();
CreateZipEntry(ExcelFileNames.WorkbookRels, null, ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString()));

InsertContentTypesXml();

_archive.Dispose();
}

Expand Down Expand Up @@ -384,9 +385,6 @@ private void AddFilesToZip()
}
}

/// <summary>
/// styles.xml
/// </summary>
private void GenerateStylesXml()
{
using (var context = new SheetStyleBuildContext(_zipDictionary, _archive, _utf8WithBom, _configuration.DynamicColumns))
Expand Down Expand Up @@ -440,9 +438,6 @@ private void GenerateDrawingXml(int sheetIndex)
ExcelXml.DefaultDrawing.Replace("{{format}}", drawing));
}

/// <summary>
/// workbook.xml、workbookRelsXml
/// </summary>
private void GenerateWorkbookXml()
{
GenerateWorkBookXmls(
Expand All @@ -469,16 +464,45 @@ private void GenerateWorkbookXml()
ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString()));
}

/// <summary>
/// [Content_Types].xml
/// </summary>
private void GenerateContentTypesXml()
{
var contentTypes = GetContentTypesXml();

CreateZipEntry(ExcelFileNames.ContentTypes, null, contentTypes);
}

private void InsertContentTypesXml()
{
var contentTypesZipEntry = _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.ContentTypes);
if (contentTypesZipEntry == null)
{
GenerateContentTypesXml();
return;
}
using (var stream = contentTypesZipEntry.Open())
{
var doc = XDocument.Load(stream);
var ns = doc.Root.GetDefaultNamespace();
var typesElement = doc.Descendants(ns + "Types").Single();
var partNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
foreach (var partName in typesElement.Elements(ns + "Override").Select(s => s.Attribute("PartName").Value))
{
partNames.Add(partName);
}
foreach (var p in _zipDictionary)
{
var partName = $"/{p.Key}";
if (!partNames.Contains(partName))
{
var newElement = new XElement(ns + "Override", new XAttribute("ContentType", p.Value.ContentType), new XAttribute("PartName", partName));
typesElement.Add(newElement);
}
}
stream.Position = 0;
doc.Save(stream);
}
}

private void CreateZipEntry(string path, string contentType, string content)
{
ZipArchiveEntry entry = _archive.CreateEntry(path, CompressionLevel.Fastest);
Expand Down

0 comments on commit ca78480

Please sign in to comment.