fix(xlsx): strip leading = from definedName ref

Per ECMA-376 §18.2.5, the content of <x:definedName> must not carry a
leading '=' — that form is specific to Excel's formula bar, not the
serialized OOXML. When users passed `--prop ref==SUM(Sheet1!A1:A5)`
(copied verbatim from the formula bar), Excel rejected the file on
open with 0x800A03EC.

Strip exactly one leading '=' before writing the definedName body.
This commit is contained in:
zmworm 2026-04-19 01:41:18 +08:00
parent e53be91ea7
commit 4d29ce1603

View file

@ -535,6 +535,11 @@ public partial class ExcelHandler
var refVal = properties.GetValueOrDefault("ref",
properties.GetValueOrDefault("refersTo",
properties.GetValueOrDefault("formula", "")));
// R7-2: per ECMA-376 §18.2.5, <x:definedName> content must NOT
// have a leading '=' (unlike the formula-bar form in Excel UI).
// Excel rejects the file with 0x800A03EC if '=' is present.
if (refVal.StartsWith('='))
refVal = refVal.TrimStart('=');
var workbook = GetWorkbook();
var definedNames = workbook.GetFirstChild<DefinedNames>();
@ -566,6 +571,28 @@ public partial class ExcelHandler
dn.Comment = nrComment;
definedNames.AppendChild(dn);
// R7-3: if the defined-name body is a formula (not just a pure
// range reference), set fullCalcOnLoad so Excel recomputes on
// first open — otherwise the name evaluates to 0 until the
// user triggers a recalc.
if (LooksLikeFormulaBody(refVal))
{
var calcPr = workbook.GetFirstChild<CalculationProperties>();
if (calcPr == null)
{
calcPr = new CalculationProperties();
var insertBefore = (DocumentFormat.OpenXml.OpenXmlElement?)workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.OleSize>()
?? (DocumentFormat.OpenXml.OpenXmlElement?)workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.CustomWorkbookViews>()
?? (DocumentFormat.OpenXml.OpenXmlElement?)workbook.GetFirstChild<DocumentFormat.OpenXml.Spreadsheet.PivotCaches>();
if (insertBefore != null)
workbook.InsertBefore(calcPr, insertBefore);
else
workbook.AppendChild(calcPr);
}
calcPr.FullCalculationOnLoad = true;
}
workbook.Save();
var nrIdx = definedNames.Elements<DefinedName>().ToList().IndexOf(dn) + 1;