3

如何使用 Apache POI 提供的事件 API 获取 Excel 工作表的合并区域(合并单元格)?

使用“传统的”类似 DOM 的解析风格,有一些方法称为Sheet.getNumMergedRegions()Sheet.getMergedRegion(int)。不幸的是,我需要处理巨大的 Excel 文件,即使使用允许使用的最高 Xmx 值(在此项目中),也会出现内存不足的错误。所以我想使用事件 API,但无法找到如何获取有关合并区域的信息,我需要知道这些信息才能正确“理解”内容......

使用此处给出的示例:http: //poi.apache.org/spreadsheet/how-to.html#xssf_sax_api 我为合并区域的每个单元格获取事件(尽管只有第一个单元格包含任何文本内容)。所以也许,如果没有更直接的方法,这将有助于了解这些合并的单元格如何(安全地)与其他(空)单元格区分开来......

4

3 回答 3

3

我不确定合并的单元格信息存储在哪里,但我很确定它不会与单元格数据本身有关,因为这不是 Excel 方式。

我建议你做的是创建一个没有合并单元格的简单文件。然后,复制一份,并添加一个合并的单元格。解压缩这两个文件(.xlsx 是 xml 文件的 zip),然后区分它们。这将很快向您展示将单元格标记为合并的设置。(我的预感是它将位于工作表设置中的某个位置,靠近开始但不靠近单元格值 BICBW)

一旦知道合并单元格的详细信息所在的位置,就可以查看用于处理合并单元格的 XSSF UserModel 代码,以了解它们的工作方式、操作方式、选项等。记住这一点,您可以查看文件格式文档以获取完整的详细信息,但首先要了解的内容可能有点繁琐和详细。最后,您可以添加代码以使用合并的信息详细信息,一旦您知道从哪里获取它!

于 2012-07-23T11:59:52.143 回答
2

扩展迈克的答案。您可以创建一个ContentHandler来定位合并区域,例如:

import java.util.ArrayList;
import java.util.List;

import org.apache.poi.ss.util.CellRangeAddress;

import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

public class MergedRegionLocator extends DefaultHandler {
    private final List<CellRangeAddress> mergedRegions = new ArrayList<>();

    @Override
    public void startElement (String uri, String localName, String name, Attributes attributes) {
        if ("mergeCell".equals(name) && attributes.getValue("ref") != null) {
            mergedRegions.add(CellRangeAddress.valueOf(attributes.getValue("ref")));
        }
    }

    public CellRangeAddress getMergedRegion (int index) {
        return mergedRegions.get(index);
    }

    public List<CellRangeAddress> getMergedRegions () {
        return mergedRegions;
    }
}

将其与 POI 基于事件的解析一起使用的示例:

OPCPackage pkg = OPCPackage.open(new FileInputStream("test.xlsx"));
XSSFReader reader = new XSSFReader(pkg);
InputStream sheetData = reader.getSheetsData().next();

MergedRegionLocator mergedRegionLocator = new MergedRegionLocator();
XMLReader parser = XMLReaderFactory.createXMLReader();
parser.setContentHandler(mergedRegionLocator);
parser.parse(new InputSource(sheetData));

mergedRegionLocator.getMergedRegions();
于 2017-03-20T20:30:44.410 回答
1

您需要打开流并对其进行两次解析。

第一次 - 提取合并的单元格。它们出现在标记sheet...xml之后的文件<sheetData>...</sheetData>中,如下例所示:

...
< /sheetData >
< mergeCells count="2" >
    < mergeCell ref="A2:C2"/ >
    < mergeCell ref="A3:A7"/ >
 </mergeCells >

将其提取并保留在一些列表中。

然后再次重新打开流并像往常一样解析它,以提取行和单元格。在endElement(...)完成每一行的方法中,检查该行是否(部分或完全)出现在合并区域中。

于 2015-04-08T13:28:45.407 回答