#excel #apache-poi
#excel #apache-poi
Вопрос:
Мы получаем файлы Excel в нашей системе, и после их загрузки мне нужно удалить любую ссылку на внешнюю книгу по соображениям безопасности.
я написал следующую функцию для удаления внешних ссылок, а также для удаления содержимого из ячейки, ссылающейся на книгу.
public static byte[] cleanFile(byte[] excelByteArrayworkbook) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (InputStream targetStream = new ByteArrayInputStream(excelByteArrayworkbook)){
try (XSSFWorkbook workbook = new XSSFWorkbook(targetStream)) {
XSSFEvaluationWorkbook evalWorkbook = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
Iterator<Sheet> sheetIterator = workbook.iterator();
int i = 0;
while (sheetIterator.hasNext()) {
Sheet sheet = sheetIterator.next();
EvaluationSheet evalSheet = evalWorkbook.getSheet(i);
i ;
for (Row row : sheet) {
for (Cell cell : row) {
if (cell.getCellType() == Cell.CELL_TYPE_FORMULA) {
EvaluationCell evaluationCell = evalSheet.getCell(cell.getRowIndex(), cell.getColumnIndex());
try {
Ptg[] formulaTokens = evalWorkbook.getFormulaTokens(evaluationCell);
for (Ptg formulaToken : formulaTokens) {
int externalSheetIndex = -1;
if (formulaToken instanceof Ref3DPtg) {
Ref3DPtg refToken = (Ref3DPtg) formulaToken;
externalSheetIndex = refToken.getExternSheetIndex();
} else if (formulaToken instanceof Area3DPtg) {
Area3DPtg refToken = (Area3DPtg) formulaToken;
externalSheetIndex = refToken.getExternSheetIndex();
} else if (formulaToken instanceof Ref3DPxg) {
Ref3DPxg refToken = (Ref3DPxg) formulaToken;
externalSheetIndex = refToken.getExternalWorkbookNumber();
} else if (formulaToken instanceof Area3DPxg) {
Area3DPxg refToken = (Area3DPxg) formulaToken;
externalSheetIndex = refToken.getExternalWorkbookNumber();
}
if (externalSheetIndex >= 0) {
cell.setCellFormula(null);
}
else if (cell.getCellFormula().contains("[")) {
cell.setCellFormula(null);
}
}
} catch (Exception e) {
cell.setCellFormula(null);
}
}
}
}
}
List<ExternalLinksTable> links = workbook.getExternalLinksTable();
links.forEach(link -> {
if(link.getCTExternalLink().isSetDdeLink())
link.getCTExternalLink().unsetDdeLink();
if(link.getCTExternalLink().isSetExtLst())
link.getCTExternalLink().unsetExtLst();
if(link.getCTExternalLink().isSetOleLink())
link.getCTExternalLink().unsetOleLink();
if(link.getCTExternalLink().isSetExternalBook())
link.getCTExternalLink().unsetExternalBook();
link.getCTExternalLink().setNil();
});
try {
workbook.write(bos);
} finally {
bos.close();
}
}
}
try {
bos.close();
} catch (IOException e) {
}
return bos.toByteArray();
}
Однако файл, который я получаю, недействителен. Excel выдает мне сообщение об ошибке, в котором говорится Сообщение об ошибке Excel
Версия Apache POI, которую я использую, равна 3.13 . Я не могу найти пример, где я могу удалить внешние ссылки
Ответ №1:
Я нашел ответ. Код не удалял ссылки в области диспетчера имен.
Я добавил следующее в свою функцию
List<XSSFName> nameUsingExternalBook = new ArrayList<XSSFName>();
for (int j = 0; j < workbook.getNumberOfNames(); j ) {
XSSFName name= workbook.getNameAt(j);
if(name.getRefersToFormula() != null amp;amp; name.getRefersToFormula().contains("[")) {
nameUsingExternalBook.add(name);
}
}
nameUsingExternalBook.forEach(name->{
workbook.removeName(name.getNameName());
});
Итак, новый файл Excel имеет правильную форму