Skip to content

fix: Add x: namespace prefix to sheetData elements for Excel compatib…#1

Open
jogibear9988 wants to merge 13 commits into
dotnetprojects:masterfrom
TeaJAge:master
Open

fix: Add x: namespace prefix to sheetData elements for Excel compatib…#1
jogibear9988 wants to merge 13 commits into
dotnetprojects:masterfrom
TeaJAge:master

Conversation

@jogibear9988

Copy link
Copy Markdown
Member

…ility

Dynamically generated sheetData content was missing namespace prefixes, causing XML inconsistency when worksheet root uses 'x:' prefix.

Symptoms: Excel opens the file with correct file size but displays an empty worksheet - data is silently ignored due to malformed XML.

Copilot AI review requested due to automatic review settings December 2, 2025 14:26
…ility

Dynamically generated sheetData content was missing namespace prefixes,
causing XML inconsistency when worksheet root uses 'x:' prefix.

Symptoms: Excel opens the file with correct file size but displays an
empty worksheet - data is silently ignored due to malformed XML.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR fixes XML namespace prefix inconsistency in dynamically generated Excel worksheet data. When the worksheet root element uses the 'x:' namespace prefix, all child elements within sheetData must also use this prefix to maintain XML validity.

Key Changes:

  • Added x: namespace prefix to dynamically generated sheetData, row, c (cell), f (formula), and v (value) elements
  • Commented out static CreateNode("d:sheetData") call since sheetData is now dynamically generated with the correct namespace
  • Updated both StringBuilder and StreamWriter-based WriteRow methods for consistency

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread EPPlus/ExcelWorksheet.cs Outdated
if (f.IsArray)
{
cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, f.Address, ConvertUtil.ExcelEscapeString(f.Formula), GetFormulaValue(v), GetCellType(v, true));
cache.AppendFormat("<x:c r=\"{0}\" s=\"{1}\"{5}><x:f ref=\"{2}\" t=\"array\">{3}</x:f>{4}</x:c>", cse.CellAddress, styleID < 0 ? 0 : styleID, f.Address, ConvertUtil.ExcelEscapeString(f.Formula), GetFormulaValue(v), GetCellType(v, true));

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

The opening <f> tag is missing the x: namespace prefix while the closing tag has it (</x:f>). This creates an XML mismatch. Change <f ref= to <x:f ref= for consistency.

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs Outdated
else
{
cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{6}><f ref=\"{2}\" t=\"shared\" si=\"{3}\">{4}</f>{5}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, f.Address, sfId, ConvertUtil.ExcelEscapeString(f.Formula), GetFormulaValue(v), GetCellType(v, true));
cache.AppendFormat("<x:c r=\"{0}\" s=\"{1}\"{6}><x:f ref=\"{2}\" t=\"shared\" si=\"{3}\">{4}</x:f>{5}</x:c>", cse.CellAddress, styleID < 0 ? 0 : styleID, f.Address, sfId, ConvertUtil.ExcelEscapeString(f.Formula), GetFormulaValue(v), GetCellType(v, true));

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

The opening <f> tag is missing the x: namespace prefix while the closing tag has it (</x:f>). This creates an XML mismatch. Change <f ref= to <x:f ref= for consistency.

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs Outdated
else
{
cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{4}><f t=\"shared\" si=\"{2}\"/>{3}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, sfId, GetFormulaValue(v), GetCellType(v, true));
cache.AppendFormat("<x:c r=\"{0}\" s=\"{1}\"{4}><x:f t=\"shared\" si=\"{2}\"/>{3}</x:c>", cse.CellAddress, styleID < 0 ? 0 : styleID, sfId, GetFormulaValue(v), GetCellType(v, true));

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

The opening <f> tag is missing the x: namespace prefix. Change <f t= to <x:f t= for consistency with other formula elements.

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs Outdated
if (f.IsArray)
{
cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, string.Format("{0}:{1}", f.Address, f.Address), ConvertUtil.ExcelEscapeString(f.Formula), GetFormulaValue(v), GetCellType(v, true));
cache.AppendFormat("<x:c r=\"{0}\" s=\"{1}\"{5}><x:f ref=\"{2}\" t=\"array\">{3}</x:f>{4}</x:c>", cse.CellAddress, styleID < 0 ? 0 : styleID, string.Format("{0}:{1}", f.Address, f.Address), ConvertUtil.ExcelEscapeString(f.Formula), GetFormulaValue(v), GetCellType(v, true));

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

The opening <f> tag is missing the x: namespace prefix while the closing tag has it (</x:f>). This creates an XML mismatch. Change <f ref= to <x:f ref= for consistency.

Copilot uses AI. Check for mistakes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 12 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread EPPlus/ExcelWorksheet.cs Outdated
Comment on lines +1463 to +1468
sw.Write("<x:mergeCells>");
foreach (string address in _mergedCells)
{
sw.Write("<mergeCell ref=\"{0}\" />", address);
sw.Write("<x:mergeCell ref=\"{0}\" />", address);
}
sw.Write("</mergeCells>");
sw.Write("</x:mergeCells>");

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

The 'x:' namespace prefix is incorrect for main spreadsheet elements. The 'x:' prefix is registered for schemaMicrosoftExcel (urn:schemas-microsoft-com:office:excel) which is used for VML drawings, not for main spreadsheet elements like mergeCells, mergeCell, etc.

Main spreadsheet elements should either be:

  1. Unprefixed (in the default namespace), OR
  2. Match the prefix used in the original worksheet XML document

Hardcoding 'x:' prefix will break standard Excel files where these elements are unprefixed. Consider dynamically detecting and using the appropriate prefix from the worksheet root element instead of hardcoding 'x:'.

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs
}
else
{
CreateNode("d:cols");

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

Commenting out CreateNode("d:sheetData") while adding 'x:' prefixes to dynamically generated sheetData content creates an inconsistency. If this line is commented out because sheetData will be dynamically generated, there should be an explanation comment. Additionally, this change coupled with the hardcoded 'x:' prefixes suggests a fundamental issue with namespace handling that needs a more comprehensive solution rather than piecemeal changes.

Suggested change
CreateNode("d:cols");
CreateNode("d:cols");
// The sheetData node is generated dynamically below, so we do not create it here.
// WARNING: Ensure that dynamically generated sheetData content uses consistent XML namespaces.

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs Outdated
if (v != null && v.ToString()!="")
{
return "<v>" + ConvertUtil.ExcelEscapeString(GetValueForXml(v)) + "</v>"; //Fixes issue 15071
return "<x:v>" + ConvertUtil.ExcelEscapeString(GetValueForXml(v)) + "</x:v>"; //Fixes issue 15071

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

The 'x:' namespace prefix is incorrect for the 'v' (value) element. This is a main spreadsheet schema element that should be unprefixed or match the worksheet's namespace prefix. Using 'x:' (which is for VML elements) will cause XML validation errors.

Suggested change
return "<x:v>" + ConvertUtil.ExcelEscapeString(GetValueForXml(v)) + "</x:v>"; //Fixes issue 15071
return "<v>" + ConvertUtil.ExcelEscapeString(GetValueForXml(v)) + "</v>"; //Fixes issue 15071

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs Outdated
Comment on lines +3986 to +3988
if (prevRow != -1) sw.Write("</x:row>");
//ulong rowID = ExcelRow.GetRowID(SheetID, row);
sw.Write("<row r=\"{0}\"", row);
sw.Write("<x:row r=\"{0}\"", row);

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

The 'x:' namespace prefix is incorrect for 'row' elements in the StreamWriter version. Row elements are part of the main spreadsheet schema and should either be unprefixed (default namespace) or match the prefix used in the original worksheet XML. The 'x:' prefix is reserved for VML drawing elements. This will break standard Excel files.

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs Outdated
Comment on lines +3536 to +3542
breaks.AppendFormat("<x:brk id=\"{0}\" max=\"16383\" man=\"1\"/>", cse.Column);
count++;
}
}
if (count > 0)
{
sw.Write(string.Format("<colBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</colBreaks>", count, breaks.ToString()));
sw.Write(string.Format("<x:colBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</x:colBreaks>", count, breaks.ToString()));

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

The 'x:' namespace prefix is incorrect for colBreaks and brk elements. These are main spreadsheet schema elements that should either be unprefixed (default namespace) or match the prefix used in the original worksheet XML. The 'x:' prefix is reserved for VML drawing elements (schemaMicrosoftExcel), not for these elements. This will cause XML validation errors and break compatibility with standard Excel files.

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs Outdated
Comment on lines +3557 to +3563
breaks.AppendFormat("<x:brk id=\"{0}\" max=\"1048575\" man=\"1\"/>", cse.Row);
count++;
}
}
if (count>0)
{
sw.Write(string.Format("<rowBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</rowBreaks>", count, breaks.ToString()));
sw.Write(string.Format("<x:rowBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</x:rowBreaks>", count, breaks.ToString()));

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

The 'x:' namespace prefix is incorrect for rowBreaks and brk elements. These are main spreadsheet schema elements that should either be unprefixed (default namespace) or match the prefix used in the original worksheet XML. The 'x:' prefix is reserved for VML drawing elements (schemaMicrosoftExcel), not for these elements. This will cause XML validation errors and break compatibility with standard Excel files.

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs Outdated
Comment on lines +3936 to +3938
if (prevRow != -1) cache.Append("</x:row>");
//ulong rowID = ExcelRow.GetRowID(SheetID, row);
cache.AppendFormat("<row r=\"{0}\"", row);
cache.AppendFormat("<x:row r=\"{0}\"", row);

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

The 'x:' namespace prefix is incorrect for 'row' elements. Row elements are part of the main spreadsheet schema and should either be unprefixed (default namespace) or match the prefix used in the original worksheet XML. The 'x:' prefix is reserved for VML drawing elements. This will break standard Excel files.

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs Outdated
if (count > 0)
{
sw.Write(string.Format("<colBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</colBreaks>", count, breaks.ToString()));
sw.Write(string.Format("<x:colBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</x:colBreaks>", count, breaks.ToString()));

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

Redundant call to 'ToString' on a String object.

Copilot uses AI. Check for mistakes.
Comment thread EPPlus/ExcelWorksheet.cs Outdated
if (count>0)
{
sw.Write(string.Format("<rowBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</rowBreaks>", count, breaks.ToString()));
sw.Write(string.Format("<x:rowBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</x:rowBreaks>", count, breaks.ToString()));

Copilot AI Dec 2, 2025

Copy link

Choose a reason for hiding this comment

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

Redundant call to 'ToString' on a String object.

Copilot uses AI. Check for mistakes.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Thomas Herrmann and others added 2 commits December 19, 2025 16:34
When saving, inconsistent namespace prefixes were used, resulting in
invalid XML documents.  The prefix is now dynamically determined from the
document and used consistently across all elements.

- Extract _nsPrefix from WorksheetXml. DocumentElement
- Replace all hardcoded "x:" prefixes with _nsPrefix
- Add using alias RegexMatch to resolve naming conflict
- Fix $"" combined with AppendFormat/string.Format calls
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 6, 2026 02:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread EPPlus/ExcelWorksheet.cs
Comment on lines 4095 to 4102
{
id = hyps[hyp.OriginalString];
}
else
{
var relationship = Part.CreateRelationship(hyp, Packaging.TargetMode.External, ExcelPackage.schemaHyperlink);
if (uri is ExcelHyperLink)
{
Comment thread EPPlus/ExcelWorksheet.cs
using OfficeOpenXml.Drawing;
using OfficeOpenXml.Drawing.Chart;
using OfficeOpenXml.Drawing.Vml;
using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
Comment thread EPPlus/ExcelWorksheet.cs
Comment on lines +3438 to +3453
{
var worksheetNode = _worksheetXml.DocumentElement;
if (worksheetNode == null)
{
return string.Empty;
}

var prefix = worksheetNode.Prefix;
if (string.IsNullOrEmpty(prefix) && string.IsNullOrEmpty(worksheetNode.NamespaceURI) == false)
{
prefix = worksheetNode.GetPrefixOfNamespace(worksheetNode.NamespaceURI);
}

return string.IsNullOrEmpty(prefix) ? string.Empty : prefix + ":";
}

Shane32 and others added 6 commits May 5, 2026 22:17
…lows (Shane32#29)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Shane32 <6377684+Shane32@users.noreply.github.com>
Co-authored-by: Shane Krueger <shane@acdmail.com>
Shane32#30)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Shane32 <6377684+Shane32@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Shane32 <6377684+Shane32@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 7, 2026 06:30

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated 4 comments.

Comment thread EPPlus/ExcelWorksheet.cs
sw.Write("<hyperlink ref=\"{0}\"{2}{3} r:id=\"{1}\"/>", ExcelCellBase.GetAddress(cse.Row, cse.Column), relationship.Id,
string.IsNullOrEmpty(hl.Display) ? "" : " display=\"" + SecurityElement.Escape(hl.Display) + "\"",
string.IsNullOrEmpty(hl.ToolTip) ? "" : " tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\"");
sw.Write($"<{_nsPrefix}hyperlink ref=\"{ExcelCellBase.GetAddress(cse.Row, cse.Column)}\"{(string.IsNullOrEmpty(hl.Display) ? "" : $" display=\"{SecurityElement.Escape(hl.Display)}\"")}{(string.IsNullOrEmpty(hl.ToolTip) ? "" : $" tooltip=\"{SecurityElement.Escape(hl.ToolTip)}\"")}" + $" r:id=\"{relationship.Id}\"/>");
Comment thread global.json
Comment on lines +1 to +6
{
"sdk": {
"version": "8.0.100",
"rollForward": "latestFeature"
}
}
Comment on lines 20 to +31
dotnet-version: |
2.1.x
3.1.x
6.0.x
8.0.x
- name: Setup .NET Core SDKs on Linux
if: matrix.os == 'ubuntu-latest'
uses: actions/setup-dotnet@v5
with:
dotnet-version: |
6.0.x
8.0.x

steps:
- name: Setup .NET
uses: actions/setup-dotnet@v4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants