Apache POI — удалить внешнюю ссылку на книгу

#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 имеет правильную форму