Summary
When using QXlsx 1.5.1 Document::saveAs() to save a modified multi-sheet .xlsx file, Microsoft Excel reports XML corruption when opening the saved file. The specific error (observed in Chinese-locale Excel) reads:
被替换的部件: 有 XML 错误的 /xl/worksheets/sheet1.xml。加载错误。行 1,列 0。 (Replaced part: XML error in /xl/worksheets/sheet1.xml. Load error. Row 1, Column 0.)
The same error occurs for sheet5.xml (the last worksheet). Middle worksheets (sheet2~sheet4) open correctly in Excel.
Crucially, QXlsx itself can still read the corrupted file without error — only Microsoft Excel and WPS Office detect the broken XML.
Bug feature
The issue occurs when there are multiple workbooks in the xlsx file. After modifying the table content of any workbook using the qxlsx class functions and saving it, the problem arises. The Excel software will alert that the xlsx file format is damaged and it is necessary to attempt to repair it before opening it.
Key Findings
QXlsx self-consistency ≠ file correctness: QXlsx can read its own saveAs() output without errors, but Microsoft Excel and WPS Office reject it. This suggests the generated XML violates the OOXML (Office Open XML) specification in ways QXlsx's parser tolerates but Excel does not.
First and last sheets are corrupted: The corruption consistently affects /xl/worksheets/sheet1.xml and /xl/worksheets/sheet5.xml (the first and last sheets). Middle sheets (2–4) are fine. This pattern suggests an off-by-one or boundary bug in the sheet serialization logic.
Shared Strings table rebuilding: The corruption likely originates from how QXlsx rebuilds xl/sharedStrings.xml. When a cell value is changed, QXlsx appears to regenerate the shared strings table but may produce invalid XML for the referencing worksheets, or create an incorrect relationship between the shared strings and the worksheet XML.
Columnar mismatch triggers corruption: When some worksheets in a multi-sheet workbook don't contain certain column headers (and therefore have zero changed cells), the saved file is more likely to be corrupted. This suggests a bug in how QXlsx handles the xl/worksheets/sheetN.xml serialization when a sheet has no active modifications.
ZipReader/ZipWriter as effective workaround: The internal ZipReader/ZipWriter classes in xlsxzipreader_p.h and xlsxzipwriter_p.h provide a robust alternative for modifying xlsx files without touching the save/load framework. These classes are stable and produce valid files, but being in _p.h headers they are not part of the public API and could break between versions.
XML namespace handling is critical: When rewriting worksheet XML, every element must carry the namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main. Omitting it (as initial versions of XlsxPatcher did) creates files that fail XML validation.
Requests to QXlsx Maintainers
Fix Document::saveAs() for multi-sheet files: Investigate the sheet serialization boundary bug (first/last sheet corruption) and the shared strings table regeneration issue.
Consider promoting ZipReader/ZipWriter to public API: These classes enable a "patch-in-place" pattern that avoids full document serialization. Making them public would allow the community to build robust patching tools without relying on private headers.
Consider adding a patch() method: A method like Document::patchCells(QList) that directly modifies cells within the existing zip XML without re-serializing the entire document would solve many use cases (mass updates, field replacements) without touching formatting, merged cells, or other structure.
Add validation against Excel: Consider adding integration tests that verify saved files open correctly in an actual OOXML validator, not just in QXlsx's own reader.
report details as follows
English: QXlsx_BugReport_EN.md
Chinese: QXlsx_BugReport.md
Summary
When using QXlsx 1.5.1 Document::saveAs() to save a modified multi-sheet .xlsx file, Microsoft Excel reports XML corruption when opening the saved file. The specific error (observed in Chinese-locale Excel) reads:
被替换的部件: 有 XML 错误的 /xl/worksheets/sheet1.xml。加载错误。行 1,列 0。 (Replaced part: XML error in /xl/worksheets/sheet1.xml. Load error. Row 1, Column 0.)
The same error occurs for sheet5.xml (the last worksheet). Middle worksheets (sheet2~sheet4) open correctly in Excel.
Crucially, QXlsx itself can still read the corrupted file without error — only Microsoft Excel and WPS Office detect the broken XML.
Bug feature
The issue occurs when there are multiple workbooks in the xlsx file. After modifying the table content of any workbook using the qxlsx class functions and saving it, the problem arises. The Excel software will alert that the xlsx file format is damaged and it is necessary to attempt to repair it before opening it.
Key Findings
QXlsx self-consistency ≠ file correctness: QXlsx can read its own saveAs() output without errors, but Microsoft Excel and WPS Office reject it. This suggests the generated XML violates the OOXML (Office Open XML) specification in ways QXlsx's parser tolerates but Excel does not.
First and last sheets are corrupted: The corruption consistently affects /xl/worksheets/sheet1.xml and /xl/worksheets/sheet5.xml (the first and last sheets). Middle sheets (2–4) are fine. This pattern suggests an off-by-one or boundary bug in the sheet serialization logic.
Shared Strings table rebuilding: The corruption likely originates from how QXlsx rebuilds xl/sharedStrings.xml. When a cell value is changed, QXlsx appears to regenerate the shared strings table but may produce invalid XML for the referencing worksheets, or create an incorrect relationship between the shared strings and the worksheet XML.
Columnar mismatch triggers corruption: When some worksheets in a multi-sheet workbook don't contain certain column headers (and therefore have zero changed cells), the saved file is more likely to be corrupted. This suggests a bug in how QXlsx handles the xl/worksheets/sheetN.xml serialization when a sheet has no active modifications.
ZipReader/ZipWriter as effective workaround: The internal ZipReader/ZipWriter classes in xlsxzipreader_p.h and xlsxzipwriter_p.h provide a robust alternative for modifying xlsx files without touching the save/load framework. These classes are stable and produce valid files, but being in _p.h headers they are not part of the public API and could break between versions.
XML namespace handling is critical: When rewriting worksheet XML, every element must carry the namespace http://schemas.openxmlformats.org/spreadsheetml/2006/main. Omitting it (as initial versions of XlsxPatcher did) creates files that fail XML validation.
Requests to QXlsx Maintainers
Fix Document::saveAs() for multi-sheet files: Investigate the sheet serialization boundary bug (first/last sheet corruption) and the shared strings table regeneration issue.
Consider promoting ZipReader/ZipWriter to public API: These classes enable a "patch-in-place" pattern that avoids full document serialization. Making them public would allow the community to build robust patching tools without relying on private headers.
Consider adding a patch() method: A method like Document::patchCells(QList) that directly modifies cells within the existing zip XML without re-serializing the entire document would solve many use cases (mass updates, field replacements) without touching formatting, merged cells, or other structure.
Add validation against Excel: Consider adding integration tests that verify saved files open correctly in an actual OOXML validator, not just in QXlsx's own reader.
report details as follows
English: QXlsx_BugReport_EN.md
Chinese: QXlsx_BugReport.md