mirror of
https://gitee.com/dotnetchina/MiniExcel.git
synced 2024-11-29 18:38:08 +08:00
Fix Issue 632, refactor sheet styles (#640)
* fix for issue 606 * fix formatting * add test * refactor sheet styles, fix #632 * change tabs to spaces
This commit is contained in:
parent
228b3c180f
commit
67e97f36b5
@ -1,9 +1,4 @@
|
|||||||
using MiniExcelLibs.Attributes;
|
using MiniExcelLibs.OpenXml.Models;
|
||||||
using MiniExcelLibs.OpenXml.Models;
|
|
||||||
using MiniExcelLibs.Utils;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace MiniExcelLibs.OpenXml.Constants
|
namespace MiniExcelLibs.OpenXml.Constants
|
||||||
{
|
{
|
||||||
@ -11,15 +6,13 @@ namespace MiniExcelLibs.OpenXml.Constants
|
|||||||
{
|
{
|
||||||
static ExcelXml()
|
static ExcelXml()
|
||||||
{
|
{
|
||||||
DefaultRels = MinifyXml(DefaultRels);
|
DefaultRels = ExcelOpenXmlUtils.MinifyXml( DefaultRels);
|
||||||
DefaultWorkbookXml = MinifyXml(DefaultWorkbookXml);
|
DefaultWorkbookXml = ExcelOpenXmlUtils.MinifyXml(DefaultWorkbookXml);
|
||||||
DefaultStylesXml = MinifyXml(DefaultStylesXml);
|
DefaultWorkbookXmlRels = ExcelOpenXmlUtils.MinifyXml(DefaultWorkbookXmlRels);
|
||||||
DefaultWorkbookXmlRels = MinifyXml(DefaultWorkbookXmlRels);
|
DefaultSheetRelXml = ExcelOpenXmlUtils.MinifyXml(DefaultSheetRelXml);
|
||||||
DefaultSheetRelXml = MinifyXml(DefaultSheetRelXml);
|
DefaultDrawing = ExcelOpenXmlUtils.MinifyXml(DefaultDrawing);
|
||||||
DefaultDrawing = MinifyXml(DefaultDrawing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string MinifyXml(string xml) => xml.Replace("\r", "").Replace("\n", "").Replace("\t", "");
|
|
||||||
|
|
||||||
internal static readonly string EmptySheetXml = $@"<?xml version=""1.0"" encoding=""utf-8""?><x:worksheet xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main""><x:dimension ref=""A1""/><x:sheetData></x:sheetData></x:worksheet>";
|
internal static readonly string EmptySheetXml = $@"<?xml version=""1.0"" encoding=""utf-8""?><x:worksheet xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main""><x:dimension ref=""A1""/><x:sheetData></x:sheetData></x:worksheet>";
|
||||||
|
|
||||||
@ -35,146 +28,6 @@ namespace MiniExcelLibs.OpenXml.Constants
|
|||||||
<Relationship Type=""http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"" Target=""/xl/sharedStrings.xml"" Id=""R3db9602ace778fdb"" />
|
<Relationship Type=""http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"" Target=""/xl/sharedStrings.xml"" Id=""R3db9602ace778fdb"" />
|
||||||
</Relationships>";
|
</Relationships>";
|
||||||
|
|
||||||
internal static readonly string NoneStylesXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
|
||||||
<x:styleSheet xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
|
|
||||||
<x:fonts>
|
|
||||||
<x:font />
|
|
||||||
</x:fonts>
|
|
||||||
<x:fills>
|
|
||||||
<x:fill />
|
|
||||||
</x:fills>
|
|
||||||
<x:borders>
|
|
||||||
<x:border />
|
|
||||||
</x:borders>
|
|
||||||
<x:cellStyleXfs>
|
|
||||||
<x:xf />
|
|
||||||
</x:cellStyleXfs>
|
|
||||||
<x:cellXfs>
|
|
||||||
<x:xf />
|
|
||||||
<x:xf />
|
|
||||||
<x:xf />
|
|
||||||
<x:xf numFmtId=""14"" applyNumberFormat=""1"" />
|
|
||||||
</x:cellXfs>
|
|
||||||
</x:styleSheet>";
|
|
||||||
|
|
||||||
#region StyleSheet
|
|
||||||
|
|
||||||
private const int startUpNumFmts = 1;
|
|
||||||
private const string NumFmtsToken = "{{numFmts}}";
|
|
||||||
private const string NumFmtsCountToken = "{{numFmtCount}}";
|
|
||||||
|
|
||||||
private const int startUpCellXfs = 5;
|
|
||||||
private const string cellXfsToken = "{{cellXfs}}";
|
|
||||||
private const string cellXfsCountToken = "{{cellXfsCount}}";
|
|
||||||
|
|
||||||
internal static readonly string DefaultStylesXml = $@"<?xml version=""1.0"" encoding=""utf-8""?>
|
|
||||||
<x:styleSheet xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
|
|
||||||
<x:numFmts count=""{NumFmtsCountToken}"">
|
|
||||||
<x:numFmt numFmtId=""0"" formatCode="""" />
|
|
||||||
{NumFmtsToken}
|
|
||||||
</x:numFmts>
|
|
||||||
<x:fonts count=""2"">
|
|
||||||
<x:font>
|
|
||||||
<x:vertAlign val=""baseline"" />
|
|
||||||
<x:sz val=""11"" />
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
<x:name val=""Calibri"" />
|
|
||||||
<x:family val=""2"" />
|
|
||||||
</x:font>
|
|
||||||
<x:font>
|
|
||||||
<x:vertAlign val=""baseline"" />
|
|
||||||
<x:sz val=""11"" />
|
|
||||||
<x:color rgb=""FFFFFFFF"" />
|
|
||||||
<x:name val=""Calibri"" />
|
|
||||||
<x:family val=""2"" />
|
|
||||||
</x:font>
|
|
||||||
</x:fonts>
|
|
||||||
<x:fills count=""3"">
|
|
||||||
<x:fill>
|
|
||||||
<x:patternFill patternType=""none"" />
|
|
||||||
</x:fill>
|
|
||||||
<x:fill>
|
|
||||||
<x:patternFill patternType=""gray125"" />
|
|
||||||
</x:fill>
|
|
||||||
<x:fill>
|
|
||||||
<x:patternFill patternType=""solid"">
|
|
||||||
<x:fgColor rgb=""284472C4"" />
|
|
||||||
</x:patternFill>
|
|
||||||
</x:fill>
|
|
||||||
</x:fills>
|
|
||||||
<x:borders count=""2"">
|
|
||||||
<x:border diagonalUp=""0"" diagonalDown=""0"">
|
|
||||||
<x:left style=""none"">
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
</x:left>
|
|
||||||
<x:right style=""none"">
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
</x:right>
|
|
||||||
<x:top style=""none"">
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
</x:top>
|
|
||||||
<x:bottom style=""none"">
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
</x:bottom>
|
|
||||||
<x:diagonal style=""none"">
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
</x:diagonal>
|
|
||||||
</x:border>
|
|
||||||
<x:border diagonalUp=""0"" diagonalDown=""0"">
|
|
||||||
<x:left style=""thin"">
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
</x:left>
|
|
||||||
<x:right style=""thin"">
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
</x:right>
|
|
||||||
<x:top style=""thin"">
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
</x:top>
|
|
||||||
<x:bottom style=""thin"">
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
</x:bottom>
|
|
||||||
<x:diagonal style=""none"">
|
|
||||||
<x:color rgb=""FF000000"" />
|
|
||||||
</x:diagonal>
|
|
||||||
</x:border>
|
|
||||||
</x:borders>
|
|
||||||
<x:cellStyleXfs count=""3"">
|
|
||||||
<x:xf numFmtId=""0"" fontId=""0"" fillId=""0"" borderId=""0"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""0"" applyAlignment=""1"" applyProtection=""1"">
|
|
||||||
<x:protection locked=""1"" hidden=""0"" />
|
|
||||||
</x:xf>
|
|
||||||
<x:xf numFmtId=""14"" fontId=""1"" fillId=""2"" borderId=""1"" applyNumberFormat=""1"" applyFill=""0"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
|
||||||
<x:protection locked=""1"" hidden=""0"" />
|
|
||||||
</x:xf>
|
|
||||||
<x:xf numFmtId=""0"" fontId=""0"" fillId=""0"" borderId=""1"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
|
||||||
<x:protection locked=""1"" hidden=""0"" />
|
|
||||||
</x:xf>
|
|
||||||
</x:cellStyleXfs>
|
|
||||||
<x:cellXfs count=""{cellXfsCountToken}"">
|
|
||||||
<x:xf></x:xf>
|
|
||||||
<x:xf numFmtId=""0"" fontId=""1"" fillId=""2"" borderId=""1"" xfId=""0"" applyNumberFormat=""1"" applyFill=""0"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
|
||||||
<x:alignment horizontal=""left"" vertical=""bottom"" textRotation=""0"" wrapText=""0"" indent=""0"" relativeIndent=""0"" justifyLastLine=""0"" shrinkToFit=""0"" readingOrder=""0"" />
|
|
||||||
<x:protection locked=""1"" hidden=""0"" />
|
|
||||||
</x:xf>
|
|
||||||
<x:xf numFmtId=""0"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
|
||||||
<x:alignment horizontal=""general"" vertical=""bottom"" textRotation=""0"" wrapText=""0"" indent=""0"" relativeIndent=""0"" justifyLastLine=""0"" shrinkToFit=""0"" readingOrder=""0"" />
|
|
||||||
<x:protection locked=""1"" hidden=""0"" />
|
|
||||||
</x:xf>
|
|
||||||
<x:xf numFmtId=""14"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
|
||||||
<x:alignment horizontal=""general"" vertical=""bottom"" textRotation=""0"" wrapText=""0"" indent=""0"" relativeIndent=""0"" justifyLastLine=""0"" shrinkToFit=""0"" readingOrder=""0"" />
|
|
||||||
<x:protection locked=""1"" hidden=""0"" />
|
|
||||||
</x:xf>
|
|
||||||
<x:xf numFmtId=""0"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyBorder=""1"" applyAlignment=""1"">
|
|
||||||
<x:alignment horizontal=""fill""/>
|
|
||||||
</x:xf>
|
|
||||||
{cellXfsToken}
|
|
||||||
</x:cellXfs>
|
|
||||||
<x:cellStyles count=""1"">
|
|
||||||
<x:cellStyle name=""Normal"" xfId=""0"" builtinId=""0"" />
|
|
||||||
</x:cellStyles>
|
|
||||||
</x:styleSheet>";
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
internal static readonly string DefaultWorkbookXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
internal static readonly string DefaultWorkbookXml = @"<?xml version=""1.0"" encoding=""utf-8""?>
|
||||||
<x:workbook xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships""
|
<x:workbook xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships""
|
||||||
xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
|
xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
|
||||||
@ -251,51 +104,6 @@ namespace MiniExcelLibs.OpenXml.Constants
|
|||||||
internal static string Sheet(SheetDto sheetDto, int sheetId)
|
internal static string Sheet(SheetDto sheetDto, int sheetId)
|
||||||
=> $@"<x:sheet name=""{ExcelOpenXmlUtils.EncodeXML(sheetDto.Name)}"" sheetId=""{sheetId}""{(string.IsNullOrWhiteSpace(sheetDto.State) ? string.Empty : $" state=\"{sheetDto.State}\"")} r:id=""{sheetDto.ID}"" />";
|
=> $@"<x:sheet name=""{ExcelOpenXmlUtils.EncodeXML(sheetDto.Name)}"" sheetId=""{sheetId}""{(string.IsNullOrWhiteSpace(sheetDto.State) ? string.Empty : $" state=\"{sheetDto.State}\"")} r:id=""{sheetDto.ID}"" />";
|
||||||
|
|
||||||
internal static string SetupStyleXml(string styleXml, ICollection<ExcelColumnAttribute> columns)
|
|
||||||
{
|
|
||||||
const int numFmtIndex = 166;
|
|
||||||
|
|
||||||
var sb = new StringBuilder(styleXml);
|
|
||||||
var columnsToApply = GenerateStyleIds(columns);
|
|
||||||
|
|
||||||
var numFmts = columnsToApply.Select((x, i) =>
|
|
||||||
{
|
|
||||||
return new
|
|
||||||
{
|
|
||||||
numFmt =
|
|
||||||
$@"<x:numFmt numFmtId=""{numFmtIndex + i}"" formatCode=""{x.Format}"" />",
|
|
||||||
|
|
||||||
cellXfs =
|
|
||||||
$@"<x:xf numFmtId=""{numFmtIndex + i}"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
|
||||||
<x:alignment horizontal=""general"" vertical=""bottom"" textRotation=""0"" wrapText=""0"" indent=""0"" relativeIndent=""0"" justifyLastLine=""0"" shrinkToFit=""0"" readingOrder=""0"" />
|
|
||||||
<x:protection locked=""1"" hidden=""0"" />
|
|
||||||
</x:xf>"
|
|
||||||
};
|
|
||||||
}).ToArray();
|
|
||||||
|
|
||||||
sb.Replace(NumFmtsToken, string.Join(string.Empty, numFmts.Select(x => x.numFmt)));
|
|
||||||
sb.Replace(NumFmtsCountToken, (startUpNumFmts + numFmts.Length).ToString());
|
|
||||||
|
|
||||||
sb.Replace(cellXfsToken, string.Join(string.Empty, numFmts.Select(x => x.cellXfs)));
|
|
||||||
sb.Replace(cellXfsCountToken, (5 + numFmts.Length).ToString());
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<ExcelColumnAttribute> GenerateStyleIds(ICollection<ExcelColumnAttribute> dynamicColumns)
|
|
||||||
{
|
|
||||||
if (dynamicColumns == null)
|
|
||||||
yield break;
|
|
||||||
|
|
||||||
int index = 0;
|
|
||||||
foreach (var g in dynamicColumns?.Where(x => !string.IsNullOrWhiteSpace(x.Format) && new ExcelNumberFormat(x.Format).IsValid).GroupBy(x => x.Format))
|
|
||||||
{
|
|
||||||
foreach (var col in g)
|
|
||||||
col.FormatId = startUpCellXfs + index;
|
|
||||||
|
|
||||||
yield return g.First();
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using MiniExcelLibs.Attributes;
|
using MiniExcelLibs.Attributes;
|
||||||
using MiniExcelLibs.OpenXml.Constants;
|
using MiniExcelLibs.OpenXml.Constants;
|
||||||
using MiniExcelLibs.OpenXml.Models;
|
using MiniExcelLibs.OpenXml.Models;
|
||||||
|
using MiniExcelLibs.OpenXml.Styles;
|
||||||
using MiniExcelLibs.Utils;
|
using MiniExcelLibs.Utils;
|
||||||
using MiniExcelLibs.Zip;
|
using MiniExcelLibs.Zip;
|
||||||
using System;
|
using System;
|
||||||
@ -364,9 +365,9 @@ namespace MiniExcelLibs.OpenXml
|
|||||||
switch (_configuration.TableStyles)
|
switch (_configuration.TableStyles)
|
||||||
{
|
{
|
||||||
case TableStyles.None:
|
case TableStyles.None:
|
||||||
return ExcelXml.SetupStyleXml(ExcelXml.NoneStylesXml, columns);
|
return new MinimalSheetStyleBuilder().Build( columns);
|
||||||
case TableStyles.Default:
|
case TableStyles.Default:
|
||||||
return ExcelXml.SetupStyleXml(ExcelXml.DefaultStylesXml, columns);
|
return new DefaultSheetStyleBuilder().Build( columns );
|
||||||
default:
|
default:
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@
|
|||||||
#endif
|
#endif
|
||||||
static class ExcelOpenXmlUtils
|
static class ExcelOpenXmlUtils
|
||||||
{
|
{
|
||||||
|
public static string MinifyXml( string xml ) => xml.Replace( "\r", "" ).Replace( "\n", "" ).Replace( "\t", "" ).Trim();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Encode to XML (special characteres: ' " > < &)
|
/// Encode to XML (special characteres: ' " > < &)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
156
src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs
Normal file
156
src/MiniExcel/OpenXml/Styles/DefaultSheetStyleBuilder.cs
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
using MiniExcelLibs.Attributes;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MiniExcelLibs.OpenXml.Styles {
|
||||||
|
|
||||||
|
public class DefaultSheetStyleBuilder : ISheetStyleBuilder
|
||||||
|
{
|
||||||
|
private const int startUpNumFmts = 1;
|
||||||
|
private const string NumFmtsToken = "{{numFmts}}";
|
||||||
|
private const string NumFmtsCountToken = "{{numFmtCount}}";
|
||||||
|
|
||||||
|
private const int startUpCellXfs = 5;
|
||||||
|
private const string cellXfsToken = "{{cellXfs}}";
|
||||||
|
private const string cellXfsCountToken = "{{cellXfsCount}}";
|
||||||
|
|
||||||
|
internal static readonly string DefaultStylesXml = ExcelOpenXmlUtils.MinifyXml
|
||||||
|
( $@"
|
||||||
|
<?xml version=""1.0"" encoding=""utf-8""?>
|
||||||
|
<x:styleSheet xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
|
||||||
|
<x:numFmts count=""{NumFmtsCountToken}"">
|
||||||
|
<x:numFmt numFmtId=""0"" formatCode="""" />
|
||||||
|
{NumFmtsToken}
|
||||||
|
</x:numFmts>
|
||||||
|
<x:fonts count=""2"">
|
||||||
|
<x:font>
|
||||||
|
<x:vertAlign val=""baseline"" />
|
||||||
|
<x:sz val=""11"" />
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
<x:name val=""Calibri"" />
|
||||||
|
<x:family val=""2"" />
|
||||||
|
</x:font>
|
||||||
|
<x:font>
|
||||||
|
<x:vertAlign val=""baseline"" />
|
||||||
|
<x:sz val=""11"" />
|
||||||
|
<x:color rgb=""FFFFFFFF"" />
|
||||||
|
<x:name val=""Calibri"" />
|
||||||
|
<x:family val=""2"" />
|
||||||
|
</x:font>
|
||||||
|
</x:fonts>
|
||||||
|
<x:fills count=""3"">
|
||||||
|
<x:fill>
|
||||||
|
<x:patternFill patternType=""none"" />
|
||||||
|
</x:fill>
|
||||||
|
<x:fill>
|
||||||
|
<x:patternFill patternType=""gray125"" />
|
||||||
|
</x:fill>
|
||||||
|
<x:fill>
|
||||||
|
<x:patternFill patternType=""solid"">
|
||||||
|
<x:fgColor rgb=""284472C4"" />
|
||||||
|
</x:patternFill>
|
||||||
|
</x:fill>
|
||||||
|
</x:fills>
|
||||||
|
<x:borders count=""2"">
|
||||||
|
<x:border diagonalUp=""0"" diagonalDown=""0"">
|
||||||
|
<x:left style=""none"">
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
</x:left>
|
||||||
|
<x:right style=""none"">
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
</x:right>
|
||||||
|
<x:top style=""none"">
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
</x:top>
|
||||||
|
<x:bottom style=""none"">
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
</x:bottom>
|
||||||
|
<x:diagonal style=""none"">
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
</x:diagonal>
|
||||||
|
</x:border>
|
||||||
|
<x:border diagonalUp=""0"" diagonalDown=""0"">
|
||||||
|
<x:left style=""thin"">
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
</x:left>
|
||||||
|
<x:right style=""thin"">
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
</x:right>
|
||||||
|
<x:top style=""thin"">
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
</x:top>
|
||||||
|
<x:bottom style=""thin"">
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
</x:bottom>
|
||||||
|
<x:diagonal style=""none"">
|
||||||
|
<x:color rgb=""FF000000"" />
|
||||||
|
</x:diagonal>
|
||||||
|
</x:border>
|
||||||
|
</x:borders>
|
||||||
|
<x:cellStyleXfs count=""3"">
|
||||||
|
<x:xf numFmtId=""0"" fontId=""0"" fillId=""0"" borderId=""0"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""0"" applyAlignment=""1"" applyProtection=""1"">
|
||||||
|
<x:protection locked=""1"" hidden=""0"" />
|
||||||
|
</x:xf>
|
||||||
|
<x:xf numFmtId=""14"" fontId=""1"" fillId=""2"" borderId=""1"" applyNumberFormat=""1"" applyFill=""0"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
||||||
|
<x:protection locked=""1"" hidden=""0"" />
|
||||||
|
</x:xf>
|
||||||
|
<x:xf numFmtId=""0"" fontId=""0"" fillId=""0"" borderId=""1"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
||||||
|
<x:protection locked=""1"" hidden=""0"" />
|
||||||
|
</x:xf>
|
||||||
|
</x:cellStyleXfs>
|
||||||
|
<x:cellXfs count=""{cellXfsCountToken}"">
|
||||||
|
<x:xf></x:xf>
|
||||||
|
<x:xf numFmtId=""0"" fontId=""1"" fillId=""2"" borderId=""1"" xfId=""0"" applyNumberFormat=""1"" applyFill=""0"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
||||||
|
<x:alignment horizontal=""left"" vertical=""bottom"" textRotation=""0"" wrapText=""0"" indent=""0"" relativeIndent=""0"" justifyLastLine=""0"" shrinkToFit=""0"" readingOrder=""0"" />
|
||||||
|
<x:protection locked=""1"" hidden=""0"" />
|
||||||
|
</x:xf>
|
||||||
|
<x:xf numFmtId=""0"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
||||||
|
<x:alignment horizontal=""general"" vertical=""bottom"" textRotation=""0"" wrapText=""0"" indent=""0"" relativeIndent=""0"" justifyLastLine=""0"" shrinkToFit=""0"" readingOrder=""0"" />
|
||||||
|
<x:protection locked=""1"" hidden=""0"" />
|
||||||
|
</x:xf>
|
||||||
|
<x:xf numFmtId=""14"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
||||||
|
<x:alignment horizontal=""general"" vertical=""bottom"" textRotation=""0"" wrapText=""0"" indent=""0"" relativeIndent=""0"" justifyLastLine=""0"" shrinkToFit=""0"" readingOrder=""0"" />
|
||||||
|
<x:protection locked=""1"" hidden=""0"" />
|
||||||
|
</x:xf>
|
||||||
|
<x:xf numFmtId=""0"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyBorder=""1"" applyAlignment=""1"">
|
||||||
|
<x:alignment horizontal=""fill""/>
|
||||||
|
</x:xf>
|
||||||
|
{cellXfsToken}
|
||||||
|
</x:cellXfs>
|
||||||
|
<x:cellStyles count=""1"">
|
||||||
|
<x:cellStyle name=""Normal"" xfId=""0"" builtinId=""0"" />
|
||||||
|
</x:cellStyles>
|
||||||
|
</x:styleSheet>"
|
||||||
|
);
|
||||||
|
|
||||||
|
public string Build( ICollection<ExcelColumnAttribute> columns )
|
||||||
|
{
|
||||||
|
const int numFmtIndex = 166;
|
||||||
|
|
||||||
|
var sb = new StringBuilder( DefaultStylesXml );
|
||||||
|
var columnsToApply = SheetStyleBuilderHelper.GenerateStyleIds( startUpCellXfs, columns );
|
||||||
|
|
||||||
|
var numFmts = columnsToApply.Select( ( x, i ) =>
|
||||||
|
{
|
||||||
|
return new
|
||||||
|
{
|
||||||
|
numFmt = $@"<x:numFmt numFmtId=""{numFmtIndex + i}"" formatCode=""{x.Format}"" />",
|
||||||
|
|
||||||
|
cellXfs = $@"<x:xf numFmtId=""{numFmtIndex + i}"" fontId=""0"" fillId=""0"" borderId=""1"" xfId=""0"" applyNumberFormat=""1"" applyFill=""1"" applyBorder=""1"" applyAlignment=""1"" applyProtection=""1"">
|
||||||
|
<x:alignment horizontal=""general"" vertical=""bottom"" textRotation=""0"" wrapText=""0"" indent=""0"" relativeIndent=""0"" justifyLastLine=""0"" shrinkToFit=""0"" readingOrder=""0"" />
|
||||||
|
<x:protection locked=""1"" hidden=""0"" />
|
||||||
|
</x:xf>"
|
||||||
|
};
|
||||||
|
} ).ToArray();
|
||||||
|
|
||||||
|
sb.Replace( NumFmtsToken, string.Join( string.Empty, numFmts.Select( x => x.numFmt ) ) );
|
||||||
|
sb.Replace( NumFmtsCountToken, (startUpNumFmts + numFmts.Length).ToString() );
|
||||||
|
|
||||||
|
sb.Replace( cellXfsToken, string.Join( string.Empty, numFmts.Select( x => x.cellXfs ) ) );
|
||||||
|
sb.Replace( cellXfsCountToken, (5 + numFmts.Length).ToString() );
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
src/MiniExcel/OpenXml/Styles/ISheetStyleBuilder.cs
Normal file
10
src/MiniExcel/OpenXml/Styles/ISheetStyleBuilder.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using MiniExcelLibs.Attributes;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MiniExcelLibs.OpenXml.Styles {
|
||||||
|
public interface ISheetStyleBuilder
|
||||||
|
{
|
||||||
|
string Build( ICollection<ExcelColumnAttribute> columns );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
71
src/MiniExcel/OpenXml/Styles/MinimalSheetStyleBuilder.cs
Normal file
71
src/MiniExcel/OpenXml/Styles/MinimalSheetStyleBuilder.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
using MiniExcelLibs.Attributes;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MiniExcelLibs.OpenXml.Styles {
|
||||||
|
public class MinimalSheetStyleBuilder : ISheetStyleBuilder
|
||||||
|
{
|
||||||
|
private const int startUpNumFmts = 1;
|
||||||
|
private const string NumFmtsToken = "{{numFmts}}";
|
||||||
|
private const string NumFmtsCountToken = "{{numFmtCount}}";
|
||||||
|
|
||||||
|
private const int startUpCellXfs = 5;
|
||||||
|
private const string cellXfsToken = "{{cellXfs}}";
|
||||||
|
private const string cellXfsCountToken = "{{cellXfsCount}}";
|
||||||
|
|
||||||
|
internal static readonly string NoneStylesXml = ExcelOpenXmlUtils.MinifyXml
|
||||||
|
( $@"
|
||||||
|
<?xml version=""1.0"" encoding=""utf-8""?>
|
||||||
|
<x:styleSheet xmlns:x=""http://schemas.openxmlformats.org/spreadsheetml/2006/main"">
|
||||||
|
<x:numFmts count=""{NumFmtsCountToken}"">
|
||||||
|
<x:numFmt numFmtId=""0"" formatCode="""" />
|
||||||
|
{NumFmtsToken}
|
||||||
|
</x:numFmts>
|
||||||
|
<x:fonts>
|
||||||
|
<x:font />
|
||||||
|
</x:fonts>
|
||||||
|
<x:fills>
|
||||||
|
<x:fill />
|
||||||
|
</x:fills>
|
||||||
|
<x:borders>
|
||||||
|
<x:border />
|
||||||
|
</x:borders>
|
||||||
|
<x:cellStyleXfs>
|
||||||
|
<x:xf />
|
||||||
|
</x:cellStyleXfs>
|
||||||
|
<x:cellXfs count=""{cellXfsCountToken}"">
|
||||||
|
<x:xf />
|
||||||
|
<x:xf />
|
||||||
|
<x:xf />
|
||||||
|
<x:xf numFmtId=""14"" applyNumberFormat=""1"" />
|
||||||
|
<x:xf />
|
||||||
|
{cellXfsToken}
|
||||||
|
</x:cellXfs>
|
||||||
|
</x:styleSheet>"
|
||||||
|
);
|
||||||
|
|
||||||
|
public string Build( ICollection<ExcelColumnAttribute> columns )
|
||||||
|
{
|
||||||
|
const int numFmtIndex = 166;
|
||||||
|
|
||||||
|
var sb = new StringBuilder( NoneStylesXml );
|
||||||
|
var columnsToApply = SheetStyleBuilderHelper.GenerateStyleIds( startUpCellXfs, columns );
|
||||||
|
|
||||||
|
var numFmts = columnsToApply.Select( ( x, i ) => {
|
||||||
|
return new {
|
||||||
|
numFmt = $@"<x:numFmt numFmtId=""{numFmtIndex + i}"" formatCode=""{x.Format}"" />",
|
||||||
|
cellXfs = $@"<x:xf numFmtId=""{numFmtIndex + i}"" applyNumberFormat=""1"" />"
|
||||||
|
};
|
||||||
|
} ).ToArray();
|
||||||
|
|
||||||
|
sb.Replace( NumFmtsToken, string.Join( string.Empty, numFmts.Select( x => x.numFmt ) ) );
|
||||||
|
sb.Replace( NumFmtsCountToken, (startUpNumFmts + numFmts.Length).ToString() );
|
||||||
|
|
||||||
|
sb.Replace( cellXfsToken, string.Join( string.Empty, numFmts.Select( x => x.cellXfs ) ) );
|
||||||
|
sb.Replace( cellXfsCountToken, (5 + numFmts.Length).ToString() );
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
src/MiniExcel/OpenXml/Styles/SheetStyleBuilderHelper.cs
Normal file
24
src/MiniExcel/OpenXml/Styles/SheetStyleBuilderHelper.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using MiniExcelLibs.Attributes;
|
||||||
|
using MiniExcelLibs.Utils;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace MiniExcelLibs.OpenXml.Styles {
|
||||||
|
public static class SheetStyleBuilderHelper
|
||||||
|
{
|
||||||
|
public static IEnumerable<ExcelColumnAttribute> GenerateStyleIds( int startUpCellXfs, ICollection<ExcelColumnAttribute> dynamicColumns ) {
|
||||||
|
if ( dynamicColumns == null )
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
foreach ( var g in dynamicColumns?.Where( x => !string.IsNullOrWhiteSpace( x.Format ) && new ExcelNumberFormat( x.Format ).IsValid ).GroupBy( x => x.Format ) ) {
|
||||||
|
foreach ( var col in g )
|
||||||
|
col.FormatId = startUpCellXfs + index;
|
||||||
|
|
||||||
|
yield return g.First();
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
using Dapper;
|
using Dapper;
|
||||||
using MiniExcelLibs.Attributes;
|
using MiniExcelLibs.Attributes;
|
||||||
using MiniExcelLibs.Csv;
|
using MiniExcelLibs.Csv;
|
||||||
using MiniExcelLibs.Exceptions;
|
using MiniExcelLibs.Exceptions;
|
||||||
@ -3692,5 +3692,47 @@ MyProperty4,MyProperty1,MyProperty5,MyProperty2,MyProperty6,,MyProperty3
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void Issue632_1()
|
||||||
|
{
|
||||||
|
//https://github.com/mini-software/MiniExcel/issues/632
|
||||||
|
var values = new List<Dictionary<string, object>>();
|
||||||
|
|
||||||
|
foreach ( var item in Enumerable.Range( 1, 100 ) ) {
|
||||||
|
var dict = new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
{ "Id", item },
|
||||||
|
{ "Time", DateTime.Now.ToLocalTime() },
|
||||||
|
{ "CPU Usage (%)", Math.Round( 56.345, 1 ) },
|
||||||
|
{ "Memory Usage (%)", Math.Round( 98.234, 1 ) },
|
||||||
|
{ "Disk Usage (%)", Math.Round( 32.456, 1 ) },
|
||||||
|
{ "CPU Temperature (°C)", Math.Round( 74.234, 1 ) },
|
||||||
|
{ "Voltage (V)", Math.Round( 6.3223, 1 ) },
|
||||||
|
{ "Network Usage (Kb/s)", Math.Round( 4503.23422, 1 ) },
|
||||||
|
{ "Instrument", "QT800050" }
|
||||||
|
};
|
||||||
|
values.Add( dict );
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = new OpenXmlConfiguration
|
||||||
|
{
|
||||||
|
TableStyles = TableStyles.None,
|
||||||
|
DynamicColumns = new DynamicExcelColumn[]
|
||||||
|
{
|
||||||
|
//new DynamicExcelColumn("Time") { Index = 0, Width = 20, Format = CultureInfo.CurrentCulture.DateTimeFormat.ShortDatePattern + " " + CultureInfo.CurrentCulture.DateTimeFormat.LongTimePattern },
|
||||||
|
//new DynamicExcelColumn("Time") { Index = 0, Width = 20, Format = CultureInfo.InvariantCulture.DateTimeFormat.ShortDatePattern + " " + CultureInfo.InvariantCulture.DateTimeFormat.LongTimePattern },
|
||||||
|
//new DynamicExcelColumn("Time") { Index = 0, Width = 20 },
|
||||||
|
new DynamicExcelColumn("Time") { Index = 0, Width = 20, Format = "d.MM.yyyy" },
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var path = Path.Combine(
|
||||||
|
Path.GetTempPath(),
|
||||||
|
string.Concat( nameof( MiniExcelIssueTests ), "_", nameof( Issue632_1 ), ".xlsx" )
|
||||||
|
);
|
||||||
|
|
||||||
|
MiniExcel.SaveAs( path, values, excelType: ExcelType.XLSX, configuration: config, overwriteFile: true );
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user