]> source.dussan.org Git - poi.git/commitdiff
Fix bug #45540 - Fix XSSF header and footer support, and include headers and footers...
authorNick Burch <nick@apache.org>
Tue, 5 Aug 2008 11:26:38 +0000 (11:26 +0000)
committerNick Burch <nick@apache.org>
Tue, 5 Aug 2008 11:26:38 +0000 (11:26 +0000)
git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@682674 13f79535-47bb-0310-9956-ffa450edef68

src/documentation/content/xdocs/changes.xml
src/documentation/content/xdocs/status.xml
src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExcelExtractor.java
src/ooxml/java/org/apache/poi/xssf/usermodel/extensions/XSSFHeaderFooter.java
src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/HeaderFooterHelper.java
src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExcelExtractor.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFSheet.java
src/ooxml/testcases/org/apache/poi/xssf/usermodel/helpers/TestHeaderFooterHelper.java

index 46f8c4389547b985847d60fbddad4045520ad2ca..a37166aac56cada3fee7e511873d88b95c5a8354 100644 (file)
@@ -37,6 +37,7 @@
 
                <!-- Don't forget to update status.xml too! -->
         <release version="3.5.1-beta2" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="add">45540 - Fix XSSF header and footer support, and include headers and footers in the output of XSSFExcelExtractor</action>
            <action dev="POI-DEVELOPERS" type="add">45431 - Support for .xlsm files, sufficient for simple files to be loaded by excel without warning</action>
            <action dev="POI-DEVELOPERS" type="add">New class org.apache.poi.hssf.record.RecordFormatException, which DDF uses instead of the HSSF version, and the HSSF version inherits from</action>
            <action dev="POI-DEVELOPERS" type="add">45431 - Partial support for .xlm files. Not quite enough for excel to load them though</action>
index af9648e52078ea4b284b56f567f145b902bc84a0..14d942dc193b905fad30cd6910d4e9ac21289bfc 100644 (file)
@@ -34,6 +34,7 @@
        <!-- Don't forget to update changes.xml too! -->
     <changes>
         <release version="3.5.1-beta2" date="2008-??-??">
+           <action dev="POI-DEVELOPERS" type="add">45540 - Fix XSSF header and footer support, and include headers and footers in the output of XSSFExcelExtractor</action>
            <action dev="POI-DEVELOPERS" type="add">45431 - Support for .xlsm files, sufficient for simple files to be loaded by excel without warning</action>
            <action dev="POI-DEVELOPERS" type="add">New class org.apache.poi.hssf.record.RecordFormatException, which DDF uses instead of the HSSF version, and the HSSF version inherits from</action>
            <action dev="POI-DEVELOPERS" type="add">45431 - Partial support for .xlm files. Not quite enough for excel to load them though</action>
index 113436dc40b4ec9ea128143b4a2caeaf219bedce..b026baf0ea7f013e773a30782042f9697b4e7a44 100644 (file)
@@ -25,9 +25,8 @@ import org.apache.poi.ss.usermodel.Cell;
 import org.apache.poi.ss.usermodel.Comment;
 import org.apache.poi.ss.usermodel.HeaderFooter;
 import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.Workbook;
 import org.apache.poi.xssf.usermodel.XSSFCell;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
 import org.apache.poi.xssf.usermodel.XSSFWorkbook;
 import org.apache.xmlbeans.XmlException;
 import org.openxml4j.exceptions.OpenXML4JException;
@@ -37,7 +36,7 @@ import org.openxml4j.opc.Package;
  * Helper class to extract text from an OOXML Excel file
  */
 public class XSSFExcelExtractor extends POIXMLTextExtractor {
-       private Workbook workbook;
+       private XSSFWorkbook workbook;
        private boolean includeSheetNames = true;
        private boolean formulasNotResults = false;
        private boolean includeCellComments = false;
@@ -91,18 +90,23 @@ public class XSSFExcelExtractor extends POIXMLTextExtractor {
                StringBuffer text = new StringBuffer();
                
                for(int i=0; i<workbook.getNumberOfSheets(); i++) {
-                       Sheet sheet = workbook.getSheetAt(i);
+                       XSSFSheet sheet = (XSSFSheet)workbook.getSheetAt(i);
                        if(includeSheetNames) {
                                text.append(workbook.getSheetName(i) + "\n");
                        }
                        
-                       // Header, if present
-                       if(sheet.getHeader() != null) {
-                               text.append(
-                                               extractHeaderFooter(sheet.getHeader())
-                               );
-                       }
-                       
+                       // Header(s), if present
+                       text.append(
+                                       extractHeaderFooter(sheet.getFirstHeader())
+                       );
+                       text.append(
+                                       extractHeaderFooter(sheet.getOddHeader())
+                       );
+                       text.append(
+                                       extractHeaderFooter(sheet.getEvenHeader())
+                       );
+
+                       // Rows and cells
                        for (Object rawR : sheet) {
                                Row row = (Row)rawR;
                                for(Iterator<Cell> ri = row.cellIterator(); ri.hasNext();) {
@@ -133,12 +137,16 @@ public class XSSFExcelExtractor extends POIXMLTextExtractor {
                                text.append("\n");
                        }
                        
-                       // Finally footer, if present
-                       if(sheet.getFooter() != null) {
-                               text.append(
-                                               extractHeaderFooter(sheet.getFooter())
-                               );
-                       }
+                       // Finally footer(s), if present
+                       text.append(
+                                       extractHeaderFooter(sheet.getFirstFooter())
+                       );
+                       text.append(
+                                       extractHeaderFooter(sheet.getOddFooter())
+                       );
+                       text.append(
+                                       extractHeaderFooter(sheet.getEvenFooter())
+                       );
                }
                
                return text.toString();
index 6d1b152e040d34163ee366fa61449cdec3330461..8c79761e950019cb68335171b52ba2efed7b7924 100644 (file)
@@ -24,21 +24,21 @@ import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTHeaderFooter;
 public abstract class XSSFHeaderFooter implements HeaderFooter {
     private HeaderFooterHelper helper;
     private CTHeaderFooter headerFooter;
-    private String value;
 
     public XSSFHeaderFooter(CTHeaderFooter headerFooter) {
        this.headerFooter = headerFooter;
-       this.value = getText();
-       this.value = this.value != null ? this.value : "";
        this.helper = new HeaderFooterHelper();
     }
     
     public CTHeaderFooter getHeaderFooter() {
         return this.headerFooter;
     }
-    
+
     public String getValue() {
-        return this.value;
+        String value = getText();
+        if(value == null)
+               return "";
+        return value;
     }
     
     public abstract String getText();
index 18fddf52ab7ece029c80d7377141ffb258b9527a..41e3ea462e47846d585ea309617c0e8e639e16d0 100644 (file)
@@ -19,55 +19,101 @@ package org.apache.poi.xssf.usermodel.helpers;
 
 
 public class HeaderFooterHelper {
+    // Note - XmlBeans handles entity encoding for us,
+       //  so these should be & forms, not the &amp; ones!
+    private static final String HeaderFooterEntity_L = "&L";
+    private static final String HeaderFooterEntity_C = "&C";
+    private static final String HeaderFooterEntity_R = "&R";
     
-    private static final String HeaderFooterEntity = "&amp;";
-    private static final String HeaderFooterEntity_R = "&amp;R";
-    private static final String HeaderFooterEntity_L = "&amp;L";
-    private static final String HeaderFooterEntity_C = "&amp;C";
+    // These are other entities that may be used in the
+    //  left, center or right. Not exhaustive
+    public static final String HeaderFooterEntity_File = "&F";
+    public static final String HeaderFooterEntity_Date = "&D";
+    public static final String HeaderFooterEntity_Time = "&T";
 
-    public String getCenterSection(String string) {
-        return getSection(string, HeaderFooterEntity_C);
-    }
     public String getLeftSection(String string) {
-        return getSection(string, HeaderFooterEntity_L);
+       return getParts(string)[0];
+    }
+    public String getCenterSection(String string) {
+       return getParts(string)[1];
     }
     public String getRightSection(String string) {
-        return getSection(string, HeaderFooterEntity_R);
+       return getParts(string)[2];
     }
     
-    public String setCenterSection(String string, String newCenter) {
-        return setSection(string, newCenter, HeaderFooterEntity_C);
-    }
     public String setLeftSection(String string, String newLeft) {
-        return setSection(string, newLeft, HeaderFooterEntity_L);
+       String[] parts = getParts(string);
+       parts[0] = newLeft;
+        return joinParts(parts);
+    }
+    public String setCenterSection(String string, String newCenter) {
+       String[] parts = getParts(string);
+       parts[1] = newCenter;
+        return joinParts(parts);
     }
     public String setRightSection(String string, String newRight) {
-        return setSection(string, newRight, HeaderFooterEntity_R);
+       String[] parts = getParts(string);
+       parts[2] = newRight;
+        return joinParts(parts);
     }
     
-    public String setSection(String string, String newSection, String entity) {
-        string = string != null ? string : "";
-        String oldSection = getSection(string, entity);
-        if (oldSection.equals("")) {
-            return string.concat(entity + newSection);
-        }
-        return string.replaceAll(entity + oldSection, entity + newSection);
+    /**
+     * Split into left, center, right
+     */
+    private String[] getParts(String string) {
+       String[] parts = new String[] { "", "", "" };
+       if(string == null)
+               return parts;
+       
+       // They can come in any order, which is just nasty
+       // Work backwards from the end, picking the last
+       //  on off each time as we go
+       int lAt = 0;
+       int cAt = 0;
+       int rAt = 0;
+       
+       while(
+               // Ensure all indicies get updated, then -1 tested
+               (lAt = string.indexOf(HeaderFooterEntity_L)) > -2 &&
+               (cAt = string.indexOf(HeaderFooterEntity_C)) > -2 &&  
+               (rAt = string.indexOf(HeaderFooterEntity_R)) > -2 &&
+               (lAt > -1 || cAt > -1 || rAt > -1)
+       ) {
+               // Pick off the last one
+               if(rAt > cAt && rAt > lAt) {
+                       parts[2] = string.substring(rAt + HeaderFooterEntity_R.length());
+                       string = string.substring(0, rAt);
+               } else if(cAt > rAt && cAt > lAt) {
+                       parts[1] = string.substring(cAt + HeaderFooterEntity_C.length());
+                       string = string.substring(0, cAt);
+               } else {
+                       parts[0] = string.substring(lAt + HeaderFooterEntity_L.length());
+                       string = string.substring(0, lAt);
+               }
+       }
+       
+       return parts;
     }
-
-    private String getSection(String string, String entity) {
-        if (string == null) {
-            return "";
-        }
-        String stringAfterEntity = "";
-        if (string.indexOf(entity) >= 0) {
-            stringAfterEntity = string.substring(string.indexOf(entity) + entity.length());
-        }
-        String nextEntity = "";
-        if (stringAfterEntity.indexOf(HeaderFooterEntity) > 0) {
-            nextEntity = stringAfterEntity.substring(stringAfterEntity.indexOf(HeaderFooterEntity), stringAfterEntity.indexOf(HeaderFooterEntity) + (HeaderFooterEntity.length()));
-            stringAfterEntity = stringAfterEntity.substring(0, stringAfterEntity.indexOf(nextEntity));
-        }
-        return stringAfterEntity;
+    private String joinParts(String[] parts) {
+       return joinParts(parts[0], parts[1], parts[2]);
     }
+    private String joinParts(String l, String c, String r) {
+       StringBuffer ret = new StringBuffer();
 
+       // Join as c, l, r
+       if(c.length() > 0) {
+               ret.append(HeaderFooterEntity_C);
+               ret.append(c);
+       }
+       if(l.length() > 0) {
+               ret.append(HeaderFooterEntity_L);
+               ret.append(l);
+       }
+       if(r.length() > 0) {
+               ret.append(HeaderFooterEntity_R);
+               ret.append(r);
+       }
+       
+       return ret.toString();
+    }
 }
index 93f29065cb0269efd34d484231c143766e4e9250..70773ad54c7b8196f4623b497070be3a2022f651 100644 (file)
@@ -192,10 +192,10 @@ public class TestXSSFExcelExtractor extends TestCase {
        /**
         * From bug #45540
         */
-       public void BROKENtestHeaderFooter() throws Exception {
+       public void testHeaderFooter() throws Exception {
                String[] files = new String[] {
+                       "45540_classic_Header.xlsx", "45540_form_Header.xlsx",
                        "45540_classic_Footer.xlsx", "45540_form_Footer.xlsx",
-                       "45540_classic_Header.xlsx", "45540_form_Header.xlsx"
                };
                for(String file : files) {
                        File xml = new File(
@@ -208,8 +208,8 @@ public class TestXSSFExcelExtractor extends TestCase {
                                new XSSFExcelExtractor(new XSSFWorkbook(xml.toString()));
                        String text = extractor.getText();
                        
-                       assertTrue("Unable to find expected word in text\n" + text, text.contains("testdoc"));
-                assertTrue("Unable to find expected word in text\n" + text, text.contains("test phrase")); 
+                       assertTrue("Unable to find expected word in text from " + file + "\n" + text, text.contains("testdoc"));
+               assertTrue("Unable to find expected word in text\n" + text, text.contains("test phrase")); 
                }
        }
 }
index ad8dfc9aeee5a3382d9d6950052f1abf37e60602..5964f69e0470779c5ebbf64f74d190649f7231dc 100644 (file)
@@ -17,6 +17,9 @@
 
 package org.apache.poi.xssf.usermodel;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
 import java.util.Iterator;
 import junit.framework.TestCase;
 import org.apache.poi.ss.usermodel.Cell;
@@ -27,6 +30,7 @@ import org.apache.poi.ss.util.Region;
 import org.apache.poi.xssf.model.CommentsTable;
 import org.apache.poi.xssf.model.StylesTable;
 import org.apache.poi.xssf.usermodel.helpers.ColumnHelper;
+import org.openxml4j.opc.Package;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCol;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTCols;
 import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTComment;
@@ -291,6 +295,74 @@ public class TestXSSFSheet extends TestCase {
         assertEquals("test center footer", sheet.getOddFooter().getCenter());
     }
     
+    public void testExistingHeaderFooter() throws Exception {
+               File xml = new File(
+                               System.getProperty("HSSF.testdata.path") +
+                               File.separator + "45540_classic_Header.xlsx"
+               );
+               assertTrue(xml.exists());
+       
+               XSSFWorkbook workbook = new XSSFWorkbook(xml.toString());
+               XSSFOddHeader hdr;
+               XSSFOddFooter ftr;
+               
+               // Sheet 1 has a header with center and right text
+               XSSFSheet s1 = (XSSFSheet)workbook.getSheetAt(0);
+               assertNotNull(s1.getHeader());
+               assertNotNull(s1.getFooter());
+               hdr = (XSSFOddHeader)s1.getHeader(); 
+               ftr = (XSSFOddFooter)s1.getFooter(); 
+               
+               assertEquals("&Ctestdoc&Rtest phrase", hdr.getText());
+               assertEquals(null, ftr.getText());
+               
+               assertEquals("", hdr.getLeft());
+               assertEquals("testdoc", hdr.getCenter());
+               assertEquals("test phrase", hdr.getRight());
+               
+               assertEquals("", ftr.getLeft());
+               assertEquals("", ftr.getCenter());
+               assertEquals("", ftr.getRight());
+               
+               
+               // Sheet 2 has a footer, but it's empty
+               XSSFSheet s2 = (XSSFSheet)workbook.getSheetAt(1);
+               assertNotNull(s2.getHeader());
+               assertNotNull(s2.getFooter());
+               hdr = (XSSFOddHeader)s2.getHeader(); 
+               ftr = (XSSFOddFooter)s2.getFooter(); 
+               
+               assertEquals(null, hdr.getText());
+               assertEquals("&L&F", ftr.getText());
+               
+               assertEquals("", hdr.getLeft());
+               assertEquals("", hdr.getCenter());
+               assertEquals("", hdr.getRight());
+               
+               assertEquals("&F", ftr.getLeft());
+               assertEquals("", ftr.getCenter());
+               assertEquals("", ftr.getRight());
+               
+               
+               // Save and reload
+               ByteArrayOutputStream baos = new ByteArrayOutputStream();
+               workbook.write(baos);
+               XSSFWorkbook wb = new XSSFWorkbook(Package.open(
+                               new ByteArrayInputStream(baos.toByteArray())
+               ));
+               
+               hdr = (XSSFOddHeader)wb.getSheetAt(0).getHeader();
+               ftr = (XSSFOddFooter)wb.getSheetAt(0).getFooter(); 
+               
+               assertEquals("", hdr.getLeft());
+               assertEquals("testdoc", hdr.getCenter());
+               assertEquals("test phrase", hdr.getRight());
+               
+               assertEquals("", ftr.getLeft());
+               assertEquals("", ftr.getCenter());
+               assertEquals("", ftr.getRight());
+    }
+    
     public void testGetAllHeadersFooters() {
         XSSFWorkbook workbook = new XSSFWorkbook();
         XSSFSheet sheet = (XSSFSheet) workbook.createSheet("Sheet 1");
@@ -626,7 +698,7 @@ public class TestXSSFSheet extends TestCase {
        assertEquals(1, ctWorksheet.getColsArray(0).getColArray(0).getStyle());
        XSSFRow row = (XSSFRow) sheet.createRow(0);
        XSSFCell cell = (XSSFCell) sheet.getRow(0).createCell(3);
-       System.out.println(cell.getCellStyle());
+       //System.out.println(cell.getCellStyle());
        
     }
     
index 9c61d3dfb68581a0caccc04b8b0536435d26803a..2d25e3e95b790a3a694a88aa2199baf7fd19a3e2 100644 (file)
@@ -21,14 +21,20 @@ import junit.framework.TestCase;
 
 import org.apache.poi.xssf.usermodel.helpers.HeaderFooterHelper;
 
-
+/**
+ * Test the header and footer helper.
+ * As we go through XmlBeans, should always use &,
+ *  and not &amp;
+ */
 public class TestHeaderFooterHelper extends TestCase {
     
     public void testGetCenterLeftRightSection() {
         HeaderFooterHelper helper = new HeaderFooterHelper();
-        String headerFooter = "&amp;CTest the center section";
+        
+        String headerFooter = "&CTest the center section";
         assertEquals("Test the center section", helper.getCenterSection(headerFooter));
-        headerFooter = "&amp;CTest the center section&amp;LThe left one&amp;RAnd the right one";
+        
+        headerFooter = "&CTest the center section&LThe left one&RAnd the right one";
         assertEquals("Test the center section", helper.getCenterSection(headerFooter));
         assertEquals("The left one", helper.getLeftSection(headerFooter));
         assertEquals("And the right one", helper.getRightSection(headerFooter));
@@ -44,15 +50,15 @@ public class TestHeaderFooterHelper extends TestCase {
 
         headerFooter = helper.setRightSection(headerFooter, "First right");
         assertEquals("First right", helper.getRightSection(headerFooter));
-        assertEquals("&amp;CFirst added center section&amp;LFirst left&amp;RFirst right", headerFooter);
+        assertEquals("&CFirst added center section&LFirst left&RFirst right", headerFooter);
 
-        headerFooter = helper.setRightSection(headerFooter, "First right&amp");
-        assertEquals("First right&amp", helper.getRightSection(headerFooter));
-        assertEquals("&amp;CFirst added center section&amp;LFirst left&amp;RFirst right&amp", headerFooter);
+        headerFooter = helper.setRightSection(headerFooter, "First right&F");
+        assertEquals("First right&F", helper.getRightSection(headerFooter));
+        assertEquals("&CFirst added center section&LFirst left&RFirst right&F", headerFooter);
         
-        headerFooter = helper.setRightSection(headerFooter, "First right&amp;");
-        assertEquals("First right", helper.getRightSection(headerFooter));
-        assertEquals("&amp;CFirst added center section&amp;LFirst left&amp;RFirst right&amp;", headerFooter);
+        headerFooter = helper.setRightSection(headerFooter, "First right&");
+        assertEquals("First right&", helper.getRightSection(headerFooter));
+        assertEquals("&CFirst added center section&LFirst left&RFirst right&", headerFooter);
     }
     
 }