提问人:Ahmed 提问时间:11/15/2023 最后编辑:Marc Le BihanAhmed 更新时间:11/16/2023 访问量:40
应用 getCellFormula() 时,Excel 参考中的文件名始终是“[1]”,使用 Apache POI
File name in Excel Reference is always "[1]" using Apache POI when applying getCellFormula()
问:
我正在试验并设法使用以下拼切代码 (Java) 读取玩具 Excel 文件:Apache POI 5.2.4
// .. get file
FileInputStream excelFile = new FileInputStream(file);
Workbook workbook = new XSSFWorkbook(excelFile);
Sheet datatypeSheet = workbook.getSheetAt(0);
Iterator<Row> iterator = datatypeSheet.iterator();
while (iterator.hasNext()) {
Row currentRow = iterator.next();
Iterator<Cell> cellIterator = currentRow.iterator();
while (cellIterator.hasNext()) {
Cell currentCell = cellIterator.next();
if (currentCell.getCellType() == CellType.FORMULA) {
// !!! Interesting part !!!
String cellLabel = currentCell.getCellFormula();
// Here I get values like "[1]Sheet1!$A$3"
// instead of "[Book1.xlsx]Sheet1!$A$3"
// !!! End interesting part !!!
}
}
}
我阅读的 Excel 工作表仅包含一个单元格,该单元格引用同一文件夹中的另一个工作簿。它是使用 Excel 2019 for Mac 创建的,并正确显示链接值。
而不是我放入 Excel 中的文件名,我只得到 .[Book1.xlsx]Sheet1!$A$3
[1]Sheet1!$A$3
所有其他字段(如值或字符串)都会正确返回。
我尝试在返回的结构中查找字符串映射表,但找不到任何不为空的内容。如何将此 [1] 解析为引用的 Excel 的原始工作簿名称?它不需要查找或加载它,只需返回文件名即可。currentCell
答:
公式字符串是 Office Open XML 格式 () 的 Excel 在公式中存储指向外部工作簿的链接的方式。因此,您可以获得存储在文件中的内容。[1]Sheet1!$A$3
*.xlsx
你可以看到,如果你解压缩文件,看看.在那里你会发现类似的东西:*.xlsx
/xl/worksheets/sheet*.xml
...
<row ...>
<c ...>
<f>[1]Sheet1!$A$3</f>
<v>...</v>
</c>
...
</row>
...
这可能是为了避免公式字符串太长。
括号内的索引是指存储在以下位置的外部引用:/xl/workbook.xml
...
<externalReferences>
<externalReference r:id="rId2"/>
<externalReference r:id="rId3"/>
</externalReferences>
...
引用 中的外部链接。r:id
/xl/workbook.xml.rels
然后,这引用了 中的外部链接。/xl/externalLinks/externalLink*.xml
然后,此外部链接使用 ./xl/externalLinks/_rels/externalLink*.xml.rels
Apache POI 提供 org.apache.poi.xssf.model.ExternalLinksTable。但这也可能包含 DDE 和/或 OLE 链接文件,而不仅仅是链接的外部工作簿。因此,正确的方法是从工作簿中获取第一个,然后获取相应的,而不是通过XSSFWorkbook.getExternalLinksTable获取所有内容。externalReference
ExternalLinksTable
如果 .cell
XSSFCell
... String getCellFormula(XSSFCell cell) {
String cellFormula = cell.getCellFormula();
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("(\\[)(\\d*)(\\])");
java.util.regex.Matcher matcher = pattern.matcher(cellFormula);
while (matcher.find()) {
String externalWorkbookIndex = matcher.group(2); // 1 based : [1] is first
int externalReferenceIdx = Integer.valueOf(externalWorkbookIndex) - 1; // 0 based : 0 is first
XSSFWorkbook workbook = cell.getSheet().getWorkbook();
if (workbook.getCTWorkbook().getExternalReferences() != null) {
if (workbook.getCTWorkbook().getExternalReferences().getExternalReferenceList().size() > externalReferenceIdx) {
String rId = workbook.getCTWorkbook().getExternalReferences().getExternalReferenceList().get(externalReferenceIdx).getId();
if (workbook.getRelationById(rId) instanceof org.apache.poi.xssf.model.ExternalLinksTable) {
org.apache.poi.xssf.model.ExternalLinksTable externalLinksTable =
(org.apache.poi.xssf.model.ExternalLinksTable)workbook.getRelationById(rId);
String referencedFileName = externalLinksTable.getLinkedFileName();
String match = matcher.group(1) + matcher.group(2) + matcher.group(3);
String replacement = matcher.group(1) + referencedFileName + matcher.group(3);
cellFormula = cellFormula.replace(match, replacement);
}
}
}
}
return cellFormula;
}
评论
currentCell.getCellType() == CellType.FORMULA
你不愿意测试吗?currentCell.getCellType().equals(CellType.FORMULA)