diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java index 8458152fed..268a680d60 100644 --- a/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java +++ b/src/java/org/apache/poi/hssf/usermodel/HSSFSheet.java @@ -867,6 +867,17 @@ public final class HSSFSheet implements org.apache.poi.ss.usermodel.Sheet { return _sheet.getMergedRegionAt(index); } + /** + * @return the list of merged regions + */ + public List getMergedRegions() { + List addresses = new ArrayList(); + for (int i=0; i < _sheet.getNumMergedRegions(); i++) { + addresses.add(_sheet.getMergedRegionAt(i)); + } + return addresses; + } + /** * @return an iterator of the PHYSICAL rows. Meaning the 3rd element may not * be the third row if say for instance the second row is undefined. diff --git a/src/java/org/apache/poi/ss/usermodel/Sheet.java b/src/java/org/apache/poi/ss/usermodel/Sheet.java index 987a35efeb..f0990511ff 100644 --- a/src/java/org/apache/poi/ss/usermodel/Sheet.java +++ b/src/java/org/apache/poi/ss/usermodel/Sheet.java @@ -320,6 +320,13 @@ public interface Sheet extends Iterable { */ public CellRangeAddress getMergedRegion(int index); + /** + * Returns the list of merged regions. + * + * @return the list of merged regions + */ + public List getMergedRegions(); + /** * Returns an iterator of the physical rows * diff --git a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java index ae6c4c4f8d..cefc4f3091 100644 --- a/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/streaming/SXSSFSheet.java @@ -431,7 +431,9 @@ public class SXSSFSheet implements Sheet, Cloneable } /** - * Returns the merged region at the specified index + * Returns the merged region at the specified index. If you want multiple + * regions, it is faster to call {@link #getMergedRegions()} than to call + * this each time. * * @return the merged region at the specified index */ @@ -440,6 +442,17 @@ public class SXSSFSheet implements Sheet, Cloneable return _sh.getMergedRegion(index); } + /** + * Returns the list of merged regions. If you want multiple regions, this is + * faster than calling {@link #getMergedRegion(int)} each time. + * + * @return the list of merged regions + */ + @Override + public List getMergedRegions() { + return _sh.getMergedRegions(); + } + /** * Returns an iterator of the physical rows * diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java index 840ed624d8..43140dcdd3 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java @@ -1082,6 +1082,10 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { } /** + * Returns the merged region at the specified index. If you want multiple + * regions, it is faster to call {@link #getMergedRegions()} than to call + * this each time. + * * @return the merged region at the specified index * @throws IllegalStateException if this worksheet does not contain merged regions */ @@ -1095,6 +1099,27 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet { return CellRangeAddress.valueOf(ref); } + /** + * Returns the list of merged regions. If you want multiple regions, this is + * faster than calling {@link #getMergedRegion(int)} each time. + * + * @return the list of merged regions + * @throws IllegalStateException if this worksheet does not contain merged regions + */ + @SuppressWarnings("deprecation") + @Override + public List getMergedRegions() { + CTMergeCells ctMergeCells = worksheet.getMergeCells(); + if(ctMergeCells == null) throw new IllegalStateException("This worksheet does not contain merged regions"); + + List addresses = new ArrayList(); + for(CTMergeCell ctMergeCell : ctMergeCells.getMergeCellArray()) { + String ref = ctMergeCell.getRef(); + addresses.add(CellRangeAddress.valueOf(ref)); + } + return addresses; + } + /** * Returns the number of merged regions defined in this worksheet * diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetMergeRegions.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetMergeRegions.java new file mode 100644 index 0000000000..416c6217be --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheetMergeRegions.java @@ -0,0 +1,48 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ +package org.apache.poi.xssf.usermodel; + +import static org.junit.Assert.*; + +import java.io.IOException; +import java.util.List; + +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.XSSFTestDataSamples; +import org.junit.Test; + +public class TestXSSFSheetMergeRegions { + @Test + public void testMergeRegionsSpeed() throws IOException { + final XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("57893-many-merges.xlsx"); + try { + final XSSFSheet sheet = wb.getSheetAt(0); + final long start = System.currentTimeMillis(); + final List mergedRegions = sheet.getMergedRegions(); + assertEquals(50000, mergedRegions.size()); + for (CellRangeAddress cellRangeAddress : mergedRegions) { + assertEquals(cellRangeAddress.getFirstRow(), cellRangeAddress.getLastRow()); + assertEquals(2, cellRangeAddress.getNumberOfCells()); + } + long millis = System.currentTimeMillis() - start; + // This time is typically ~800ms, versus ~7800ms to iterate getMergedRegion(int). + assertTrue("Should have taken <2000 ms to iterate 50k merged regions but took " + millis, millis < 2000); + } finally { + wb.close(); + } + } +} diff --git a/test-data/spreadsheet/57893-many-merges.xlsx b/test-data/spreadsheet/57893-many-merges.xlsx new file mode 100644 index 0000000000..572dfec27a Binary files /dev/null and b/test-data/spreadsheet/57893-many-merges.xlsx differ