Skip to content

Commit 4cd6d3a

Browse files
EthanEthan
authored andcommitted
fix(sheet): remove and re-add phoneticPr for correct XML order; ensure conditionalFormat is not duplicated
This commit resolves two separate issues in the sheet XML output. First, the phoneticPr element is now explicitly removed and re-added to ensure it appears in the correct order within the XML structure, preventing Excel from misinterpreting the file. Second, the logic for handling conditionalFormat has been adjusted to avoid unintentional duplication of formatting rules. These changes improve the correctness and compatibility of the generated Excel files.
1 parent 84e636e commit 4cd6d3a

File tree

1 file changed

+64
-31
lines changed

1 file changed

+64
-31
lines changed

src/MiniExcel/SaveByTemplate/ExcelOpenXmlTemplate.Impl.cs

Lines changed: 64 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
using System;
44
using System.Collections;
55
using System.Collections.Generic;
6-
using System.ComponentModel;
76
using System.Data;
87
using System.Globalization;
98
using System.IO;
@@ -309,7 +308,6 @@ private void WriteSheetXml(Stream outputFileStream, XmlDocument doc, XmlNode she
309308

310309
var prefix = string.IsNullOrEmpty(sheetData.Prefix) ? "" : $"{sheetData.Prefix}:";
311310
var endPrefix = string.IsNullOrEmpty(sheetData.Prefix) ? "" : $":{sheetData.Prefix}"; // https://user-images.githubusercontent.com/12729184/115000066-fd02b300-9ed4-11eb-8e65-bf0014015134.png
312-
var contents = doc.InnerXml.Split(new[] { $"<{prefix}sheetData>{{{{{{{{{{{{split}}}}}}}}}}}}</{prefix}sheetData>" }, StringSplitOptions.None);
313311

314312
var conditionalFormatNodes = doc.SelectNodes("/x:worksheet/x:conditionalFormatting", _ns);
315313
for (var i = 0; i < conditionalFormatNodes?.Count; ++i)
@@ -318,6 +316,16 @@ private void WriteSheetXml(Stream outputFileStream, XmlDocument doc, XmlNode she
318316
node.ParentNode.RemoveChild(node);
319317
}
320318

319+
var phoneticPr = doc.SelectSingleNode("/x:worksheet/x:phoneticPr", _ns);
320+
var phoneticPrXml = string.Empty;
321+
if (phoneticPr != null)
322+
{
323+
phoneticPrXml = phoneticPr.OuterXml;
324+
phoneticPr.ParentNode.RemoveChild(phoneticPr);
325+
}
326+
327+
var contents = doc.InnerXml.Split(new[] { $"<{prefix}sheetData>{{{{{{{{{{{{split}}}}}}}}}}}}</{prefix}sheetData>" }, StringSplitOptions.None);
328+
321329
using (var writer = new StreamWriter(outputFileStream, Encoding.UTF8))
322330
{
323331
writer.Write(contents[0]);
@@ -516,6 +524,11 @@ private void WriteSheetXml(Stream outputFileStream, XmlDocument doc, XmlNode she
516524
writer.Write($"</{prefix}mergeCells>");
517525
}
518526

527+
if (!string.IsNullOrEmpty(phoneticPrXml))
528+
{
529+
writer.Write(phoneticPrXml);
530+
}
531+
519532
if (newConditionalFormatRanges.Count != 0)
520533
{
521534
writer.Write(string.Join(string.Empty, newConditionalFormatRanges.Select(cf => cf.Node.OuterXml)));
@@ -536,15 +549,15 @@ private void GenerateCellValues(string endPrefix, StreamWriter writer, ref int r
536549
var cleanInnerXml = CleanXml(innerXml, endPrefix);
537550

538551
// https://github.com/mini-software/MiniExcel/issues/771 Saving by template introduces unintended value replication in each row #771
539-
var notFirstRowElement = rowElement.Clone();
552+
var notFirstRowElement = rowElement.Clone();
540553
foreach (XmlElement c in notFirstRowElement.SelectNodes("x:c", _ns))
541554
{
542555
var v = c.SelectSingleNode("x:v", _ns);
543-
if (v != null && !_nonTemplateRegex.IsMatch(v.InnerText))
556+
if (v != null && !_nonTemplateRegex.IsMatch(v.InnerText))
544557
v.InnerText = string.Empty;
545558
}
546559
var cleanNotFirstRowInnerXml = CleanXml(notFirstRowElement.InnerXml, endPrefix);
547-
560+
548561
foreach (var item in rowInfo.CellIEnumerableValues)
549562
{
550563
iEnumerableIndex++;
@@ -722,7 +735,7 @@ private void GenerateCellValues(string endPrefix, StreamWriter writer, ref int r
722735
// note: only first time need add diff https://user-images.githubusercontent.com/12729184/114494728-6bceda80-9c4f-11eb-9685-8b5ed054eabe.png
723736
if (!isFirst)
724737
rowIndexDiff += rowInfo.IEnumerableMercell?.Height ?? 1; //TODO:base on the merge size
725-
738+
726739
if (isFirst)
727740
{
728741
// https://github.com/mini-software/MiniExcel/issues/771 Saving by template introduces unintended value replication in each row #771
@@ -1003,13 +1016,13 @@ private void UpdateDimensionAndGetRowsInfo(IDictionary<string, object> inputMaps
10031016
else
10041017
{
10051018
// ==== add dimension element if not found ====
1006-
1019+
10071020
var firstRow = rows[0].SelectNodes("x:c", _ns);
10081021
var lastRow = rows[rows.Count - 1].SelectNodes("x:c", _ns);
1009-
1022+
10101023
var dimStart = ((XmlElement)firstRow?[0])?.GetAttribute("r");
10111024
var dimEnd = ((XmlElement)lastRow?[lastRow.Count - 1])?.GetAttribute("r");
1012-
1025+
10131026
refs = new[] { dimStart, dimEnd };
10141027

10151028
dimension = (XmlElement)doc.CreateNode(XmlNodeType.Element, "dimension", null);
@@ -1021,14 +1034,14 @@ private void UpdateDimensionAndGetRowsInfo(IDictionary<string, object> inputMaps
10211034
foreach (XmlElement row in rows)
10221035
{
10231036
// ==== get ienumerable infomation & maxrowindexdiff ====
1024-
1037+
10251038
var xRowInfo = new XRowInfo { Row = row };
10261039
_xRowInfos.Add(xRowInfo);
10271040

10281041
foreach (XmlElement c in row.SelectNodes("x:c", _ns))
10291042
{
10301043
var r = c.GetAttribute("r");
1031-
1044+
10321045
// ==== mergecells ====
10331046
if (_xMergeCellInfos.TryGetValue(r, out var merCell))
10341047
{
@@ -1285,44 +1298,64 @@ private static bool EvaluateStatement(object tagValue, string comparisonOperator
12851298
case double dtg when double.TryParse(value, out var doubleNumber):
12861299
switch (comparisonOperator)
12871300
{
1288-
case "==": return dtg.Equals(doubleNumber);
1289-
case "!=": return !dtg.Equals(doubleNumber);
1290-
case ">": return dtg > doubleNumber;
1291-
case "<": return dtg < doubleNumber;
1292-
case ">=": return dtg >= doubleNumber;
1293-
case "<=": return dtg <= doubleNumber;
1301+
case "==":
1302+
return dtg.Equals(doubleNumber);
1303+
case "!=":
1304+
return !dtg.Equals(doubleNumber);
1305+
case ">":
1306+
return dtg > doubleNumber;
1307+
case "<":
1308+
return dtg < doubleNumber;
1309+
case ">=":
1310+
return dtg >= doubleNumber;
1311+
case "<=":
1312+
return dtg <= doubleNumber;
12941313
}
12951314
break;
12961315

12971316
case int itg when int.TryParse(value, out var intNumber):
12981317
switch (comparisonOperator)
12991318
{
1300-
case "==": return itg.Equals(intNumber);
1301-
case "!=": return !itg.Equals(intNumber);
1302-
case ">": return itg > intNumber;
1303-
case "<": return itg < intNumber;
1304-
case ">=": return itg >= intNumber;
1305-
case "<=": return itg <= intNumber;
1319+
case "==":
1320+
return itg.Equals(intNumber);
1321+
case "!=":
1322+
return !itg.Equals(intNumber);
1323+
case ">":
1324+
return itg > intNumber;
1325+
case "<":
1326+
return itg < intNumber;
1327+
case ">=":
1328+
return itg >= intNumber;
1329+
case "<=":
1330+
return itg <= intNumber;
13061331
}
13071332
break;
13081333

13091334
case DateTime dttg when DateTime.TryParse(value, out var date):
13101335
switch (comparisonOperator)
13111336
{
1312-
case "==": return dttg.Equals(date);
1313-
case "!=": return !dttg.Equals(date);
1314-
case ">": return dttg > date;
1315-
case "<": return dttg < date;
1316-
case ">=": return dttg >= date;
1317-
case "<=": return dttg <= date;
1337+
case "==":
1338+
return dttg.Equals(date);
1339+
case "!=":
1340+
return !dttg.Equals(date);
1341+
case ">":
1342+
return dttg > date;
1343+
case "<":
1344+
return dttg < date;
1345+
case ">=":
1346+
return dttg >= date;
1347+
case "<=":
1348+
return dttg <= date;
13181349
}
13191350
break;
13201351

13211352
case string stg:
13221353
switch (comparisonOperator)
13231354
{
1324-
case "==": return stg == value;
1325-
case "!=": return stg != value;
1355+
case "==":
1356+
return stg == value;
1357+
case "!=":
1358+
return stg != value;
13261359
}
13271360
break;
13281361
}

0 commit comments

Comments
 (0)