好的,我正在从数据表生成 Excel 文件。我生成文件并保存它,没有编译或运行时错误。当我在 Excel 中打开文件时,它会弹出消息:
我们发现“filename.xlsx”中的某些内容存在问题。您希望我们尽力恢复吗?如果您信任此工作簿的来源,请单击“是”。
所以我点击
Yes
。一两秒后,它会显示以下消息:
Excel 能够通过修复或删除不可读的内容来打开文件。
修复的记录:格式来自 /xl/styles.xml(样式)
单击查看列出修复的日志文件:C:\file\path\filename.xml
但是如果你点击打开日志,它基本上只是说同样的事情,没有额外的细节。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<logFileName>error336080_01.xml</logFileName>
<summary>Errors were detected in file 'C:\my\file\path\data.xlsx'</summary>
<repairedRecords>
<repairedRecord>Repaired Records: Format from /xl/styles.xml part (Styles)</repairedRecord>
</repairedRecords>
</recoveryLog>
所以,我想好吧...我刚刚找到了 Microsoft 漂亮的小 OOXML SDK 验证器/比较工具。所以我打开其中的“坏”文件,然后运行
Validate
。它完全成功返回,并表明文件中没有错误。所以我不太确定Excel在抱怨什么。
此外,在允许Excel“修复”并完成打开文件后,工作表的所有样式和显示都正确,所有数据都已填写,并且看起来与预期的完全一样。
这是我用来生成 OOXML 样式表的代码...
(是的,它是 VB.NET,它是一个遗留应用程序。)
Private Function ConstructStyleSheet() As Stylesheet
Dim rv As Stylesheet = New Stylesheet()
rv.AppendChild(New NumberingFormats(
New NumberingFormat() With {.NumberFormatId = 0, .FormatCode = "General"},
New NumberingFormat() With {.NumberFormatId = 5, .FormatCode = "MM/dd/yyyy HH:mm:ss"}
))
rv.AppendChild(New Fonts(
New Font(),
New Font(New Bold())
))
rv.AppendChild(New Borders(
New Border(),
New Border(New BottomBorder(New Color() With {.Auto = True}) With {.Style = BorderStyleValues.Thin})
))
'// COMMENTING OUT THIS BLOCK (BUT LEAVING ALL ABOVE) YIELDS AN XLSX WITH NO ERRORS
'// BUT OF COURSE, NO STYLING ON ANY CELLS, EITHER
rv.AppendChild(New CellFormats(
New CellFormat() With {.FontId = 0, .ApplyFont = True},
New CellFormat() With {.FontId = 1, .BorderId = 1, .ApplyFont = True, .ApplyBorder = True},
New CellFormat() With {.FontId = 0, .ApplyFont = True, .NumberFormatId = 5, .ApplyNumberFormat = True}
))
Return rv
End Function
这是
/xl/styles.xml
样式表的内容...
<?xml version="1.0" encoding="utf-8"?>
<x:styleSheet xmlns:x="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
<x:numFmts>
<x:numFmt numFmtId="0" formatCode="General" />
<x:numFmt numFmtId="5" formatCode="MM/dd/yyyy HH:mm:ss" />
</x:numFmts>
<x:fonts>
<x:font />
<x:font>
<x:b />
</x:font>
</x:fonts>
<x:borders>
<x:border />
<x:border>
<x:bottom style="thin">
<x:color auto="1" />
</x:bottom>
</x:border>
</x:borders>
<x:cellXfs>
<x:xf fontId="0" applyFont="1" />
<x:xf fontId="1" borderId="1" applyFont="1" applyBorder="1" />
<x:xf numFmtId="5" fontId="0" applyNumberFormat="1" applyFont="1" />
</x:cellXfs>
</x:styleSheet>
经过一番工作后也找到了这个问题,并将答案发布在这里供后代使用。
结果是 Excel 需要您将填充样式放入输出文件中,即使您没有在任何单元格中使用任何填充样式。
Private Function ConstructStyleSheet() As Stylesheet
Dim rv As Stylesheet = New Stylesheet()
rv.AppendChild(New NumberingFormats(
New NumberingFormat() With {.NumberFormatId = 5, .FormatCode = "mm/dd/yyyy hh:mm:ss"}
) With {.Count = 1})
rv.AppendChild(New Fonts(
New Font(),
New Font(New Bold())
) With {.Count = 2})
'// ===== NEW SECTION =====
rv.AppendChild(New Fills(
New Fill(New PatternFill() With {.PatternType = PatternValues.None}),
New Fill(New PatternFill() With {.PatternType = PatternValues.Gray125})
) With {.Count = 2})
'\\ =======================
rv.AppendChild(New Borders(
New Border(),
New Border(New BottomBorder(New Color() With {.Auto = True}) With {.Style = BorderStyleValues.Thin})
) With {.Count = 2})
'// ===== THEN ALSO ADD THE .FillId = 0 ON ALL OF THE CellFormats
rv.AppendChild(New CellFormats(
New CellFormat() With {.FillId = 0, .BorderId = 0, .FontId = 0, .NumberFormatId = 0},
New CellFormat() With {.FillId = 0, .ApplyBorder = True, .ApplyFont = True, .BorderId = 1, .FontId = 1, .NumberFormatId = 0},
New CellFormat() With {.FillId = 0, .ApplyNumberFormat = True, .BorderId = 0, .NumberFormatId = 5, .FontId = 0, .ApplyFont = True}
) With {.Count = 3})
Return rv
End Function
在这两个问题之后,这个故事的明确寓意是 Excel(我猜其他 Office 应用程序也是如此?)对 XLSX 文件中输出的 XML 极其挑剔,您只需花费大量的时间调试和追踪像这样的愚蠢的小东西,即使它们是你的文件中实际上不需要的东西。
遇到这种情况我能做什么?