Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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: 1 addition & 1 deletion .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
- name: Setup .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: 6.0.x
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ FodyWeavers.xsd
*.msp

# JetBrains Rider
.idea/
*.sln.iml

/BenchmarkDotNet.Artifacts
Expand Down
1 change: 1 addition & 0 deletions src/MiniExcel/ExcelFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{
using MiniExcelLibs.Csv;
using MiniExcelLibs.OpenXml;
using MiniExcelLibs.OpenXml.SaveByTemplate;
using System;
using System.IO;

Expand Down
2 changes: 1 addition & 1 deletion src/MiniExcel/MiniExcelLibs.csproj
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.NET 6.0 (LTS) end date is Nov 12, 2024, we will follow the date to upgrade next month.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net45;netstandard2.0;net6.0;</TargetFrameworks>
<TargetFrameworks>net45;netstandard2.0;net8.0;</TargetFrameworks>
<Version>1.34.2</Version>
</PropertyGroup>
<PropertyGroup>
Expand Down
154 changes: 0 additions & 154 deletions src/MiniExcel/OpenXml/ExcelOpenXmlTemplate.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
using System.Text.RegularExpressions;
using System.Xml;

namespace MiniExcelLibs.OpenXml
namespace MiniExcelLibs.OpenXml.SaveByTemplate
{
internal partial class ExcelOpenXmlTemplate
{
Expand Down Expand Up @@ -113,7 +113,7 @@ public string ToXmlString(string prefix)
public List<XMergeCell> NewXMergeCellInfos { get; private set; }

private void GenerateSheetXmlImpl(ZipArchiveEntry sheetZipEntry, Stream stream, Stream sheetStream,
Dictionary<string, object> inputMaps, IDictionary<int, string> sharedStrings,
IDictionary<string, object> inputMaps, IDictionary<int, string> sharedStrings,
bool mergeCells = false)
{
var doc = new XmlDocument();
Expand Down Expand Up @@ -911,7 +911,7 @@ private void ReplaceSharedStringsToStr(IDictionary<int, string> sharedStrings, r
}
}

private void UpdateDimensionAndGetRowsInfo(Dictionary<string, object> inputMaps, ref XmlDocument doc, ref XmlNodeList rows, bool changeRowIndex = true)
private void UpdateDimensionAndGetRowsInfo(IDictionary<string, object> inputMaps, ref XmlDocument doc, ref XmlNodeList rows, bool changeRowIndex = true)
{
// note : dimension need to put on the top ![image](https://user-images.githubusercontent.com/12729184/114507911-5dd88400-9c66-11eb-94c6-82ed7bdb5aab.png)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
using System.Threading;
using System.Threading.Tasks;

namespace MiniExcelLibs.OpenXml
namespace MiniExcelLibs.OpenXml.SaveByTemplate
{
internal partial class ExcelOpenXmlTemplate
{
Expand Down
124 changes: 124 additions & 0 deletions src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
namespace MiniExcelLibs.OpenXml.SaveByTemplate
{
using MiniExcelLibs.Utils;
using MiniExcelLibs.Zip;
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;

internal partial class ExcelOpenXmlTemplate : IExcelTemplate, IExcelTemplateAsync
{
private static readonly XmlNamespaceManager _ns;
private static readonly Regex _isExpressionRegex;

static ExcelOpenXmlTemplate()
{
_isExpressionRegex = new Regex("(?<={{).*?(?=}})");
_ns = new XmlNamespaceManager(new NameTable());
_ns.AddNamespace("x", Config.SpreadsheetmlXmlns);
_ns.AddNamespace("x14ac", Config.SpreadsheetmlXml_x14ac);
}

private readonly Stream _stream;
private readonly OpenXmlConfiguration _configuration;
private readonly StringBuilder _calcChainContent = new StringBuilder();

public ExcelOpenXmlTemplate(Stream stream, IConfiguration configuration)
{
_stream = stream;
_configuration = (OpenXmlConfiguration)configuration ?? OpenXmlConfiguration.DefaultConfig;
}

public void SaveAsByTemplate(string templatePath, object value)
{
using (var stream = FileHelper.OpenSharedRead(templatePath))
SaveAsByTemplateImpl(stream, value);
}

public void SaveAsByTemplate(byte[] templateBtyes, object value)
{
using (Stream stream = new MemoryStream(templateBtyes))
SaveAsByTemplateImpl(stream, value);
}

public void SaveAsByTemplateImpl(Stream templateStream, object value)
{
//only support xlsx
templateStream.CopyTo(_stream);

var reader = new ExcelOpenXmlSheetReader(_stream, null);
var _archive = new ExcelOpenXmlZip(_stream, mode: ZipArchiveMode.Update, true, Encoding.UTF8);
{
//read sharedString
var sharedStrings = reader._sharedStrings;
StringBuilder calcSheetContent = new StringBuilder();

//read all xlsx sheets
var sheets = _archive.zipFile.Entries.Where(w =>
w.FullName.StartsWith("xl/worksheets/sheet", StringComparison.OrdinalIgnoreCase)
|| w.FullName.StartsWith("/xl/worksheets/sheet", StringComparison.OrdinalIgnoreCase)
).ToList();

int sheetIdx = 0;
foreach (var sheet in sheets)
{
this.XRowInfos =
new List<XRowInfo>(); //every time need to use new XRowInfos or it'll cause duplicate problem: https://user-images.githubusercontent.com/12729184/115003101-0fcab700-9ed8-11eb-9151-ca4d7b86d59e.png
this.XMergeCellInfos = new Dictionary<string, XMergeCell>();
this.NewXMergeCellInfos = new List<XMergeCell>();

var sheetStream = sheet.Open();
var fullName = sheet.FullName;

ZipArchiveEntry entry = _archive.zipFile.CreateEntry(fullName);
using (var zipStream = entry.Open())
{
GenerateSheetXmlImpl(sheet, zipStream, sheetStream,
InputValueExtractor.ToValueDictionary(value), sharedStrings, false);
//doc.Save(zipStream); //don't do it because : ![image](https://user-images.githubusercontent.com/12729184/114361127-61a5d100-9ba8-11eb-9bb9-34f076ee28a2.png)
}

// disposing writer disposes streams as well. reopen the entry to read and parse calc functions
using (var filledStream = entry.Open())
{
sheetIdx++;
_calcChainContent.Append(CalcChainHelper.GetCalcChainContent(CalcChainCellRefs, sheetIdx));
}
}

var calcChain = _archive.zipFile.Entries.FirstOrDefault(e => e.FullName.Contains("xl/calcChain.xml"));
if (calcChain != null)
{
string calcChainPathname = calcChain.FullName;
calcChain.Delete();
var calcChainEntry = _archive.zipFile.CreateEntry(calcChainPathname);
using (var calcChainStream = calcChainEntry.Open())
{
CalcChainHelper.GenerateCalcChainSheet(calcChainStream, _calcChainContent.ToString());
}
}
}

_archive.zipFile.Dispose();
}

public Task SaveAsByTemplateAsync(string templatePath, object value,
CancellationToken cancellationToken = default(CancellationToken))
{
return Task.Run(() => SaveAsByTemplate(templatePath, value), cancellationToken);
}

public Task SaveAsByTemplateAsync(byte[] templateBtyes, object value,
CancellationToken cancellationToken = default(CancellationToken))
{
return Task.Run(() => SaveAsByTemplate(templateBtyes, value), cancellationToken);
}
}
}
43 changes: 43 additions & 0 deletions src/MiniExcel/SaveByTemplate/InputValueExtractor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;
using MiniExcelLibs.Utils;

namespace MiniExcelLibs.OpenXml.SaveByTemplate
{
public static class InputValueExtractor
{
public static IDictionary<string, object> ToValueDictionary(object valueObject)
=> valueObject is Dictionary<string, object> valueDictionary
? GetValuesFromDictionary(valueDictionary)
: GetValuesFromObject(valueObject);

private static IDictionary<string, object> GetValuesFromDictionary(Dictionary<string, object> valueDictionary)
{
return valueDictionary
.ToDictionary(
x => x.Key,
x => x.Value is IDataReader dataReader
? TypeHelper.ConvertToEnumerableDictionary(dataReader).ToList()
: x.Value);
}

private static IDictionary<string, object> GetValuesFromObject(object valueObject)
{
var type = valueObject.GetType();

var propertyValues = type
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Select(property => new { property.Name, Value = property.GetValue(valueObject) });

var fieldValues = type
.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Select(field => new { field.Name, Value = field.GetValue(valueObject) });
Comment on lines +34 to +36
Copy link
Contributor Author

@ramioh ramioh Oct 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old code had a check to exclude a field by name if it was previously added as a property. I removed this check because I can't think how this can ever be true. But please correct me if I am wrong.


return propertyValues
.Concat(fieldValues)
.ToDictionary(x => x.Name, x => x.Value);
}
}
}
Loading