【问题标题】:How to get merged regions using apache POI's event API?如何使用 apache POI 的事件 API 获取合并区域?
【发布时间】:2012-07-23 08:08:15
【问题描述】:

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

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

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

【问题讨论】:

    标签: java apache-poi


    【解决方案1】:

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

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

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

    【讨论】:

    • 你是对的 - 我在错误的地方搜索。有名为“mergeCell”的元素具有“ref”属性。 ref 的值是例如“A1:B3”。现在,似乎我必须解释该字符串 ("A1:B3") 以获取所有合并区域的列/行索引。谢谢!
    • 那么,合适的地方在哪里?是“mergeCell”元素吗?我也有同样的问题。
    • 我按照你的建议做了,并比较了我刚刚创建的新 xlsx 文件,实际上 - 区别在于 标记之后的 。但不幸的是 - 在我的真实文件中 - 在我加载它之后 - 我在任何地方都没有任何 ,我以常规方式检查它(通过 XSSFWorkbook,这需要大量时间)并且它设法获取合并单元格(14 个元素的arrayList,这实际上应该是)我的文件有什么问题?什么会导致 XSSFReader 无法正确处理合并单元格?
    【解决方案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();
    

    【讨论】:

      【解决方案3】:

      您需要打开流并解析两次。

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

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

      提取并保存在一些列表中。

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

      【讨论】:

        猜你喜欢
        • 2021-01-27
        • 1970-01-01
        • 1970-01-01
        • 2012-06-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-24
        • 1970-01-01
        相关资源
        最近更新 更多