git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@682674 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_5_BETA2
@@ -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> |
@@ -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> |
@@ -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(); |
@@ -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(); |
@@ -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 & 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 = "&"; | |||
private static final String HeaderFooterEntity_R = "&R"; | |||
private static final String HeaderFooterEntity_L = "&L"; | |||
private static final String HeaderFooterEntity_C = "&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(); | |||
} | |||
} |
@@ -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")); | |||
} | |||
} | |||
} |
@@ -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()); | |||
} | |||
@@ -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 & | |||
*/ | |||
public class TestHeaderFooterHelper extends TestCase { | |||
public void testGetCenterLeftRightSection() { | |||
HeaderFooterHelper helper = new HeaderFooterHelper(); | |||
String headerFooter = "&CTest the center section"; | |||
String headerFooter = "&CTest the center section"; | |||
assertEquals("Test the center section", helper.getCenterSection(headerFooter)); | |||
headerFooter = "&CTest the center section&LThe left one&RAnd the right one"; | |||
headerFooter = "&CTest the center section<he 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("&CFirst added center section&LFirst left&RFirst right", headerFooter); | |||
assertEquals("&CFirst added center section&LFirst left&RFirst right", headerFooter); | |||
headerFooter = helper.setRightSection(headerFooter, "First right&"); | |||
assertEquals("First right&", helper.getRightSection(headerFooter)); | |||
assertEquals("&CFirst added center section&LFirst left&RFirst right&", 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&"); | |||
assertEquals("First right", helper.getRightSection(headerFooter)); | |||
assertEquals("&CFirst added center section&LFirst left&RFirst right&", headerFooter); | |||
headerFooter = helper.setRightSection(headerFooter, "First right&"); | |||
assertEquals("First right&", helper.getRightSection(headerFooter)); | |||
assertEquals("&CFirst added center section&LFirst left&RFirst right&", headerFooter); | |||
} | |||
} |