Skip to content

Commit ca78480

Browse files
authored
fix(Insert Sheet): Added insert sheet feature about ContentTypesXml processing (#728)
* Added insert sheet feature about `ContentTypesXml` processing * adjust the order of attributes
1 parent 1021b08 commit ca78480

File tree

2 files changed

+80
-31
lines changed

2 files changed

+80
-31
lines changed

src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.Async.cs

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using System.Text;
1212
using System.Threading;
1313
using System.Threading.Tasks;
14+
using System.Xml.Linq;
1415

1516
namespace MiniExcelLibs.OpenXml
1617
{
@@ -65,19 +66,18 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToken can
6566
{
6667
currentSheetIndex = existSheetDto.SheetIdx;
6768
_archive.Entries.Single(s => s.FullName == existSheetDto.Path).Delete();
68-
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(currentSheetIndex))?.Delete();
69-
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Drawing(currentSheetIndex))?.Delete();
7069
await CreateSheetXmlAsync(_value, existSheetDto.Path, cancellationToken);
7170
}
7271

7372
await AddFilesToZipAsync(cancellationToken);
7473

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

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

7980
GenerateWorkBookXmls(out StringBuilder workbookXml, out StringBuilder workbookRelsXml, out Dictionary<int, string> sheetsRelsXml);
80-
8181
foreach (var sheetRelsXml in sheetsRelsXml)
8282
{
8383
var sheetRelsXmlPath = ExcelFileNames.SheetRels(sheetRelsXml.Key);
@@ -91,6 +91,8 @@ public async Task InsertAsync(bool overwriteSheet = false, CancellationToken can
9191
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.WorkbookRels)?.Delete();
9292
await CreateZipEntryAsync(ExcelFileNames.WorkbookRels, null, ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString()), cancellationToken);
9393

94+
await InsertContentTypesXmlAsync(cancellationToken);
95+
9496
_archive.Dispose();
9597
}
9698

@@ -382,9 +384,6 @@ private async Task AddFilesToZipAsync(CancellationToken cancellationToken)
382384
}
383385
}
384386

385-
/// <summary>
386-
/// styles.xml
387-
/// </summary>
388387
private async Task GenerateStylesXmlAsync(CancellationToken cancellationToken)
389388
{
390389
using (var context = new SheetStyleBuildContext(_zipDictionary, _archive, _utf8WithBom, _configuration.DynamicColumns))
@@ -440,9 +439,6 @@ await CreateZipEntryAsync(
440439
cancellationToken);
441440
}
442441

443-
/// <summary>
444-
/// workbook.xml 、 workbookRelsXml
445-
/// </summary>
446442
private async Task GenerateWorkbookXmlAsync(CancellationToken cancellationToken)
447443
{
448444
GenerateWorkBookXmls(
@@ -472,16 +468,45 @@ await CreateZipEntryAsync(
472468
cancellationToken);
473469
}
474470

475-
/// <summary>
476-
/// [Content_Types].xml
477-
/// </summary>
478471
private async Task GenerateContentTypesXmlAsync(CancellationToken cancellationToken)
479472
{
480473
var contentTypes = GetContentTypesXml();
481474

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

478+
private async Task InsertContentTypesXmlAsync(CancellationToken cancellationToken)
479+
{
480+
var contentTypesZipEntry = _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.ContentTypes);
481+
if (contentTypesZipEntry == null)
482+
{
483+
await GenerateContentTypesXmlAsync(cancellationToken);
484+
return;
485+
}
486+
using (var stream = contentTypesZipEntry.Open())
487+
{
488+
var doc = XDocument.Load(stream);
489+
var ns = doc.Root.GetDefaultNamespace();
490+
var typesElement = doc.Descendants(ns + "Types").Single();
491+
var partNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
492+
foreach (var partName in typesElement.Elements(ns + "Override").Select(s => s.Attribute("PartName").Value))
493+
{
494+
partNames.Add(partName);
495+
}
496+
foreach (var p in _zipDictionary)
497+
{
498+
var partName = $"/{p.Key}";
499+
if (!partNames.Contains(partName))
500+
{
501+
var newElement = new XElement(ns + "Override", new XAttribute("ContentType", p.Value.ContentType), new XAttribute("PartName", partName));
502+
typesElement.Add(newElement);
503+
}
504+
}
505+
stream.Position = 0;
506+
doc.Save(stream);
507+
}
508+
}
509+
485510
private async Task CreateZipEntryAsync(string path, string contentType, string content, CancellationToken cancellationToken)
486511
{
487512
ZipArchiveEntry entry = _archive.CreateEntry(path, CompressionLevel.Fastest);

src/MiniExcel/OpenXml/ExcelOpenXmlSheetWriter.cs

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
using MiniExcelLibs.WriteAdapter;
77
using MiniExcelLibs.Zip;
88
using System;
9-
using System.Collections;
109
using System.Collections.Generic;
1110
using System.IO;
1211
using System.IO.Compression;
1312
using System.Linq;
1413
using System.Text;
14+
using System.Xml.Linq;
1515

1616
namespace MiniExcelLibs.OpenXml
1717
{
@@ -101,32 +101,33 @@ public void Insert(bool overwriteSheet = false)
101101
{
102102
currentSheetIndex = existSheetDto.SheetIdx;
103103
_archive.Entries.Single(s => s.FullName == existSheetDto.Path).Delete();
104-
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(currentSheetIndex))?.Delete();
105-
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.Drawing(currentSheetIndex))?.Delete();
106104
CreateSheetXml(_value, existSheetDto.Path);
107105
}
108106

109107
AddFilesToZip();
110108

111-
GenerateDrawinRelXml(currentSheetIndex);
109+
_archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.DrawingRels(currentSheetIndex - 1))?.Delete();
110+
GenerateDrawinRelXml(currentSheetIndex - 1);
112111

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

115115
GenerateWorkBookXmls(out StringBuilder workbookXml, out StringBuilder workbookRelsXml, out Dictionary<int, string> sheetsRelsXml);
116-
117116
foreach (var sheetRelsXml in sheetsRelsXml)
118117
{
119118
var sheetRelsXmlPath = ExcelFileNames.SheetRels(sheetRelsXml.Key);
120119
_archive.Entries.SingleOrDefault(s => s.FullName == sheetRelsXmlPath)?.Delete();
121120
CreateZipEntry(sheetRelsXmlPath, null, ExcelXml.DefaultSheetRelXml.Replace("{{format}}", sheetRelsXml.Value));
122121
}
123122

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

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

129+
InsertContentTypesXml();
130+
130131
_archive.Dispose();
131132
}
132133

@@ -384,9 +385,6 @@ private void AddFilesToZip()
384385
}
385386
}
386387

387-
/// <summary>
388-
/// styles.xml
389-
/// </summary>
390388
private void GenerateStylesXml()
391389
{
392390
using (var context = new SheetStyleBuildContext(_zipDictionary, _archive, _utf8WithBom, _configuration.DynamicColumns))
@@ -440,9 +438,6 @@ private void GenerateDrawingXml(int sheetIndex)
440438
ExcelXml.DefaultDrawing.Replace("{{format}}", drawing));
441439
}
442440

443-
/// <summary>
444-
/// workbook.xml、workbookRelsXml
445-
/// </summary>
446441
private void GenerateWorkbookXml()
447442
{
448443
GenerateWorkBookXmls(
@@ -469,16 +464,45 @@ private void GenerateWorkbookXml()
469464
ExcelXml.DefaultWorkbookXmlRels.Replace("{{sheets}}", workbookRelsXml.ToString()));
470465
}
471466

472-
/// <summary>
473-
/// [Content_Types].xml
474-
/// </summary>
475467
private void GenerateContentTypesXml()
476468
{
477469
var contentTypes = GetContentTypesXml();
478470

479471
CreateZipEntry(ExcelFileNames.ContentTypes, null, contentTypes);
480472
}
481473

474+
private void InsertContentTypesXml()
475+
{
476+
var contentTypesZipEntry = _archive.Entries.SingleOrDefault(s => s.FullName == ExcelFileNames.ContentTypes);
477+
if (contentTypesZipEntry == null)
478+
{
479+
GenerateContentTypesXml();
480+
return;
481+
}
482+
using (var stream = contentTypesZipEntry.Open())
483+
{
484+
var doc = XDocument.Load(stream);
485+
var ns = doc.Root.GetDefaultNamespace();
486+
var typesElement = doc.Descendants(ns + "Types").Single();
487+
var partNames = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase);
488+
foreach (var partName in typesElement.Elements(ns + "Override").Select(s => s.Attribute("PartName").Value))
489+
{
490+
partNames.Add(partName);
491+
}
492+
foreach (var p in _zipDictionary)
493+
{
494+
var partName = $"/{p.Key}";
495+
if (!partNames.Contains(partName))
496+
{
497+
var newElement = new XElement(ns + "Override", new XAttribute("ContentType", p.Value.ContentType), new XAttribute("PartName", partName));
498+
typesElement.Add(newElement);
499+
}
500+
}
501+
stream.Position = 0;
502+
doc.Save(stream);
503+
}
504+
}
505+
482506
private void CreateZipEntry(string path, string contentType, string content)
483507
{
484508
ZipArchiveEntry entry = _archive.CreateEntry(path, CompressionLevel.Fastest);

0 commit comments

Comments
 (0)