]> source.dussan.org Git - poi.git/commitdiff
[bug-62055] Fix XSSFImportFromXML table resize. Thanks to Leonard Kappe. This closes #99
authorPJ Fanning <fanningpj@apache.org>
Sun, 25 Feb 2018 17:06:19 +0000 (17:06 +0000)
committerPJ Fanning <fanningpj@apache.org>
Sun, 25 Feb 2018 17:06:19 +0000 (17:06 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1825315 13f79535-47bb-0310-9956-ffa450edef68

src/examples/src/org/apache/poi/xssf/usermodel/examples/CreateTable.java
src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java
src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFSheet.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTable.java
src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableColumn.java [new file with mode: 0644]
src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFXmlColumnPr.java
src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFImportFromXML.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTable.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTableColumn.java [new file with mode: 0644]
test-data/spreadsheet/CustomXMLMappings-complex-type.xlsx

index e1905f5be25d790d5c0f3ad9cad969d9e83705ad..d1acce5f7247fad8d71921a4298c68666e626dcc 100644 (file)
@@ -75,9 +75,9 @@ public class CreateTable {
                 }
             }
             // Create the columns
-            table.addColumn();
-            table.addColumn();
-            table.addColumn();
+            table.createColumn("Column 1");
+            table.createColumn("Column 2");
+            table.createColumn("Column 3");
 
             // Set which area the table should be placed in
             AreaReference reference = wb.getCreationHelper().createAreaReference(
index c7e211d1455fe79a51bbbd892afcfe29e9d67a90..f95823f423d08deb61c8f4717bbb6597aa3efa18 100644 (file)
@@ -50,9 +50,9 @@ import org.apache.poi.xssf.usermodel.XSSFMap;
 import org.apache.poi.xssf.usermodel.XSSFRow;
 import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFTable;
+import org.apache.poi.xssf.usermodel.XSSFTableColumn;
 import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell;
 import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr;
-import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
@@ -175,35 +175,27 @@ public class XSSFExportToXml implements Comparator<String>{
                 // Exports elements and attributes mapped with tables
                 if (table!=null) {
 
-                    List<CTTableColumn> tableColumns = table.getCTTable().getTableColumns().getTableColumnList();
+                    List<XSSFTableColumn> tableColumns = table.getColumns();
 
                     XSSFSheet sheet = table.getXSSFSheet();
 
-                    int startRow = table.getStartCellReference().getRow();
-                    // In mappings created with Microsoft Excel the first row contains the table header and must be skipped
-                    startRow +=1;
-
+                    int startRow = table.getStartCellReference().getRow() + table.getHeaderRowCount();
                     int endRow = table.getEndCellReference().getRow();
 
                     for(int i = startRow; i<= endRow; i++) {
                         XSSFRow row = sheet.getRow(i);
 
-                        Node tableRootNode = getNodeByXPath(table.getCommonXpath(),doc.getFirstChild(),doc,true);
+                        Node tableRootNode = getNodeByXPath(table.getCommonXpath(), doc.getFirstChild(), doc, true);
 
                         short startColumnIndex = table.getStartCellReference().getCol();
-                        for (int j = startColumnIndex; j <= table.getEndCellReference().getCol(); j++) {
-                            XSSFCell cell = row.getCell(j);
+                        for (XSSFTableColumn tableColumn : tableColumns) {
+                            XSSFCell cell = row.getCell(startColumnIndex + tableColumn.getColumnIndex());
                             if (cell != null) {
-                                int tableColumnIndex = j - startColumnIndex;
-                                if (tableColumnIndex < tableColumns.size()) { 
-                                    CTTableColumn ctTableColumn = tableColumns.get(tableColumnIndex);
-                                    if (ctTableColumn.getXmlColumnPr() != null) {
-                                        XSSFXmlColumnPr pointer = new XSSFXmlColumnPr(table, ctTableColumn,
-                                                ctTableColumn.getXmlColumnPr());
-                                        String localXPath = pointer.getLocalXPath();
-                                        Node currentNode = getNodeByXPath(localXPath,tableRootNode,doc,false);
-                                        mapCellOnNode(cell,currentNode);
-                                    }
+                                XSSFXmlColumnPr xmlColumnPr = tableColumn.getXmlColumnPr();
+                                if (xmlColumnPr != null) {
+                                    String localXPath = xmlColumnPr.getLocalXPath();
+                                    Node currentNode = getNodeByXPath(localXPath,tableRootNode,doc,false);
+                                    mapCellOnNode(cell, currentNode);
                                 }
                             }
                         }
index 8ea6f1a8a43f1f7fe0ed1af94b2ebca5be68d46d..d32dae26fc80f663b948ef98243016bb2c0a67a7 100644 (file)
@@ -47,6 +47,7 @@ import org.apache.poi.xssf.usermodel.XSSFCell;
 import org.apache.poi.xssf.usermodel.XSSFMap;
 import org.apache.poi.xssf.usermodel.XSSFRow;
 import org.apache.poi.xssf.usermodel.XSSFTable;
+import org.apache.poi.xssf.usermodel.XSSFTableColumn;
 import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell;
 import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.STXmlDataType;
@@ -124,25 +125,32 @@ public class XSSFImportFromXML {
 
             String commonXPath = table.getCommonXpath();
             NodeList result = (NodeList) xpath.evaluate(commonXPath, doc, XPathConstants.NODESET);
-            int rowOffset = table.getStartCellReference().getRow() + 1;// the first row contains the table header
-            int columnOffset = table.getStartCellReference().getCol() - 1;
+            int rowOffset = table.getStartCellReference().getRow() + table.getHeaderRowCount();
+            int columnOffset = table.getStartCellReference().getCol();
+
+            table.setDataRowCount(result.getLength());
 
             for (int i = 0; i < result.getLength(); i++) {
 
                 // TODO: implement support for denormalized XMLs (see
                 // OpenOffice part 4: chapter 3.5.1.7)
 
-               Node singleNode = result.item(i).cloneNode(true);
-                for (XSSFXmlColumnPr xmlColumnPr : table.getXmlColumnPrs()) {
+                Node singleNode = result.item(i).cloneNode(true);
+
+                for (XSSFTableColumn tableColum : table.getColumns()) {
+
+                    XSSFXmlColumnPr xmlColumnPr = tableColum.getXmlColumnPr();
+                    if(xmlColumnPr == null) {
+                        continue;
+                    }
 
-                    int localColumnId = (int) xmlColumnPr.getId();
                     int rowId = rowOffset + i;
-                    int columnId = columnOffset + localColumnId;
+                    int columnId = columnOffset + tableColum.getColumnIndex();
                     String localXPath = xmlColumnPr.getLocalXPath();
-                    localXPath = localXPath.substring(localXPath.substring(1).indexOf('/') + 2);
+                    localXPath = localXPath.substring(localXPath.indexOf('/', 1) + 1);
 
                     // TODO: convert the data to the cell format
-                                       String value = (String) xpath.evaluate(localXPath, singleNode, XPathConstants.STRING);
+                    String value = (String) xpath.evaluate(localXPath, singleNode, XPathConstants.STRING);
                     logger.log(POILogger.DEBUG, "Extracting with xpath " + localXPath + " : value is '" + value + "'");
                     XSSFRow row = table.getXSSFSheet().getRow(rowId);
                     if (row == null) {
@@ -161,6 +169,8 @@ public class XSSFImportFromXML {
         }
     }
 
+    
+
     private static enum DataType {
         BOOLEAN(STXmlDataType.BOOLEAN), //
         DOUBLE(STXmlDataType.DOUBLE), //
index f4329abdc4be7a1533951f6b6ee971eabbd69f42..417d1e44e3fe4ca5bfe72fa49a75ca55016818b4 100644 (file)
@@ -80,6 +80,7 @@ import org.apache.poi.util.Beta;
 import org.apache.poi.util.Internal;
 import org.apache.poi.util.POILogFactory;
 import org.apache.poi.util.POILogger;
+import org.apache.poi.util.Removal;
 import org.apache.poi.util.Units;
 import org.apache.poi.xssf.model.CommentsTable;
 import org.apache.poi.xssf.usermodel.XSSFPivotTable.PivotTableReferenceConfigurator;
@@ -4057,10 +4058,28 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet  {
     }
 
     /**
-     * Creates a new Table, and associates it with this Sheet
+     * Creates a new Table, and associates it with this Sheet. The table does
+     * not yet have an area defined and needs to be initialized by calling
+     * {@link XSSFTable#setArea(AreaReference)}.
+     * 
+     * @deprecated Use {@link #createTable(AreaReference))} instead
      */
+    @Deprecated
+    @Removal(version = "4.2.0")
     public XSSFTable createTable() {
-        if(! worksheet.isSetTableParts()) {
+        return createTable(null);
+    }
+    
+    /**
+     * Creates a new Table, and associates it with this Sheet.
+     *
+     * @param tableArea
+     *            the area that the table should cover, should not be {@null}
+     * @return the created table
+     * @since 4.0.0
+     */
+    public XSSFTable createTable(AreaReference tableArea) {
+        if (!worksheet.isSetTableParts()) {
             worksheet.addNewTableParts();
         }
 
@@ -4093,6 +4112,10 @@ public class XSSFSheet extends POIXMLDocumentPart implements Sheet  {
 
         tables.put(tbl.getId(), table);
 
+        if(tableArea != null) {
+            table.setArea(tableArea);
+        }
+        
         return table;
     }
 
index 5d84662405c277b38a784f04d74471cda0b8739d..0fbd8d333b587bc504985cd67fa8ee16396e79bb 100644 (file)
@@ -24,6 +24,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Locale;
@@ -32,12 +33,14 @@ import org.apache.poi.POIXMLDocumentPart;
 import org.apache.poi.openxml4j.opc.PackagePart;
 import org.apache.poi.ss.SpreadsheetVersion;
 import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.ss.usermodel.DataFormatter;
 import org.apache.poi.ss.usermodel.Table;
 import org.apache.poi.ss.usermodel.TableStyleInfo;
 import org.apache.poi.ss.util.AreaReference;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.util.Internal;
+import org.apache.poi.util.Removal;
 import org.apache.poi.util.StringUtil;
 import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr;
 import org.apache.xmlbeans.XmlException;
@@ -48,12 +51,12 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.TableDocument;
 
 /**
  * 
- * This class implements the Table Part (Open Office XML Part 4:
- * chapter 3.5.1)
+ * This class implements the Table Part (Open Office XML Part 4: chapter 3.5.1)
  * 
- * This implementation works under the assumption that a table contains mappings to a subtree of an XML.
- * The root element of this subtree an occur multiple times (one for each row of the table). The child nodes
- * of the root element can be only attributes or element with maxOccurs=1 property set
+ * Columns of this table may contains mappings to a subtree of an XML. The root
+ * element of this subtree can occur multiple times (one for each row of the
+ * table). The child nodes of the root element can be only attributes or
+ * elements with maxOccurs=1 property set.
  * 
  *
  * @author Roberto Manicardi
@@ -61,8 +64,8 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.TableDocument;
 public class XSSFTable extends POIXMLDocumentPart implements Table {
 
     private CTTable ctTable;
-    private transient List<XSSFXmlColumnPr> xmlColumnPr;
-    private transient CTTableColumn[] ctColumns;
+    private transient List<XSSFXmlColumnPr> xmlColumnPrs;
+    private transient List<XSSFTableColumn> tableColumns;
     private transient HashMap<String, Integer> columnMap;
     private transient CellReference startCellReference;
     private transient CellReference endCellReference;    
@@ -155,18 +158,6 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
         
         return false;
     }
-
-    /**
-      * caches table columns for performance.
-      * Updated via updateHeaders
-      * @since 3.15 beta 2
-      */
-    private CTTableColumn[] getTableColumns() {
-        if (ctColumns == null) {
-            ctColumns = ctTable.getTableColumns().getTableColumnArray();
-        }
-        return ctColumns;
-    }
     
     /**
      * 
@@ -179,9 +170,9 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
     public String getCommonXpath() {
         if (commonXPath == null) {
             String[] commonTokens = {};
-            for (CTTableColumn column : getTableColumns()) {
+            for (XSSFTableColumn column : getColumns()) {
                 if (column.getXmlColumnPr()!=null) {
-                    String xpath = column.getXmlColumnPr().getXpath();
+                    String xpath = column.getXmlColumnPr().getXPath();
                     String[] tokens =  xpath.split("/");
                     if (commonTokens.length==0) {
                         commonTokens = tokens;
@@ -210,45 +201,166 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
         return commonXPath;
     }
 
+    /**
+     * Note this list is static - once read, it does not notice later changes to the underlying column structures
+     * To clear the cache, call {@link #updateHeaders}
+     * @return List of XSSFTableColumn
+     * @since 4.0.0
+     */
+    public List<XSSFTableColumn> getColumns() {
+        if (tableColumns == null) {
+           List<XSSFTableColumn> columns = new ArrayList<>();
+            CTTableColumns ctTableColumns = ctTable.getTableColumns();
+            if (ctTableColumns != null) {
+                for (CTTableColumn column : ctTableColumns.getTableColumnList()) {
+                    XSSFTableColumn tableColumn = new XSSFTableColumn(this, column);
+                    columns.add(tableColumn);
+                }
+            }
+            tableColumns = Collections.unmodifiableList(columns);
+        }
+        return tableColumns;
+    }
     
     /**
      * Note this list is static - once read, it does not notice later changes to the underlying column structures
      * To clear the cache, call {@link #updateHeaders}
+     * 
+     * @deprecated Use {@link XSSFTableColumn#getXmlColumnPr()} instead.
+     * 
      * @return List of XSSFXmlColumnPr
      */
+    @Deprecated
+    @Removal(version="4.2.0")
     public List<XSSFXmlColumnPr> getXmlColumnPrs() {
-        if (xmlColumnPr==null) {
-            xmlColumnPr = new ArrayList<>();
-            for (CTTableColumn column: getTableColumns()) {
-                if (column.getXmlColumnPr()!=null) {
-                    XSSFXmlColumnPr columnPr = new XSSFXmlColumnPr(this,column,column.getXmlColumnPr());
-                    xmlColumnPr.add(columnPr);
+        if (xmlColumnPrs == null) {
+            xmlColumnPrs = new ArrayList<>();
+            for (XSSFTableColumn column: getColumns()) {
+                XSSFXmlColumnPr xmlColumnPr = column.getXmlColumnPr();
+                if (xmlColumnPr != null) {
+                    xmlColumnPrs.add(xmlColumnPr);
                 }
             }
         }
-        return xmlColumnPr;
+        return xmlColumnPrs;
     }
     
     /**
-     * Adds another column to the table.
+     * Add a new column to the right end of the table.
      * 
-     * Warning - Return type likely to change!
+     * @param columnName
+     *            the unique name of the column, must not be {@code null}
+     * @return the created table column
+     * @since 4.0.0
      */
-    @Internal("Return type likely to change")
-    public void addColumn() {
+    public XSSFTableColumn createColumn(String columnName) {
+        return createColumn(columnName, getColumnCount());
+    }
+    
+    /**
+     * Adds a new column to the table.
+     * 
+     * @param columnName
+     *            the unique name of the column, or {@code null} for a generated name
+     * @param columnIndex
+     *            the 0-based position of the column in the table
+     * @return the created table column
+     * @throws IllegalArgumentException
+     *             if the column name is not unique or missing or if the column
+     *             can't be created at the given index
+     * @since 4.0.0
+     */
+    public XSSFTableColumn createColumn(String columnName, int columnIndex) {
+                
+        int columnCount = getColumnCount();
+        if(columnIndex < 0 || columnIndex > columnCount) {
+            throw new IllegalArgumentException("Column index out of bounds");
+        }
+        
         // Ensure we have Table Columns
         CTTableColumns columns = ctTable.getTableColumns();
         if (columns == null) {
             columns = ctTable.addNewTableColumns();
         }
         
-        // Add another Column, and give it a sensible ID
-        CTTableColumn column = columns.addNewTableColumn();
-        int num = columns.sizeOfTableColumnArray();
-        columns.setCount(num);
-        column.setId(num);
+        // check if name is unique and calculate unique column id 
+        long nextColumnId = 1; 
+        for (XSSFTableColumn tableColumn : getColumns()) {
+            if (columnName != null && columnName.equalsIgnoreCase(tableColumn.getName())) {
+                throw new IllegalArgumentException("Column '" + columnName
+                        + "' already exists. Column names must be unique per table.");
+            }
+            nextColumnId = Math.max(nextColumnId, tableColumn.getId());
+        }
+        
+        // Add the new Column
+        CTTableColumn column = columns.insertNewTableColumn(columnIndex);
+        columns.setCount(columns.sizeOfTableColumnArray());
+        
+        column.setId(nextColumnId);
+        if(columnName != null) {
+            column.setName(columnName); 
+        } else {
+            column.setName("Column " + nextColumnId);
+        }
+        
+        if (ctTable.getRef() != null) {
+            // calculate new area
+            int newColumnCount = columnCount + 1;
+            CellReference tableStart = getStartCellReference();
+            CellReference tableEnd = getEndCellReference();
+            SpreadsheetVersion version = getXSSFSheet().getWorkbook().getSpreadsheetVersion();
+            CellReference newTableEnd = new CellReference(tableEnd.getRow(),
+                    tableStart.getCol() + newColumnCount - 1);
+            AreaReference newTableArea = new AreaReference(tableStart, newTableEnd, version);
+
+            setCellRef(newTableArea);
+        }
         
-        // Have the Headers updated if possible
+        updateHeaders();
+        
+        return getColumns().get(columnIndex);
+    }
+    
+    /**
+     * Remove a column from the table.
+     *
+     * @param column
+     *            the column to remove
+     * @since 4.0.0
+     */
+    public void removeColumn(XSSFTableColumn column) {
+        int columnIndex = getColumns().indexOf(column);
+        if (columnIndex >= 0) {
+            ctTable.getTableColumns().removeTableColumn(columnIndex);
+            updateReferences();
+            updateHeaders();
+        }
+    }
+    
+    /**
+     * Remove a column from the table.
+     *
+     * @param columnIndex
+     *            the 0-based position of the column in the table
+     * @throws IllegalArgumentException
+     *             if no column at the index exists or if the table has only a
+     *             single column
+     * @since 4.0.0
+     */
+    public void removeColumn(int columnIndex) {
+        if (columnIndex < 0 || columnIndex > getColumnCount() - 1) {
+            throw new IllegalArgumentException("Column index out of bounds");
+        }
+        
+        if(getColumnCount() == 1) {
+            throw new IllegalArgumentException("Table must have at least one column");
+        }
+        
+        CTTableColumns tableColumns = ctTable.getTableColumns();
+        tableColumns.removeTableColumn(columnIndex);
+        tableColumns.setCount(tableColumns.getTableColumnList().size());
+        updateReferences();
         updateHeaders();
     }
     
@@ -323,20 +435,25 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
     }
 
     /**
+     * @deprecated Use {@link #getColumnCount()} instead.
+     * 
      * @return  the number of mapped table columns (see Open Office XML Part 4: chapter 3.5.1.4)
      */
+    @Deprecated
+    @Removal(version = "4.2.0")
     public long getNumberOfMappedColumns() {
         return ctTable.getTableColumns().getCount();
     }
 
     /**
-     * @return The reference for the cells of the table
-     * (see Open Office XML Part 4: chapter 3.5.1.2, attribute ref) 
+     * Get the area reference for the cells which this table covers. The area
+     * includes header rows and totals rows.
      *
-     * Does not track updates to underlying changes to CTTable
-     * To synchronize with changes to the underlying CTTable,
-     * call {@link #updateReferences()}.
+     * Does not track updates to underlying changes to CTTable To synchronize
+     * with changes to the underlying CTTable, call {@link #updateReferences()}.
      * 
+     * @return the area of the table
+     * @see "Open Office XML Part 4: chapter 3.5.1.2, attribute ref"
      * @since 3.17 beta 1
      */
     public AreaReference getCellReferences() {
@@ -346,16 +463,35 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
                 SpreadsheetVersion.EXCEL2007
         );
     }
+    
     /**
-     * Updates the reference for the cells of the table
-     * (see Open Office XML Part 4: chapter 3.5.1.2, attribute ref)
-     * and synchronizes any changes
-     * @param refs table range
+     * Set the area reference for the cells which this table covers. The area
+     * includes includes header rows and totals rows. Automatically synchronizes
+     * any changes by calling {@link #updateHeaders()}.
+     * 
+     * Note: The area's width should be identical to the amount of columns in
+     * the table or the table may be invalid. All header rows, totals rows and
+     * at least one data row must fit inside the area. Updating the area with
+     * this method does not create or remove any columns and does not change any
+     * cell values.
      * 
+     * @deprecated Use {@link #setTableArea} instead, which will ensure that the
+     *             the amount of columns always matches table area always width.
+     * 
+     * @see "Open Office XML Part 4: chapter 3.5.1.2, attribute ref"
      * @since 3.17 beta 1
      */
+    @Deprecated
+    @Removal(version="4.2.0")
     public void setCellReferences(AreaReference refs) {
-        // Strip the Sheet name
+        setCellRef(refs);
+    }
+    
+    @Internal
+    protected void setCellRef(AreaReference refs) {
+        
+        // Strip the sheet name,
+        // CTWorksheet.getTableParts defines in which sheet the table is
         String ref = refs.formatAsString();
         if (ref.indexOf('!') != -1) {
             ref = ref.substring(ref.indexOf('!')+1);
@@ -383,6 +519,87 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
         updateHeaders();
     }
     
+    /**
+     * Set the area reference for the cells which this table covers. The area
+     * includes includes header rows and totals rows.
+     * 
+     * Updating the area with this method will create new column as necessary to
+     * the right side of the table but will not modify any cell values.
+     * 
+     * @param refs
+     *            the new area of the table
+     * @throws IllegalArgumentException
+     *             if the area is {@code null} or not
+     * @since 4.0.0
+     */
+    public void setArea(AreaReference tableArea) {
+
+        if (tableArea == null) {
+            throw new IllegalArgumentException("AreaReference must not be null");
+        }
+        
+        String areaSheetName = tableArea.getFirstCell().getSheetName();
+        if (areaSheetName != null && !areaSheetName.equals(getXSSFSheet().getSheetName())) {
+            // TODO to move a table from one sheet to another
+            // CTWorksheet.getTableParts needs to be updated on both sheets
+            throw new IllegalArgumentException(
+                    "The AreaReference must not reference a different sheet");
+        }
+        
+        int rowCount = (tableArea.getLastCell().getRow() - tableArea.getFirstCell().getRow()) + 1;
+        int minimumRowCount = 1 + getHeaderRowCount() + getTotalsRowCount();
+        if (rowCount < minimumRowCount) {
+            throw new IllegalArgumentException("AreaReference needs at least " + minimumRowCount
+                    + " rows, to cover at least one data row and all header rows and totals rows");
+        }
+
+        // Strip the sheet name,
+        // CTWorksheet.getTableParts defines in which sheet the table is
+        String ref = tableArea.formatAsString();
+        if (ref.indexOf('!') != -1) {
+            ref = ref.substring(ref.indexOf('!') + 1);
+        }
+
+        // Update
+        ctTable.setRef(ref);
+        if (ctTable.isSetAutoFilter()) {
+            ctTable.getAutoFilter().setRef(ref);
+        }
+        updateReferences();
+
+        // add or remove columns on the right side of the table
+        int columnCount = getColumnCount();
+        int newColumnCount = (tableArea.getLastCell().getCol() - tableArea.getFirstCell().getCol()) + 1;
+        if (newColumnCount > columnCount) {
+            for (int i = columnCount; i < newColumnCount; i++) {
+                createColumn(null, i);
+            }
+        } else if (newColumnCount < columnCount) {
+            for (int i = columnCount; i > newColumnCount; i--) {
+                removeColumn(i -1);
+            }
+        }
+
+        updateHeaders();
+    }
+    
+    /**
+     * Get the area that this table covers.
+     *
+     * @return the table's area or {@code null} if the area has not been
+     *         initialized
+     * @since 4.0.0
+     */
+    public AreaReference getArea() {
+        String ref = ctTable.getRef();
+        if (ref != null) {
+            SpreadsheetVersion version = getXSSFSheet().getWorkbook().getSpreadsheetVersion();
+            return new AreaReference(ctTable.getRef(), version);
+        } else {
+            return null;
+        }
+    }
+    
     /**
      * @return The reference for the cell in the top-left part of the table
      * (see Open Office XML Part 4: chapter 3.5.1.2, attribute ref) 
@@ -445,12 +662,17 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
 
     
     /**
-     * @return the total number of rows in the selection. (Note: in this version autofiltering is ignored)
+     * Get the total number of rows in this table, including all
+     * {@linkplain #getHeaderRowCount() header rows} and all
+     * {@linkplain #getTotalsRowCount() totals rows}. (Note: in this version
+     * autofiltering is ignored)
+     * 
      * Returns <code>0</code> if the start or end cell references are not set.
      * 
-     * Does not track updates to underlying changes to CTTable
-     * To synchronize with changes to the underlying CTTable,
-     * call {@link #updateReferences()}.
+     * Does not track updates to underlying changes to CTTable To synchronize
+     * with changes to the underlying CTTable, call {@link #updateReferences()}.
+     * 
+     * @return the total number of rows
      */
     public int getRowCount() {
         CellReference from = getStartCellReference();
@@ -462,6 +684,117 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
         }
         return rowCount;
     }
+    
+    /**
+     * Get the number of data rows in this table. This does not include any
+     * header rows or totals rows.
+     * 
+     * Returns <code>0</code> if the start or end cell references are not set.
+     * 
+     * Does not track updates to underlying changes to CTTable To synchronize
+     * with changes to the underlying CTTable, call {@link #updateReferences()}.
+     * 
+     * @return the number of data rows
+     * @since 4.0.0
+     */
+    public int getDataRowCount() {
+        CellReference from = getStartCellReference();
+        CellReference to = getEndCellReference();
+
+        int rowCount = 0;
+        if (from != null && to != null) {
+            rowCount = (to.getRow() - from.getRow() + 1) - getHeaderRowCount()
+                    - getTotalsRowCount();
+        }
+        return rowCount;
+    }
+
+    /**
+     * Set the number of rows in the data area of the table. This does not
+     * affect any header rows or totals rows.
+     * 
+     * If the new row count is less than the current row count, superfluous rows
+     * will be cleared. If the new row count is greater than the current row
+     * count, cells below the table will be overwritten by the table.
+     * 
+     * To resize the table without overwriting cells, use
+     * {@link #setArea(AreaReference)} instead.
+     *
+     * @param newDataRowCount
+     *            new row count for the table
+     * @throws IllegalArgumentException
+     *             if the row count is less than 1
+     * @since 4.0.0
+     */
+    public void setDataRowCount(int newDataRowCount) {
+
+        if (newDataRowCount < 1) {
+            throw new IllegalArgumentException("Table must have at least one data row");
+        }
+
+        updateReferences();
+        int dataRowCount = getDataRowCount();
+        if (dataRowCount == newDataRowCount) {
+            return;
+        }
+
+        CellReference tableStart = getStartCellReference();
+        CellReference tableEnd = getEndCellReference();
+        SpreadsheetVersion version = getXSSFSheet().getWorkbook().getSpreadsheetVersion();
+
+        // calculate new area
+        int newTotalRowCount = getHeaderRowCount() + newDataRowCount + getTotalsRowCount();
+        CellReference newTableEnd = new CellReference(tableStart.getRow() + newTotalRowCount - 1,
+                tableEnd.getCol());
+        AreaReference newTableArea = new AreaReference(tableStart, newTableEnd, version);
+
+        // clear cells
+        CellReference clearAreaStart;
+        CellReference clearAreaEnd;
+        if (newDataRowCount < dataRowCount) {
+            // table size reduced -
+            // clear all table cells that are outside of the new area
+            clearAreaStart = new CellReference(newTableArea.getLastCell().getRow() + 1,
+                    newTableArea.getFirstCell().getCol());
+            clearAreaEnd = tableEnd;
+        } else {
+            // table size increased -
+            // clear all cells below the table that are inside the new area
+            clearAreaStart = new CellReference(tableEnd.getRow() + 1,
+                    newTableArea.getFirstCell().getCol());
+            clearAreaEnd = newTableEnd;
+        }
+        AreaReference areaToClear = new AreaReference(clearAreaStart, clearAreaEnd, version);
+        for (CellReference cellRef : areaToClear.getAllReferencedCells()) {
+            XSSFRow row = getXSSFSheet().getRow(cellRef.getRow());
+            if (row != null) {
+                XSSFCell cell = row.getCell(cellRef.getCol());
+                if (cell != null) {
+                    cell.setCellType(CellType.BLANK);
+                    cell.setCellStyle(null);
+                }
+            }
+        }
+
+        // update table area
+        setCellRef(newTableArea);
+    }
+
+    /**
+     * Get the total number of columns in this table.
+     *
+     * @return the column count
+     * @since 4.0.0
+     */
+    public int getColumnCount() {
+        CTTableColumns tableColumns = ctTable.getTableColumns();
+        if(tableColumns == null) {
+            return 0;
+        }
+        // Casting to int should be safe here - tables larger than the
+        // sheet (which holds the actual data of the table) can't exists.
+        return (int) tableColumns.getCount();
+    }
 
     /**
      * Synchronize table headers with cell values in the parent sheet.
@@ -479,7 +812,7 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
     public void updateHeaders() {
         XSSFSheet sheet = (XSSFSheet)getParent();
         CellReference ref = getStartCellReference();
-        if(ref == null) return;
+        if (ref == null) return;
 
         int headerRow = ref.getRow();
         int firstHeaderColumn = ref.getCol();
@@ -488,18 +821,21 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
 
         if (row != null && row.getCTRow().validate()) {
             int cellnum = firstHeaderColumn;
-            for (CTTableColumn col : getCTTable().getTableColumns().getTableColumnList()) {
-                XSSFCell cell = row.getCell(cellnum);
-                if (cell != null) {
-                    col.setName(formatter.formatCellValue(cell));
+            CTTableColumns ctTableColumns = getCTTable().getTableColumns();
+            if(ctTableColumns != null) {
+                for (CTTableColumn col : ctTableColumns.getTableColumnList()) {
+                    XSSFCell cell = row.getCell(cellnum);
+                    if (cell != null) {
+                        col.setName(formatter.formatCellValue(cell));
+                    }
+                    cellnum++;
                 }
-                cellnum++;
             }
-            ctColumns = null;
-            columnMap = null;
-            xmlColumnPr = null;
-            commonXPath = null;
         }
+        tableColumns = null;
+        columnMap = null;
+        xmlColumnPrs = null;
+        commonXPath = null;
     }
 
     private static String caseInsensitive(String s) {
@@ -522,11 +858,11 @@ public class XSSFTable extends POIXMLDocumentPart implements Table {
         if (columnHeader == null) return -1;
         if (columnMap == null) {
             // FIXME: replace with org.apache.commons.collections.map.CaseInsensitiveMap
-            final int count = getTableColumns().length;
+            final int count = getColumnCount();
             columnMap = new HashMap<>(count * 3 / 2);
             
             int i = 0;
-            for (CTTableColumn column : getTableColumns()) {
+            for (XSSFTableColumn column : getColumns()) {
                 String columnName = column.getName();
                 columnMap.put(caseInsensitive(columnName), i);
                 i++;
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableColumn.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFTableColumn.java
new file mode 100644 (file)
index 0000000..6cb483d
--- /dev/null
@@ -0,0 +1,134 @@
+/* ====================================================================
+   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 org.apache.poi.util.Internal;
+import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;
+import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXmlColumnPr;
+
+/**
+ * A table column of an {@link XSSFTable}. Use {@link XSSFTable#createColumn} to
+ * create new table columns.
+ * 
+ * @author Leonard Kappe
+ * @since 4.0.0
+ */
+public class XSSFTableColumn {
+
+    private final XSSFTable table;
+    private final CTTableColumn ctTableColumn;
+    private XSSFXmlColumnPr xmlColumnPr;
+
+    /**
+     * Create a new table column.
+     *
+     * @param table
+     *            the table which contains the column
+     * @param ctTableColumn
+     *            the table column xmlbean to wrap
+     * @since 4.0.0
+     */
+    @Internal
+    protected XSSFTableColumn(XSSFTable table, CTTableColumn ctTableColumn) {
+        this.table = table;
+        this.ctTableColumn = ctTableColumn;
+    }
+
+    /**
+     * Get the table which contains this column
+     *
+     * @return the table containing this column
+     * @since 4.0.0
+     */
+    public XSSFTable getTable() {
+        return table;
+    }
+
+    /**
+     * Get the identifier of this column, which is is unique per table.
+     * 
+     * @return the column id
+     * @since 4.0.0
+     */
+    public long getId() {
+        return ctTableColumn.getId();
+    }
+
+    /**
+     * Set the identifier of this column, which must be unique per table.
+     * 
+     * It is up to the caller to enforce the uniqueness of the id.
+     * 
+     * @return the column id
+     * @since 4.0.0
+     */
+    public void setId(long columnId) {
+        ctTableColumn.setId(columnId);
+    }
+
+    /**
+     * Get the name of the column, which is is unique per table.
+     * 
+     * @return the column name
+     * @since 4.0.0
+     */
+    public String getName() {
+        return ctTableColumn.getName();
+    }
+
+    /**
+     * Get the name of the column, which is is unique per table.
+     * 
+     * @return the column name
+     * @since 4.0.0
+     */
+    public void setName(String columnName) {
+        ctTableColumn.setName(columnName);
+    }
+
+    /**
+     * Get the XmlColumnPr (XML column properties) if this column has an XML
+     * mapping.
+     *
+     * @return the XmlColumnPr or <code>null</code> if this column has no XML
+     *         mapping
+     * @since 4.0.0
+     */
+    public XSSFXmlColumnPr getXmlColumnPr() {
+        if (xmlColumnPr == null) {
+            CTXmlColumnPr ctXmlColumnPr = ctTableColumn.getXmlColumnPr();
+            if (ctXmlColumnPr != null) {
+                xmlColumnPr = new XSSFXmlColumnPr(this, ctXmlColumnPr);
+            }
+        }
+        return xmlColumnPr;
+    }
+
+    /**
+     * Get the column's position in its table, staring with zero from left to
+     * right.
+     *
+     * @return the column index
+     * @since 4.0.0
+     */
+    public int getColumnIndex() {
+        return table.findColumnIndex(getName());
+    }
+
+}
index 574d64013aaad42aacf5f264a174c60a3ac11eb2..47d34f4bb4c074affa63df052f2b2b1452d0a6b4 100644 (file)
 
 package org.apache.poi.xssf.usermodel.helpers;
 
+import org.apache.poi.util.Internal;
+import org.apache.poi.util.Removal;
 import org.apache.poi.xssf.usermodel.XSSFTable;
+import org.apache.poi.xssf.usermodel.XSSFTableColumn;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXmlColumnPr;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.STXmlDataType.Enum;
 
-
 /**
  * 
  * This class is a wrapper around the CTXmlColumnPr (Open Office XML Part 4:
@@ -32,56 +34,85 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.STXmlDataType.Enum;
  * @author Roberto Manicardi
  */
 public class XSSFXmlColumnPr {
-       
-       private XSSFTable table;
-       private CTTableColumn ctTableColumn;
-       private CTXmlColumnPr ctXmlColumnPr;
-       
-       public XSSFXmlColumnPr(XSSFTable table ,CTTableColumn ctTableColum,CTXmlColumnPr ctXmlColumnPr){
-               this.table = table;
-               this.ctTableColumn = ctTableColum;
-               this.ctXmlColumnPr = ctXmlColumnPr;
-       }
-       
-       public long getMapId(){
-               return ctXmlColumnPr.getMapId();
-       }
-       
-       public String getXPath(){
-               return ctXmlColumnPr.getXpath();
-       }
-       /**
-        * (see Open Office XML Part 4: chapter 3.5.1.3)
-        * @return An integer representing the unique identifier of this column. 
-        */
-       public long getId(){
-               return ctTableColumn.getId();
-       }
-       
-       
-       /**
-        * If the XPath is, for example, /Node1/Node2/Node3 and /Node1/Node2 is the common XPath for the table, the local XPath is /Node3
-        *      
-        * @return the local XPath 
-        */
-       public String getLocalXPath(){
-               StringBuilder localXPath = new StringBuilder();
-               int numberOfCommonXPathAxis = table.getCommonXpath().split("/").length-1;
-               
-               String[] xPathTokens = ctXmlColumnPr.getXpath().split("/");
-               for(int i=numberOfCommonXPathAxis; i<xPathTokens.length;i++){
-                       localXPath.append("/" +xPathTokens[i]);
-               }
-               return localXPath.toString();
-       }
-
-       public Enum getXmlDataType() {
-               
-               return ctXmlColumnPr.getXmlDataType();
-       }
-       
-       
-       
-       
+
+    private XSSFTable table;
+    private XSSFTableColumn tableColumn;
+    private CTXmlColumnPr ctXmlColumnPr;
+
+    /**
+     * Create a new XSSFXmlColumnPr (XML column properties) wrapper around a
+     * CTXmlColumnPr.
+     *
+     * @param tableColumn
+     *            table column for which the XML column properties are set
+     * @param ctXmlColumnPr
+     *            the XML column properties xmlbean to wrap
+     */
+    @Internal
+    public XSSFXmlColumnPr(XSSFTableColumn tableColumn, CTXmlColumnPr ctXmlColumnPr) {
+        this.table = tableColumn.getTable();
+        this.tableColumn = tableColumn;
+        this.ctXmlColumnPr = ctXmlColumnPr;
+    }
+
+    @Deprecated
+    @Removal(version="4.2")
+    public XSSFXmlColumnPr(XSSFTable table, CTTableColumn ctTableColum, CTXmlColumnPr ctXmlColumnPr) {
+        this.table = table;
+        this.tableColumn = table.getColumns().get(table.findColumnIndex(ctTableColum.getName()));
+        this.ctXmlColumnPr = ctXmlColumnPr;
+    }
+
+    /**
+     * Get the column for which these XML column properties are set.
+     *
+     * @return the table column
+     * @since 4.0.0
+     */
+    public XSSFTableColumn getTableColumn() {
+        return tableColumn;
+    }
+
+    public long getMapId() {
+        return ctXmlColumnPr.getMapId();
+    }
+
+    public String getXPath() {
+        return ctXmlColumnPr.getXpath();
+    }
+
+    /**
+     * (see Open Office XML Part 4: chapter 3.5.1.3)
+     * 
+     * @deprecated Use {@link XSSFTableColumn#getId()} instead.
+     * 
+     * @return An integer representing the unique identifier of this column.
+     */
+    @Deprecated
+    @Removal(version="4.2")
+    public long getId() {
+        return tableColumn.getId();
+    }
+
+    /**
+     * If the XPath is, for example, /Node1/Node2/Node3 and /Node1/Node2 is the common XPath for the table, the local XPath is /Node3
+     * 
+     * @return the local XPath
+     */
+    public String getLocalXPath() {
+        StringBuilder localXPath = new StringBuilder();
+        int numberOfCommonXPathAxis = table.getCommonXpath().split("/").length-1;
+
+        String[] xPathTokens = ctXmlColumnPr.getXpath().split("/");
+        for (int i = numberOfCommonXPathAxis; i < xPathTokens.length; i++) {
+            localXPath.append("/" + xPathTokens[i]);
+        }
+        return localXPath.toString();
+    }
+
+    public Enum getXmlDataType() {
+
+        return ctXmlColumnPr.getXmlDataType();
+    }
 
 }
index e38e8e9d0ea7eb6fe36ac9aa4c252af8bcf2d61d..e93239d940ac5a90ba70b987dffb8655b3ed2354 100644 (file)
@@ -32,6 +32,7 @@ import java.util.Locale;
 
 import javax.xml.xpath.XPathExpressionException;
 
+import org.apache.poi.ss.usermodel.CellType;
 import org.apache.poi.xssf.XSSFTestDataSamples;
 import org.apache.poi.xssf.usermodel.XSSFMap;
 import org.apache.poi.xssf.usermodel.XSSFRow;
@@ -41,188 +42,200 @@ import org.junit.Test;
 import org.xml.sax.SAXException;
 
 public class TestXSSFImportFromXML {
-       
-       @Test
-       public void testImportFromXML() throws IOException, XPathExpressionException, SAXException{
-               try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMappings.xlsx")) {
-                       String name = "name";
-                       String teacher = "teacher";
-                       String tutor = "tutor";
-                       String cdl = "cdl";
-                       String duration = "duration";
-                       String topic = "topic";
-                       String project = "project";
-                       String credits = "credits";
-
-                       String testXML = "<CORSO>" +
-                                       "<NOME>" + name + "</NOME>" +
-                                       "<DOCENTE>" + teacher + "</DOCENTE>" +
-                                       "<TUTOR>" + tutor + "</TUTOR>" +
-                                       "<CDL>" + cdl + "</CDL>" +
-                                       "<DURATA>" + duration + "</DURATA>" +
-                                       "<ARGOMENTO>" + topic + "</ARGOMENTO>" +
-                                       "<PROGETTO>" + project + "</PROGETTO>" +
-                                       "<CREDITI>" + credits + "</CREDITI>" +
-                                       "</CORSO>\u0000";
-
-                       XSSFMap map = wb.getMapInfo().getXSSFMapByName("CORSO_mapping");
-                       assertNotNull(map);
-                       XSSFImportFromXML importer = new XSSFImportFromXML(map);
-
-                       importer.importFromXML(testXML);
-
-                       XSSFSheet sheet = wb.getSheetAt(0);
-
-                       XSSFRow row = sheet.getRow(0);
-                       assertTrue(row.getCell(0).getStringCellValue().equals(name));
-                       assertTrue(row.getCell(1).getStringCellValue().equals(teacher));
-                       assertTrue(row.getCell(2).getStringCellValue().equals(tutor));
-                       assertTrue(row.getCell(3).getStringCellValue().equals(cdl));
-                       assertTrue(row.getCell(4).getStringCellValue().equals(duration));
-                       assertTrue(row.getCell(5).getStringCellValue().equals(topic));
-                       assertTrue(row.getCell(6).getStringCellValue().equals(project));
-                       assertTrue(row.getCell(7).getStringCellValue().equals(credits));
-               }
-       }
-       
-       @Test(timeout=60000)
-       public void testMultiTable() throws IOException, XPathExpressionException, SAXException{
-               try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMappings-complex-type.xlsx")) {
-                       String cellC6 = "c6";
-                       String cellC7 = "c7";
-                       String cellC8 = "c8";
-                       String cellC9 = "c9";
-
-                       StringBuilder testXML = new StringBuilder("<ns1:MapInfo xmlns:ns1=\"" + NS_SPREADSHEETML + "\" SelectionNamespaces=\"\">" +
-                                       "<ns1:Schema ID=\"" + cellC6 + "\" SchemaRef=\"a\" />" +
-                                       "<ns1:Schema ID=\"" + cellC7 + "\" SchemaRef=\"b\" />" +
-                                       "<ns1:Schema ID=\"" + cellC8 + "\" SchemaRef=\"c\" />" +
-                                       "<ns1:Schema ID=\"" + cellC9 + "\" SchemaRef=\"d\" />");
-
-                       for (int i = 10; i < 10010; i++) {
-                               testXML.append("<ns1:Schema ID=\"c").append(i).append("\" SchemaRef=\"d\" />");
-                       }
-
-                       testXML.append("<ns1:Map ID=\"1\" Name=\"\" RootElement=\"\" SchemaID=\"\" ShowImportExportValidationErrors=\"\" AutoFit=\"\" Append=\"\" PreserveSortAFLayout=\"\" PreserveFormat=\"\">" + "<ns1:DataBinding DataBindingLoadMode=\"\" />" + "</ns1:Map>" + "<ns1:Map ID=\"2\" Name=\"\" RootElement=\"\" SchemaID=\"\" ShowImportExportValidationErrors=\"\" AutoFit=\"\" Append=\"\" PreserveSortAFLayout=\"\" PreserveFormat=\"\">" + "<ns1:DataBinding DataBindingLoadMode=\"\" />" + "</ns1:Map>" + "<ns1:Map ID=\"3\" Name=\"\" RootElement=\"\" SchemaID=\"\" ShowImportExportValidationErrors=\"\" AutoFit=\"\" Append=\"\" PreserveSortAFLayout=\"\" PreserveFormat=\"\">" + "<ns1:DataBinding DataBindingLoadMode=\"\" />" + "</ns1:Map>" + "</ns1:MapInfo>\u0000");
-
-                       XSSFMap map = wb.getMapInfo().getXSSFMapByName("MapInfo_mapping");
-                       assertNotNull(map);
-                       XSSFImportFromXML importer = new XSSFImportFromXML(map);
-
-                       importer.importFromXML(testXML.toString());
-
-                       //Check for Schema element
-                       XSSFSheet sheet = wb.getSheetAt(1);
-
-                       assertEquals(cellC6, sheet.getRow(5).getCell(2).getStringCellValue());
-                       assertEquals(cellC7, sheet.getRow(6).getCell(2).getStringCellValue());
-                       assertEquals(cellC8, sheet.getRow(7).getCell(2).getStringCellValue());
-                       assertEquals(cellC9, sheet.getRow(8).getCell(2).getStringCellValue());
-                       assertEquals("c5001", sheet.getRow(5000).getCell(2).getStringCellValue());
-               }
-       }
-
-       
-       @Test
-       public void testSingleAttributeCellWithNamespace() throws IOException, XPathExpressionException, SAXException{
-               try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMapping-singleattributenamespace.xlsx")) {
-                       int id = 1;
-                       String displayName = "dispName";
-                       String ref = "19";
-                       int count = 21;
-
-                       String testXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>" +
-                                       "<ns1:table xmlns:ns1=\"" + NS_SPREADSHEETML + "\" id=\"" + id + "\" displayName=\"" + displayName + "\" ref=\"" + ref + "\">" +
-                                       "<ns1:tableColumns count=\"" + count + "\" />" +
-                                       "</ns1:table>\u0000";
-                       XSSFMap map = wb.getMapInfo().getXSSFMapByName("table_mapping");
-                       assertNotNull(map);
-                       XSSFImportFromXML importer = new XSSFImportFromXML(map);
-                       importer.importFromXML(testXML);
-
-                       //Check for Schema element
-                       XSSFSheet sheet = wb.getSheetAt(0);
-
-                       assertEquals(new Double(id), sheet.getRow(28).getCell(1).getNumericCellValue(), 0);
-                       assertEquals(displayName, sheet.getRow(11).getCell(5).getStringCellValue());
-                       assertEquals(ref, sheet.getRow(14).getCell(7).getStringCellValue());
-                       assertEquals(new Double(count), sheet.getRow(18).getCell(3).getNumericCellValue(), 0);
-               }
-       }
-       
-       @Test
-       public void testOptionalFields_Bugzilla_55864() throws IOException, XPathExpressionException, SAXException {
-               try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55864.xlsx")) {
-                       String testXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
-                                       "<PersonInfoRoot>" +
-                                       "<PersonData>" +
-                                       "<FirstName>Albert</FirstName>" +
-                                       "<LastName>Einstein</LastName>" +
-                                       "<BirthDate>1879-03-14</BirthDate>" +
-                                       "</PersonData>" +
-                                       "</PersonInfoRoot>";
-
-                       XSSFMap map = wb.getMapInfo().getXSSFMapByName("PersonInfoRoot_Map");
-                       assertNotNull(map);
-                       XSSFImportFromXML importer = new XSSFImportFromXML(map);
-
-                       importer.importFromXML(testXML);
-
-                       XSSFSheet sheet = wb.getSheetAt(0);
-
-                       XSSFRow rowHeadings = sheet.getRow(0);
-                       XSSFRow rowData = sheet.getRow(1);
-
-                       assertEquals("FirstName", rowHeadings.getCell(0).getStringCellValue());
-                       assertEquals("Albert", rowData.getCell(0).getStringCellValue());
-
-                       assertEquals("LastName", rowHeadings.getCell(1).getStringCellValue());
-                       assertEquals("Einstein", rowData.getCell(1).getStringCellValue());
-
-                       assertEquals("BirthDate", rowHeadings.getCell(2).getStringCellValue());
-                       assertEquals("1879-03-14", rowData.getCell(2).getStringCellValue());
-
-                       // Value for OptionalRating is declared optional (minOccurs=0) in 55864.xlsx
-                       assertEquals("OptionalRating", rowHeadings.getCell(3).getStringCellValue());
-                       assertNull("", rowData.getCell(3));
-               }
-       }
-
-       @Test
-       public void testOptionalFields_Bugzilla_57890() throws IOException, ParseException, XPathExpressionException, SAXException {
-               XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("57890.xlsx");
-
-               String testXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + "<TestInfoRoot>"
-                               + "<TestData>" + "<Int>" + Integer.MIN_VALUE + "</Int>" + "<UnsignedInt>12345</UnsignedInt>"
-                               + "<double>1.0000123</double>" + "<Date>1991-03-14</Date>" + "</TestData>" + "</TestInfoRoot>";
-
-               XSSFMap map = wb.getMapInfo().getXSSFMapByName("TestInfoRoot_Map");
-               assertNotNull(map);
-               XSSFImportFromXML importer = new XSSFImportFromXML(map);
-
-               importer.importFromXML(testXML);
-
-               XSSFSheet sheet = wb.getSheetAt(0);
-
-               XSSFRow rowHeadings = sheet.getRow(0);
-               XSSFRow rowData = sheet.getRow(1);
-
-               assertEquals("Date", rowHeadings.getCell(0).getStringCellValue());
-               Date date = new SimpleDateFormat("yyyy-MM-dd", DateFormatSymbols.getInstance(Locale.ROOT)).parse("1991-3-14");
-               assertEquals(date, rowData.getCell(0).getDateCellValue());
-
-               assertEquals("Amount Int", rowHeadings.getCell(1).getStringCellValue());
-               assertEquals(new Double(Integer.MIN_VALUE), rowData.getCell(1).getNumericCellValue(), 0);
-
-               assertEquals("Amount Double", rowHeadings.getCell(2).getStringCellValue());
-               assertEquals(1.0000123, rowData.getCell(2).getNumericCellValue(), 0);
-
-               assertEquals("Amount UnsignedInt", rowHeadings.getCell(3).getStringCellValue());
-               assertEquals(new Double(12345), rowData.getCell(3).getNumericCellValue(), 0);
-               
-               wb.close();
-       }
-       
-       
-       
+
+    @Test
+    public void testImportFromXML() throws IOException, XPathExpressionException, SAXException{
+        try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMappings.xlsx")) {
+            String name = "name";
+            String teacher = "teacher";
+            String tutor = "tutor";
+            String cdl = "cdl";
+            String duration = "duration";
+            String topic = "topic";
+            String project = "project";
+            String credits = "credits";
+
+            String testXML = "<CORSO>" +
+                    "<NOME>" + name + "</NOME>" +
+                    "<DOCENTE>" + teacher + "</DOCENTE>" +
+                    "<TUTOR>" + tutor + "</TUTOR>" +
+                    "<CDL>" + cdl + "</CDL>" +
+                    "<DURATA>" + duration + "</DURATA>" +
+                    "<ARGOMENTO>" + topic + "</ARGOMENTO>" +
+                    "<PROGETTO>" + project + "</PROGETTO>" +
+                    "<CREDITI>" + credits + "</CREDITI>" +
+                    "</CORSO>\u0000";
+
+            XSSFMap map = wb.getMapInfo().getXSSFMapByName("CORSO_mapping");
+            assertNotNull(map);
+            XSSFImportFromXML importer = new XSSFImportFromXML(map);
+
+            importer.importFromXML(testXML);
+
+            XSSFSheet sheet = wb.getSheetAt(0);
+
+            XSSFRow row = sheet.getRow(0);
+            assertTrue(row.getCell(0).getStringCellValue().equals(name));
+            assertTrue(row.getCell(1).getStringCellValue().equals(teacher));
+            assertTrue(row.getCell(2).getStringCellValue().equals(tutor));
+            assertTrue(row.getCell(3).getStringCellValue().equals(cdl));
+            assertTrue(row.getCell(4).getStringCellValue().equals(duration));
+            assertTrue(row.getCell(5).getStringCellValue().equals(topic));
+            assertTrue(row.getCell(6).getStringCellValue().equals(project));
+            assertTrue(row.getCell(7).getStringCellValue().equals(credits));
+        }
+    }
+
+    @Test(timeout=60000)
+    public void testMultiTable() throws IOException, XPathExpressionException, SAXException{
+        try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMappings-complex-type.xlsx")) {
+            String cellC6 = "c6";
+            String cellC7 = "c7";
+            String cellC8 = "c8";
+            String cellC9 = "c9";
+
+            StringBuilder testXML = new StringBuilder("<ns1:MapInfo xmlns:ns1=\"" + NS_SPREADSHEETML + "\" SelectionNamespaces=\"\">" +
+                    "<ns1:Schema ID=\"" + cellC6 + "\" SchemaRef=\"a\" />" +
+                    "<ns1:Schema ID=\"" + cellC7 + "\" SchemaRef=\"b\" />" +
+                    "<ns1:Schema ID=\"" + cellC8 + "\" SchemaRef=\"c\" />" +
+                    "<ns1:Schema ID=\"" + cellC9 + "\" SchemaRef=\"d\" />");
+
+            int cellOffset = 10; // cell C10
+            for (int i = 0; i < 10000; i++) {
+                testXML.append("<ns1:Schema ID=\"c").append(i + cellOffset).append("\" SchemaRef=\"d\" />");
+            }
+
+            testXML.append("<ns1:Map ID=\"1\" Name=\"\" RootElement=\"\" SchemaID=\"\" ShowImportExportValidationErrors=\"\" AutoFit=\"\" Append=\"\" PreserveSortAFLayout=\"\" PreserveFormat=\"\">" + "<ns1:DataBinding DataBindingLoadMode=\"\" />" + "</ns1:Map>" + "<ns1:Map ID=\"2\" Name=\"\" RootElement=\"\" SchemaID=\"\" ShowImportExportValidationErrors=\"\" AutoFit=\"\" Append=\"\" PreserveSortAFLayout=\"\" PreserveFormat=\"\">" + "<ns1:DataBinding DataBindingLoadMode=\"\" />" + "</ns1:Map>" + "<ns1:Map ID=\"3\" Name=\"\" RootElement=\"\" SchemaID=\"\" ShowImportExportValidationErrors=\"\" AutoFit=\"\" Append=\"\" PreserveSortAFLayout=\"\" PreserveFormat=\"\">" + "<ns1:DataBinding DataBindingLoadMode=\"\" />" + "</ns1:Map>" + "</ns1:MapInfo>\u0000");
+
+            XSSFMap map = wb.getMapInfo().getXSSFMapByName("MapInfo_mapping");
+            assertNotNull(map);
+            XSSFImportFromXML importer = new XSSFImportFromXML(map);
+
+            importer.importFromXML(testXML.toString());
+
+            //Check for Schema element
+            XSSFSheet sheet = wb.getSheetAt(1);
+
+
+            // check table size (+1 for the header row)
+            assertEquals(3 + 1, wb.getTable("Tabella1").getRowCount());
+            assertEquals(10004 + 1, wb.getTable("Tabella2").getRowCount());
+
+            // table1 size was reduced, check that former table cells have been cleared
+            assertEquals(CellType.BLANK, wb.getSheetAt(0).getRow(8).getCell(5).getCellType());
+
+            // table2 size was increased, check that new table cells have been cleared
+            assertEquals(CellType.BLANK, sheet.getRow(10).getCell(3).getCellType());
+
+            assertEquals(cellC6, sheet.getRow(5).getCell(2).getStringCellValue());
+            assertEquals(cellC7, sheet.getRow(6).getCell(2).getStringCellValue());
+            assertEquals(cellC8, sheet.getRow(7).getCell(2).getStringCellValue());
+            assertEquals(cellC9, sheet.getRow(8).getCell(2).getStringCellValue());
+            assertEquals("c5001", sheet.getRow(5000).getCell(2).getStringCellValue());
+        }
+    }
+
+
+    @Test
+    public void testSingleAttributeCellWithNamespace() throws IOException, XPathExpressionException, SAXException{
+        try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMapping-singleattributenamespace.xlsx")) {
+            int id = 1;
+            String displayName = "dispName";
+            String ref = "19";
+            int count = 21;
+
+            String testXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>" +
+                    "<ns1:table xmlns:ns1=\"" + NS_SPREADSHEETML + "\" id=\"" + id + "\" displayName=\"" + displayName + "\" ref=\"" + ref + "\">" +
+                    "<ns1:tableColumns count=\"" + count + "\" />" +
+                    "</ns1:table>\u0000";
+            XSSFMap map = wb.getMapInfo().getXSSFMapByName("table_mapping");
+            assertNotNull(map);
+            XSSFImportFromXML importer = new XSSFImportFromXML(map);
+            importer.importFromXML(testXML);
+
+            //Check for Schema element
+            XSSFSheet sheet = wb.getSheetAt(0);
+
+            assertEquals(new Double(id), sheet.getRow(28).getCell(1).getNumericCellValue(), 0);
+            assertEquals(displayName, sheet.getRow(11).getCell(5).getStringCellValue());
+            assertEquals(ref, sheet.getRow(14).getCell(7).getStringCellValue());
+            assertEquals(new Double(count), sheet.getRow(18).getCell(3).getNumericCellValue(), 0);
+        }
+    }
+
+    @Test
+    public void testOptionalFields_Bugzilla_55864() throws IOException, XPathExpressionException, SAXException {
+        try (XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55864.xlsx")) {
+            String testXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
+                    "<PersonInfoRoot>" +
+                    "<PersonData>" +
+                    "<FirstName>Albert</FirstName>" +
+                    "<LastName>Einstein</LastName>" +
+                    "<BirthDate>1879-03-14</BirthDate>" +
+                    "</PersonData>" +
+                    "</PersonInfoRoot>";
+
+            XSSFMap map = wb.getMapInfo().getXSSFMapByName("PersonInfoRoot_Map");
+            assertNotNull(map);
+            XSSFImportFromXML importer = new XSSFImportFromXML(map);
+
+            importer.importFromXML(testXML);
+
+            XSSFSheet sheet = wb.getSheetAt(0);
+
+            XSSFRow rowHeadings = sheet.getRow(0);
+            XSSFRow rowData = sheet.getRow(1);
+
+            assertEquals("FirstName", rowHeadings.getCell(0).getStringCellValue());
+            assertEquals("Albert", rowData.getCell(0).getStringCellValue());
+
+            assertEquals("LastName", rowHeadings.getCell(1).getStringCellValue());
+            assertEquals("Einstein", rowData.getCell(1).getStringCellValue());
+
+            assertEquals("BirthDate", rowHeadings.getCell(2).getStringCellValue());
+            assertEquals("1879-03-14", rowData.getCell(2).getStringCellValue());
+
+            // Value for OptionalRating is declared optional (minOccurs=0) in 55864.xlsx
+            assertEquals("OptionalRating", rowHeadings.getCell(3).getStringCellValue());
+            assertNull("", rowData.getCell(3));
+        }
+    }
+
+    @Test
+    public void testOptionalFields_Bugzilla_57890() throws IOException, ParseException, XPathExpressionException, SAXException {
+        XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("57890.xlsx");
+
+        String testXML = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" + "<TestInfoRoot>"
+                + "<TestData>" + "<Int>" + Integer.MIN_VALUE + "</Int>" + "<UnsignedInt>12345</UnsignedInt>"
+                + "<double>1.0000123</double>" + "<Date>1991-03-14</Date>" + "</TestData>" + "</TestInfoRoot>";
+
+        XSSFMap map = wb.getMapInfo().getXSSFMapByName("TestInfoRoot_Map");
+        assertNotNull(map);
+        XSSFImportFromXML importer = new XSSFImportFromXML(map);
+
+        importer.importFromXML(testXML);
+
+        XSSFSheet sheet = wb.getSheetAt(0);
+
+        XSSFRow rowHeadings = sheet.getRow(0);
+        XSSFRow rowData = sheet.getRow(1);
+
+        assertEquals("Date", rowHeadings.getCell(0).getStringCellValue());
+        Date date = new SimpleDateFormat("yyyy-MM-dd", DateFormatSymbols.getInstance(Locale.ROOT)).parse("1991-3-14");
+        assertEquals(date, rowData.getCell(0).getDateCellValue());
+
+        assertEquals("Amount Int", rowHeadings.getCell(1).getStringCellValue());
+        assertEquals(new Double(Integer.MIN_VALUE), rowData.getCell(1).getNumericCellValue(), 0);
+
+        assertEquals("Amount Double", rowHeadings.getCell(2).getStringCellValue());
+        assertEquals(1.0000123, rowData.getCell(2).getNumericCellValue(), 0);
+
+        assertEquals("Amount UnsignedInt", rowHeadings.getCell(3).getStringCellValue());
+        assertEquals(new Double(12345), rowData.getCell(3).getNumericCellValue(), 0);
+
+        wb.close();
+    }
+
+
+
 }
index 6ff8b8b007fd9093beec55837c18f62a1bf11e02..9e2f9246dd911ab16e2db1c2cf287335c51541c2 100644 (file)
@@ -31,6 +31,7 @@ import java.util.ArrayList;
 import java.util.List;
 
 import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.util.AreaReference;
 import org.apache.poi.ss.util.CellReference;
 import org.apache.poi.util.IOUtils;
 import org.apache.poi.util.TempFile;
@@ -223,6 +224,14 @@ public final class TestXSSFTable {
         wb.close(); 
     }
 
+    @Test
+    public void getColumnCount() throws IOException {
+        XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("StructuredReferences.xlsx");
+        XSSFTable table = wb.getTable("\\_Prime.1");
+        assertEquals(3, table.getColumnCount());
+        wb.close(); 
+    }
+    
     @Test
     public void getAndSetDisplayName() throws IOException {
         XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("StructuredReferences.xlsx");
@@ -291,7 +300,131 @@ public final class TestXSSFTable {
         
         IOUtils.closeQuietly(wb);
     }
+    
+    @Test
+    public void testGetDataRowCount() {
+        XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sh = wb.createSheet();
+        AreaReference tableArea = new AreaReference("B2:B6", wb.getSpreadsheetVersion());
+        XSSFTable table = sh.createTable(tableArea);
+
+        assertEquals(5, table.getRowCount()); // includes column header
+        assertEquals(4, table.getDataRowCount());
+        
+        table.setArea(new AreaReference("B2:B7", wb.getSpreadsheetVersion()));
+        
+        assertEquals(6, table.getRowCount());
+        assertEquals(5, table.getDataRowCount());
+        
+        IOUtils.closeQuietly(wb);
+    }
+    
+    @Test
+    public void testSetDataRowCount() throws IOException {
+        XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sh = wb.createSheet();
+        
+        // 1 header row + 1 data row 
+        AreaReference tableArea = new AreaReference("C10:C11", wb.getSpreadsheetVersion());
+        XSSFTable table = sh.createTable(tableArea); 
+            
+        assertEquals(2, table.getRowCount()); // includes all data and header/footer rows
+        
+        assertEquals(1, table.getHeaderRowCount());
+        assertEquals(1, table.getDataRowCount());
+        assertEquals(0, table.getTotalsRowCount());
 
+        table.setDataRowCount(5);
+        
+        assertEquals(6, table.getRowCount());
+        
+        assertEquals(1, table.getHeaderRowCount());
+        assertEquals(5, table.getDataRowCount());
+        assertEquals(0, table.getTotalsRowCount());
+        
+        assertEquals("C10:C15", table.getArea().formatAsString());
+        
+        
+        IOUtils.closeQuietly(wb);
+    }
+    
+    @Test
+    public void testSetArea() throws IOException {
+        XSSFWorkbook wb = new XSSFWorkbook();
+            XSSFSheet sh = wb.createSheet();
+            
+            AreaReference tableArea = new AreaReference("B10:D12", wb.getSpreadsheetVersion());
+            XSSFTable table = sh.createTable(tableArea);
+            
+            assertEquals(3, table.getColumnCount());
+            assertEquals(3, table.getRowCount());
+
+            // move table without resizing, shouldn't change row or column count
+            AreaReference tableArea2 = new AreaReference("B11:D13", wb.getSpreadsheetVersion());
+            table.setArea(tableArea2);
+
+            assertEquals(3, table.getColumnCount());
+            assertEquals(3, table.getRowCount());
+            // increase size by 1 row and 1 column
+            AreaReference tableArea3 = new AreaReference("B11:E14", wb.getSpreadsheetVersion());
+            table.setArea(tableArea3);
+            
+            assertEquals(4, table.getColumnCount());
+            assertEquals(4, table.getRowCount());
+
+            // reduce size by 2 rows and 2 columns
+            AreaReference tableArea4 = new AreaReference("C12:D13", wb.getSpreadsheetVersion());
+            table.setArea(tableArea4);
+
+            assertEquals(2, table.getColumnCount());
+            assertEquals(2, table.getRowCount());
+            
+            IOUtils.closeQuietly(wb);
+    }
+    
+    @Test
+    public void testCreateColumn() {
+        XSSFWorkbook wb = new XSSFWorkbook();
+        XSSFSheet sh = wb.createSheet();
+        
+        AreaReference tableArea = new AreaReference("A2:A3", wb.getSpreadsheetVersion());
+        XSSFTable table = sh.createTable(tableArea);
+
+        assertEquals(1, table.getColumnCount());
+        assertEquals(2, table.getRowCount());
+
+        // add columns
+        table.createColumn("Column B");
+        table.createColumn("Column D");
+        table.createColumn("Column C", 2); // add between B and D
+        table.updateReferences();
+        table.updateHeaders();
+
+        assertEquals(4, table.getColumnCount());
+        assertEquals(2, table.getRowCount());
+
+        assertEquals("Column 1", table.getColumns().get(0).getName()); // generated name
+        assertEquals("Column B", table.getColumns().get(1).getName());
+        assertEquals("Column C", table.getColumns().get(2).getName());
+        assertEquals("Column D", table.getColumns().get(3).getName());
+
+        IOUtils.closeQuietly(wb);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testCreateColumnInvalidIndex() throws IOException {
+        try (XSSFWorkbook wb = new XSSFWorkbook();) {
+            XSSFSheet sh = wb.createSheet();
+            AreaReference tableArea = new AreaReference("D2:D3", wb.getSpreadsheetVersion());
+            XSSFTable table = sh.createTable(tableArea);
+
+            // add columns
+            table.createColumn("Column 2", 1);
+            table.createColumn("Column 3", 3); // out of bounds
+        }
+    }
+    
     @Test
     public void testDifferentHeaderTypes() throws IOException {
         XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("TablesWithDifferentHeaders.xlsx");
@@ -345,13 +478,13 @@ public final class TestXSSFTable {
         c5.setCellValue("CD");
         c6.setCellValue("EF");
 
-        // Setting up the CTTable
-        XSSFTable t = s.createTable();
+        // Setting up the table
+        XSSFTable t = s.createTable(new AreaReference("A1:C3", wb.getSpreadsheetVersion()));
         t.setName("TableTest");
         t.setDisplayName("CT_Table_Test");
-        t.addColumn();
-        t.addColumn();
-        t.addColumn();
+        t.createColumn("Column 1");
+        t.createColumn("Column 2");
+        t.createColumn("Column 3");
         t.setCellReferences(wb.getCreationHelper().createAreaReference(
                 new CellReference(c1), new CellReference(c6)
         ));
diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTableColumn.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFTableColumn.java
new file mode 100644 (file)
index 0000000..83cf563
--- /dev/null
@@ -0,0 +1,79 @@
+/* ====================================================================
+   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.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import java.io.IOException;
+import java.util.List;
+
+import org.apache.poi.xssf.XSSFTestDataSamples;
+import org.junit.Test;
+
+public final class TestXSSFTableColumn {
+
+    @Test
+    public void testGetColumnName() throws IOException {
+        try (XSSFWorkbook wb = XSSFTestDataSamples
+                .openSampleWorkbook("CustomXMLMappings-complex-type.xlsx")) {
+            XSSFTable table = wb.getTable("Tabella2");
+
+            List<XSSFTableColumn> tableColumns = table.getColumns();
+
+            assertEquals("ID", tableColumns.get(0).getName());
+            assertEquals("Unmapped Column", tableColumns.get(1).getName());
+            assertEquals("SchemaRef", tableColumns.get(2).getName());
+            assertEquals("Namespace", tableColumns.get(3).getName());
+
+        }
+    }
+
+    @Test
+    public void testGetColumnIndex() throws IOException {
+        try (XSSFWorkbook wb = XSSFTestDataSamples
+                .openSampleWorkbook("CustomXMLMappings-complex-type.xlsx")) {
+            XSSFTable table = wb.getTable("Tabella2");
+
+            List<XSSFTableColumn> tableColumns = table.getColumns();
+
+            assertEquals(0, tableColumns.get(0).getColumnIndex());
+            assertEquals(1, tableColumns.get(1).getColumnIndex());
+            assertEquals(2, tableColumns.get(2).getColumnIndex());
+            assertEquals(3, tableColumns.get(3).getColumnIndex());
+
+        }
+    }
+
+    @Test
+    public void testGetXmlColumnPrs() throws IOException {
+        try (XSSFWorkbook wb = XSSFTestDataSamples
+                .openSampleWorkbook("CustomXMLMappings-complex-type.xlsx")) {
+            XSSFTable table = wb.getTable("Tabella2");
+
+            List<XSSFTableColumn> tableColumns = table.getColumns();
+
+            assertNotNull(tableColumns.get(0).getXmlColumnPr());
+            assertNull(tableColumns.get(1).getXmlColumnPr()); // unmapped column
+            assertNotNull(tableColumns.get(2).getColumnIndex());
+            assertNotNull(tableColumns.get(3).getColumnIndex());
+
+        }
+    }
+}
index 0d6d8d00990b979ddb0a7092c2320c2a3c9486a2..7cd51014798388b687b249abd6e230f673ff2d57 100644 (file)
Binary files a/test-data/spreadsheet/CustomXMLMappings-complex-type.xlsx and b/test-data/spreadsheet/CustomXMLMappings-complex-type.xlsx differ