Apache Poi идентифицирует формулу со ссылкой на другую книгу - PullRequest
0 голосов
/ 06 июня 2019

У меня есть рабочая книга, которую я должен очистить от всех ссылок на другие рабочие книги. В настоящее время я пытаюсь разобрать формулы ячеек, чтобы проверить, ссылаются ли они на какой-либо файл Excel.

Для этого я использую эту строку

cell.getCellFormula().matches(".*\\[.*\\.xls[xm]?\\].*")

проблема в том, что ячейка выглядит следующим образом в формате XML:

 <c r="K64" s="2128">
    <f>[5]Segments!$AS$7/Annual!AF38</f>
    <v>0.0</v>
 </c>

Как видите, в действительности формула вообще не содержит .xls, '.xlsx' или .xlsm. Насколько я знаю, [5] указывает общую строку, которая содержит фактический путь и, следовательно, фактическое значение для формулы.

Теперь можно сказать и изменить регулярное выражение на .*\\[\d+\\].*, но я думаю, что это может быть довольно подвержено ошибкам. Также я думаю, что не все внешние ссылки будут выглядеть буквально так.

Итак, мой вопрос:

Как определить формулы, которые ссылаются на внешнюю рабочую книгу?


Если у вас есть какие-либо вопросы, не стесняйтесь спрашивать.

EDIT:

Я подготовил образец файла Excel, в котором показана проблема. Он доступен для скачивания на workupload.com

1 Ответ

2 голосов
/ 06 июня 2019

Способ, показанный в Динамическое добавление внешних (кросс-рабочих книг) ссылок , безусловно, это путь. Просмотрите все маркеры формул, и если один из них имеет индекс внешнего листа, эта формула ссылается на внешний лист.

Пример использования загруженного вами файла:

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.formula.*;
import org.apache.poi.ss.formula.ptg.*;
import org.apache.poi.ss.formula.EvaluationWorkbook.ExternalSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.usermodel.HSSFEvaluationWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFEvaluationWorkbook;

import java.io.FileInputStream;

public class ExcelReadExternalReference {
    public static void main(String[] args) throws Exception {

        String filePath = "TestExternalLinks.xlsx";
        // String filePath = "TestExternalLinks.xls";

        Workbook workbook = WorkbookFactory.create(new FileInputStream(filePath));

        EvaluationWorkbook evalWorkbook = null;
        if (workbook instanceof HSSFWorkbook) {
            evalWorkbook = HSSFEvaluationWorkbook.create((HSSFWorkbook) workbook);
        } else if (workbook instanceof XSSFWorkbook) {
            evalWorkbook = XSSFEvaluationWorkbook.create((XSSFWorkbook) workbook);
        }

        Sheet sheet = workbook.getSheetAt(0);
        EvaluationSheet evalSheet = evalWorkbook.getSheet(0);

        for (Row row : sheet) {
            for (Cell cell : row) {
                if (cell.getCellType() == CellType.FORMULA) {
                    String cellFormula = cell.getCellFormula();
                    System.out.println(cellFormula);

                    EvaluationCell evaluationCell = evalSheet.getCell(cell.getRowIndex(), cell.getColumnIndex());
                    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) {
                            System.out.print("We have extrenal sheet index: " + externalSheetIndex
                                    + ". So this formula refers an external sheet in workbook: ");

                            ExternalSheet externalSheet = null;
                            if (workbook instanceof HSSFWorkbook) {
                                externalSheet = evalWorkbook.getExternalSheet(externalSheetIndex);
                            } else if (workbook instanceof XSSFWorkbook) {
                                externalSheet = evalWorkbook.getExternalSheet(null, null, externalSheetIndex);
                            }
                            String linkedFileName = externalSheet.getWorkbookName();
                            System.out.println(linkedFileName);

                        }
                    }
                }
            }
        }

        workbook.close();
    }

}
...