2

我有 100 多个已损坏的工作簿 - 当试图打开它们时,Excel 会抛出一条错误消息,指出“x”是一个未声明的前缀。这些文件无法在 xml 查看器(包括 OpenXML 之一)中加载。现在,如果我将 Excel 工作簿的扩展名更改为 .zip,解压缩所有部分,在 workbook.xml 文件中编辑以下行(这是 xml 文档中的最后一个元素)

<extLst><x:ext uri="{140A7094-0E35-4892-8432-C4D2E57EDEB5}" xmlns:x15="http://schemas.microsoft.com/office/spreadsheetml/2010/11/main"><x15:workbookPr chartTrackingRefBase="1"/></x:ext></extLst>

通过删除整个元素或删除标签x:中的 ,<ext>然后我将其打包备份后工作簿将正常运行。

我还尝试了以下 VB.Net 代码:

 Private Sub RemoveExceptionsFromWorkbook(ByVal workbookPath As String)
        Using excelDoc As SpreadsheetDocument = SpreadsheetDocument.Open(workbookPath, True)
            If excelDoc.WorkbookPart.Workbook.Descendants(Of WorkbookExtensionList)().Any() Then
                excelDoc.WorkbookPart.Workbook.RemoveAllChildren(Of WorkbookExtensionList)()
                excelDoc.WorkbookPart.Workbook.Save()
            End If
        End Using
    End Sub

但是我每次都得到'x'是一个未声明的前缀错误。有谁知道如何解决这一问题?任何帮助将不胜感激。

4

2 回答 2

3

据我所知,您无法使用 Excel 或 Open XML SDK 来执行此操作,因为文件本身已损坏。这意味着您必须像修改普通的 ZIP 文件一样对其进行修改。为了方便起见,我使用了 DotNetZip,但您可以使用任何您喜欢的 ZIP 库。尝试这个:

using (ZipFile zf = ZipFile.Read("damagedcopy.xlsx"))
{
    ZipEntry ze = zf["xl/workbook.xml"];
    using (MemoryStream ms = new MemoryStream())
    {
        ze.Extract(ms);
        // this is important, otherwise the StreamReader starts from the end.
        ms.Position = 0;
        StreamReader sr = new StreamReader(ms);
        string streamdata = sr.ReadToEnd();
        // I only updated the relevant portion of the XML
        streamdata = streamdata.Replace("<x:ext", "<ext");
        streamdata = streamdata.Replace("</x:ext>", "</ext>");
        sr.Close();
        zf.UpdateEntry("xl/workbook.xml", streamdata);
        zf.Save();
    }
}

根据需要遍历所有 100 多个 Excel 文件(我感到你的痛苦……)。

于 2013-07-16T04:56:41.180 回答
1

+1 给 Vincent Tan 的概念。你是对的 - xml 文件无法打开,所以我必须先将其修改为文本文件。首先我在上面运行了这个:

Private Sub RemovePrefix()
     'Change the extension of the workbook.xml file to txt
     IO.File.Move(WorkbookXmlFilePath, WorkbookXmlTxtFileName)  

     Dim arrText() As String = IO.File.ReadAllLines(WorkbookXmlTxtFileName)
     Dim arrNewText(arrText.Length - 1) As String

     For i As Integer = 0 To UBound(arrText)
          If arrText(i).Contains("x:") Then
               arrNewText(i) = Strings.Replace(arrText(i), "x:", "")
          Else
               arrNewText(i) = arrText(i)
          End If
     Next

     IO.File.WriteAllLines(WorkbookXmlTxtFileName, arrNewText)

     'Change the extension back to xml
     IO.File.Move(WorkbookXmlTxtFileName, WorkbookXmlFilePath)
End Sub

之后,xml 文件不再损坏,但尝试打开 Excel 工作簿仍然给我一条消息,指出数据已损坏。<extLst>因此,我的问题中的过程随后可以从 workbook.xml 文档中完全删除节点并修复工作簿。

Private Sub RemoveExceptionList(ByVal workbookPath as String)
     Using excelDoc As SpreadsheetDocument = SpreadsheetDocument.Open(workbookPath, True)
          If excelDoc.WorkbookPart.Workbook.Descendants(Of WorkbookExtensionList)().Any() Then
               excelDoc.WorkbookPart.Workbook.RemoveAllChildren(Of WorkbookExtensionList)()
               excelDoc.WorkbookPart.Workbook.Save()
          End If
     End Using
 End Sub
于 2013-07-16T23:57:33.127 回答