通过OpenXML的SDK有效和无效XLSX文件(XLSX file via OpenXml SDK

2019-10-29 03:41发布

我有一个程序,它导出一个System.Data.DataTable到XLSX / OPENXML电子表格。 终于等来了它主要的工作。 然而,在Excel中打开电子表格时,Excel的抱怨文件是无效的,需要维修,让这条消息...

我们发现一个问题,在一些内容。 你希望我们尝试恢复多,我们可以吗? 如果您信任该工作簿的来源,CLIK是。

如果我点击是的,它回来了这条消息...

点击日志文件,打开的是,恰恰说明了这...

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <recoveryLog xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">
        <logFileName>error268360_01.xml</logFileName>
        <summary>Errors were detected in file 'C:\Users\aabdi\AppData\Local\Temp\data.20190814.152538.xlsx'</summary>
        <repairedRecords>
            <repairedRecord>Repaired Records: Cell information from /xl/worksheets/sheet1.xml part</repairedRecord>
        </repairedRecords>
    </recoveryLog> 

显然,我们不希望这个部署到生产环境中是这样的。 所以,我一直在试图找出如何解决这个问题。 我扔在一起,一个小巧的样本来验证XML并显示错误的基础上, 从MSDN这个链接 。 但是,当我运行该程序并加载Excel的抱怨完全相同的XLSX文件,确认伤愈复出说,该文件是完全有效的。 所以,我不知道还有什么地方从那里。

对于试图验证我的XLSX XML任何更好的工具? 以下是我使用生成XLSX文件的完整代码。 (是的,它是在VB.NET,这是一个传统的应用程序。)

如果我在注释掉该行For Each dr As DataRow循环,那么XLSX文件在Excel中打开罚款,(只是没有任何数据)。 所以这件事情的个体细胞,但我不是真的会大量使用它们。 设定值和数据类型,仅此而已。

我也试过更换For Each环路ConstructDataRow用下面的,但它仍然输出相同的“坏”的XML ...

        rv.Append(
            (From dc In dr.Table.Columns
             Select ConstructCell(
                 NVL(dr(dc.Ordinal), String.Empty),
                 MapSystemTypeToCellType(dc.DataType)
             )
            ).ToArray()
        )

也试过更换调用AppendAppendChild每个细胞也一样,但这并没有帮助。

该压缩了XLSX文件(示数,以虚拟数据)可以在这里找到:
https://drive.google.com/open?id=1KVVWEqH7VHMxwbRA-Pn807SXHZ32oJWR

全部数据表到Excel XLSX代码


    #Region " ToExcel "
    <Extension>
    Public Function ToExcel(ByVal target As DataTable) As Attachment
        Dim filename = Path.GetTempFileName()
        Using doc As SpreadsheetDocument = SpreadsheetDocument.Create(filename, DocumentFormat.OpenXml.SpreadsheetDocumentType.Workbook)
            Dim data = New SheetData()

            Dim wbp = doc.AddWorkbookPart()
            wbp.Workbook = New Workbook()
            Dim wsp = wbp.AddNewPart(Of WorksheetPart)()
            wsp.Worksheet = New Worksheet(data)

            Dim sheets = wbp.Workbook.AppendChild(New Sheets())
            Dim sheet = New Sheet() With {.Id = wbp.GetIdOfPart(wsp), .SheetId = 1, .Name = "Data"}
            sheets.Append(sheet)

            data.AppendChild(ConstructHeaderRow(target))
            For Each dr As DataRow In target.Rows
                data.AppendChild(ConstructDataRow(dr)) '// THIS LINE YIELDS THE BAD PARTS
            Next

            wbp.Workbook.Save()
        End Using

        Dim attachmentname As String = Path.Combine(Path.GetDirectoryName(filename), $"data.{Now.ToString("yyyyMMdd.HHmmss")}.xlsx")
        File.Move(filename, attachmentname)
        Return New Attachment(attachmentname, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
    End Function

    Private Function ConstructHeaderRow(dt As DataTable) As Row
        Dim rv = New Row()
        For Each dc As DataColumn In dt.Columns
            rv.Append(ConstructCell(dc.ColumnName, CellValues.String))
        Next
        Return rv
    End Function

    Private Function ConstructDataRow(dr As DataRow) As Row
        Dim rv = New Row()
        For Each dc As DataColumn In dr.Table.Columns
            rv.Append(ConstructCell(NVL(dr(dc.Ordinal), String.Empty), MapSystemTypeToCellType(dc.DataType)))
        Next
        Return rv
    End Function

    Private Function ConstructCell(value As String, datatype As CellValues) As Cell
        Return New Cell() With {
        .CellValue = New CellValue(value),
        .DataType = datatype
        }
    End Function

    Private Function MapSystemTypeToCellType(t As System.Type) As CellValues
        Dim rv As CellValues
        Select Case True
            Case t Is GetType(String)
                rv = CellValues.String
            Case t Is GetType(Date)
                rv = CellValues.Date
            Case t Is GetType(Boolean)
                rv = CellValues.Boolean
            Case IsNumericType(t)
                rv = CellValues.Number
            Case Else
                rv = CellValues.String
        End Select

        Return rv
    End Function
    #End Region

Answer 1:

对于任何人进来,并找到这个,我终于跟踪下来到Cell.DataType

设定值CellValues.Date会导致Excel要“修理”的文件。 (显然日期, 数据类型应为NULL ,并且Date仅在Office 2010中使用)。

另外,如果你指定的数据类型CellValues.Boolean ,那么CellValue必须是0或1“真” /“假”,也将导致Excel要“修理”你的电子表格。

此外,微软已经内置在这里下载一个更好的验证工具:
https://www.microsoft.com/en-us/download/details.aspx?id=30425



文章来源: XLSX file via OpenXml SDK Both Valid and Invalid