阅读excel时如何跳过一些无效字符



使用poi读取一些excel失败,遇到这样的错误

Caused by: org.xml.sax.SAXParseException; systemId: file://; lineNumber: 105; columnNumber: 147342; An invalid XML character (Unicode: 0xffff) was found in the element content of the document.
at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.createSAXParseException(ErrorHandlerWrapper.java:204)
at java.xml/com.sun.org.apache.xerces.internal.util.ErrorHandlerWrapper.fatalError(ErrorHandlerWrapper.java:178)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLErrorReporter.reportError(XMLErrorReporter.java:400)

xl/sharedStrings.xml来看,存在导致该问题的<ffff>

怎么能成功地读取它而忽略这些无效字符呢?例如

aaa <ffff> bbb ==> aaa bbb

这些无效字符不应该在XML中,Excel本身也不会将它们放入其中。因此,可能有人在使用Excel以外的其他工具创建该文件时出错了。应该避免这种错误,而不是试图忽视症状。

但我知道在遥远的未来,如果有的话,对其他人的工作感到不快是什么感觉。所以一个人需要即兴发挥。但在这种情况下,只有使用丑陋的低级别方法才能做到这一点。因为XML无效,所以无法解析XML。因此,只有字符串替换是可能的。

在APACHE POI EXCEL XmlException中:是一个无效的XML字符,有什么方法可以预处理EXCEL文件吗?我已经学会了。在这种情况下,要替换在XML中也无效的UTF-16代理对空数字字符引用。

在下面的代码中,我将展示一个更灵活的代码,可以在必要时向/xl/sharedStrings.xml添加多个其他修复操作。

其原理是使用OPCPackage,即*.xlsxZIP包,来获取作为文本字符串的/xl/sharedStrings.xml。然后进行所需的更换,并将修复后的/xl/sharedStrings.xml放回OPCPackage中。然后从修复的OPCPackage而不是从损坏的文件创建XSSFWorkbook

import java.io.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.openxml4j.opc.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
class RepairSharedStringsTable {

static String removeInvalidXmlCharacters(String string) {
String xml10pattern = "[^"
+ "u0009rn"
+ "u0020-uD7FF"
+ "uE000-uFFFD"
+ "ud800udc00-udbffudfff"
+ "]";
string = string.replaceAll(xml10pattern, "");
return string;     
}

static void repairSharedStringsTable(OPCPackage opcPackage) {
for (PackagePart packagePart : opcPackage.getPartsByName(Pattern.compile("/xl/sharedStrings.xml"))) {

String sharedStrings = "";
try (BufferedInputStream inputStream = new BufferedInputStream(packagePart.getInputStream());
ByteArrayOutputStream sharedStringsBytes = new ByteArrayOutputStream() ) {
byte[] buffer = new byte[1024];
int length;

while ((length = inputStream.read(buffer)) != -1) {
sharedStringsBytes.write(buffer, 0, length);
}
sharedStrings = sharedStringsBytes.toString("UTF-8");
} catch (Exception ex) {
ex.printStackTrace();
}

System.out.println(sharedStrings);
//sharedStrings = replaceUTF16SurrogatePairs(sharedStrings);
sharedStrings = removeInvalidXmlCharacters(sharedStrings);
//sharedStrings = doSomethingElse(sharedStrings);
System.out.println(sharedStrings);
try (BufferedOutputStream outputStream = new BufferedOutputStream(packagePart.getOutputStream()) ) {
outputStream.write(sharedStrings.getBytes("UTF-8"));
} catch (Exception ex) {
ex.printStackTrace();
}
}  
}
public static void main(String[] args) throws Exception {
try (XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream("./Excel.xlsx"))) {
System.out.println("success");
} catch (Exception ex) {
System.out.println("failed");
ex.printStackTrace();
}
OPCPackage opcPackage = OPCPackage.open(new FileInputStream("./Excel.xlsx"));
repairSharedStringsTable(opcPackage);
opcPackage.flush();

try (XSSFWorkbook workbook = new XSSFWorkbook(opcPackage);
FileOutputStream out = new FileOutputStream("./ExcelRepaired.xlsx");) {
workbook.write(out);
System.out.println("success");
} catch (Exception ex) {
System.out.println("failed");
ex.printStackTrace();
}
}
}

在我的情况下,下面的文件都有无效字符

xl/sharedStrings.xml
xl/worksheets/sheet1.xml
xl/worksheets/sheet8.xml

所有这些xml都应该进行处理

opcPackage.getPartsByName(Pattern.compile("(/xl/sharedStrings.xml)|(/xl/worksheets/.+\.xml)"))

最新更新