Allow access from XSSFReader to sheet comments and headers/footers (related to bug #50076)
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1037753 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
1c64221e5a
commit
6161794320
@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
<changes>
|
<changes>
|
||||||
<release version="3.8-beta1" date="2010-??-??">
|
<release version="3.8-beta1" date="2010-??-??">
|
||||||
|
<action dev="poi-developers" type="add">50076 - Allow access from XSSFReader to sheet comments and headers/footers</action>
|
||||||
<action dev="poi-developers" type="add">50076 - Refactor XSSFEventBasedExcelExtractor to make it easier for you to have control over outputting the cell contents</action>
|
<action dev="poi-developers" type="add">50076 - Refactor XSSFEventBasedExcelExtractor to make it easier for you to have control over outputting the cell contents</action>
|
||||||
<action dev="poi-developers" type="fix">50258 - avoid corruption of XSSFWorkbook after applying XSSFRichTextRun#applyFont</action>
|
<action dev="poi-developers" type="fix">50258 - avoid corruption of XSSFWorkbook after applying XSSFRichTextRun#applyFont</action>
|
||||||
<action dev="poi-developers" type="fix">50154 - Allow white spaces and unicode in OPC relationship targets </action>
|
<action dev="poi-developers" type="fix">50154 - Allow white spaces and unicode in OPC relationship targets </action>
|
||||||
|
@ -20,6 +20,7 @@ package org.apache.poi;
|
|||||||
import org.apache.poi.POIXMLProperties.CoreProperties;
|
import org.apache.poi.POIXMLProperties.CoreProperties;
|
||||||
import org.apache.poi.POIXMLProperties.CustomProperties;
|
import org.apache.poi.POIXMLProperties.CustomProperties;
|
||||||
import org.apache.poi.POIXMLProperties.ExtendedProperties;
|
import org.apache.poi.POIXMLProperties.ExtendedProperties;
|
||||||
|
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||||
|
|
||||||
public abstract class POIXMLTextExtractor extends POITextExtractor {
|
public abstract class POIXMLTextExtractor extends POITextExtractor {
|
||||||
/** The POIXMLDocument that's open */
|
/** The POIXMLDocument that's open */
|
||||||
@ -56,10 +57,16 @@ public abstract class POIXMLTextExtractor extends POITextExtractor {
|
|||||||
/**
|
/**
|
||||||
* Returns opened document
|
* Returns opened document
|
||||||
*/
|
*/
|
||||||
public final POIXMLDocument getDocument(){
|
public final POIXMLDocument getDocument() {
|
||||||
return _document;
|
return _document;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the opened OPCPackage that contains the document
|
||||||
|
*/
|
||||||
|
public OPCPackage getPackage() {
|
||||||
|
return _document.getPackage();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an OOXML properties text extractor for the
|
* Returns an OOXML properties text extractor for the
|
||||||
|
@ -30,8 +30,10 @@ import org.apache.poi.openxml4j.opc.OPCPackage;
|
|||||||
import org.apache.poi.openxml4j.opc.PackagePart;
|
import org.apache.poi.openxml4j.opc.PackagePart;
|
||||||
import org.apache.poi.openxml4j.opc.PackagePartName;
|
import org.apache.poi.openxml4j.opc.PackagePartName;
|
||||||
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
import org.apache.poi.openxml4j.opc.PackageRelationship;
|
||||||
|
import org.apache.poi.openxml4j.opc.PackageRelationshipCollection;
|
||||||
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
import org.apache.poi.openxml4j.opc.PackageRelationshipTypes;
|
||||||
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
|
import org.apache.poi.openxml4j.opc.PackagingURIHelper;
|
||||||
|
import org.apache.poi.xssf.model.CommentsTable;
|
||||||
import org.apache.poi.xssf.model.SharedStringsTable;
|
import org.apache.poi.xssf.model.SharedStringsTable;
|
||||||
import org.apache.poi.xssf.model.StylesTable;
|
import org.apache.poi.xssf.model.StylesTable;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFRelation;
|
import org.apache.poi.xssf.usermodel.XSSFRelation;
|
||||||
@ -155,7 +157,7 @@ public class XSSFReader {
|
|||||||
* Current CTSheet bean
|
* Current CTSheet bean
|
||||||
*/
|
*/
|
||||||
private CTSheet ctSheet;
|
private CTSheet ctSheet;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterator over CTSheet objects, returns sheets in <tt>logical</tt> order.
|
* Iterator over CTSheet objects, returns sheets in <tt>logical</tt> order.
|
||||||
* We can't rely on the Ooxml4J's relationship iterator because it returns objects in physical order,
|
* We can't rely on the Ooxml4J's relationship iterator because it returns objects in physical order,
|
||||||
@ -228,7 +230,40 @@ public class XSSFReader {
|
|||||||
public String getSheetName() {
|
public String getSheetName() {
|
||||||
return ctSheet.getName();
|
return ctSheet.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the comments associated with this sheet,
|
||||||
|
* or null if there aren't any
|
||||||
|
*/
|
||||||
|
public CommentsTable getSheetComments() {
|
||||||
|
PackagePart sheetPkg = getSheetPart();
|
||||||
|
|
||||||
|
// Do we have a comments relationship? (Only ever one if so)
|
||||||
|
try {
|
||||||
|
PackageRelationshipCollection commentsList =
|
||||||
|
sheetPkg.getRelationshipsByType(XSSFRelation.SHEET_COMMENTS.getRelation());
|
||||||
|
if(commentsList.size() > 0) {
|
||||||
|
PackageRelationship comments = commentsList.getRelationship(0);
|
||||||
|
PackagePartName commentsName = PackagingURIHelper.createPartName(comments.getTargetURI());
|
||||||
|
PackagePart commentsPart = sheetPkg.getPackage().getPart(commentsName);
|
||||||
|
return new CommentsTable(commentsPart, comments);
|
||||||
|
}
|
||||||
|
} catch (InvalidFormatException e) {
|
||||||
|
return null;
|
||||||
|
} catch (IOException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PackagePart getSheetPart() {
|
||||||
|
String sheetId = ctSheet.getId();
|
||||||
|
return sheetMap.get(sheetId);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We're read only, so remove isn't supported
|
||||||
|
*/
|
||||||
public void remove() {
|
public void remove() {
|
||||||
throw new IllegalStateException("Not supported");
|
throw new IllegalStateException("Not supported");
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,8 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
|
|||||||
private boolean vIsOpen;
|
private boolean vIsOpen;
|
||||||
// Set when F start element is seen
|
// Set when F start element is seen
|
||||||
private boolean fIsOpen;
|
private boolean fIsOpen;
|
||||||
|
// Set when a header/footer element is seen
|
||||||
|
private boolean hfIsOpen;
|
||||||
|
|
||||||
// Set when cell start element is seen;
|
// Set when cell start element is seen;
|
||||||
// used when cell close element is seen.
|
// used when cell close element is seen.
|
||||||
@ -76,26 +78,39 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
|
|||||||
// Gathers characters as they are seen.
|
// Gathers characters as they are seen.
|
||||||
private StringBuffer value = new StringBuffer();
|
private StringBuffer value = new StringBuffer();
|
||||||
private StringBuffer formula = new StringBuffer();
|
private StringBuffer formula = new StringBuffer();
|
||||||
|
private StringBuffer headerFooter = new StringBuffer();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Accepts objects needed while parsing.
|
* Accepts objects needed while parsing.
|
||||||
*
|
*
|
||||||
* @param styles Table of styles
|
* @param styles Table of styles
|
||||||
* @param strings Table of shared strings
|
* @param strings Table of shared strings
|
||||||
* @param cols Minimum number of columns to show
|
|
||||||
* @param target Sink for output
|
|
||||||
*/
|
*/
|
||||||
public XSSFSheetXMLHandler(
|
public XSSFSheetXMLHandler(
|
||||||
StylesTable styles,
|
StylesTable styles,
|
||||||
ReadOnlySharedStringsTable strings,
|
ReadOnlySharedStringsTable strings,
|
||||||
SheetContentsHandler sheetContentsHandler,
|
SheetContentsHandler sheetContentsHandler,
|
||||||
|
DataFormatter dataFormatter,
|
||||||
boolean formulasNotResults) {
|
boolean formulasNotResults) {
|
||||||
this.stylesTable = styles;
|
this.stylesTable = styles;
|
||||||
this.sharedStringsTable = strings;
|
this.sharedStringsTable = strings;
|
||||||
this.output = sheetContentsHandler;
|
this.output = sheetContentsHandler;
|
||||||
this.formulasNotResults = formulasNotResults;
|
this.formulasNotResults = formulasNotResults;
|
||||||
this.nextDataType = xssfDataType.NUMBER;
|
this.nextDataType = xssfDataType.NUMBER;
|
||||||
this.formatter = new DataFormatter();
|
this.formatter = dataFormatter;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Accepts objects needed while parsing.
|
||||||
|
*
|
||||||
|
* @param styles Table of styles
|
||||||
|
* @param strings Table of shared strings
|
||||||
|
*/
|
||||||
|
public XSSFSheetXMLHandler(
|
||||||
|
StylesTable styles,
|
||||||
|
ReadOnlySharedStringsTable strings,
|
||||||
|
SheetContentsHandler sheetContentsHandler,
|
||||||
|
boolean formulasNotResults) {
|
||||||
|
this(styles, strings, sheetContentsHandler, new DataFormatter(), formulasNotResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void startElement(String uri, String localName, String name,
|
public void startElement(String uri, String localName, String name,
|
||||||
@ -122,6 +137,13 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
|
|||||||
fIsOpen = true;
|
fIsOpen = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if("oddHeader".equals(name) || "evenHeader".equals(name) ||
|
||||||
|
"firstHeader".equals(name) || "firstFooter".equals(name) ||
|
||||||
|
"oddFooter".equals(name) || "evenFooter".equals(name)) {
|
||||||
|
hfIsOpen = true;
|
||||||
|
// Clear contents cache
|
||||||
|
headerFooter.setLength(0);
|
||||||
|
}
|
||||||
else if("row".equals(name)) {
|
else if("row".equals(name)) {
|
||||||
int rowNum = Integer.parseInt(attributes.getValue("r")) - 1;
|
int rowNum = Integer.parseInt(attributes.getValue("r")) - 1;
|
||||||
output.startRow(rowNum);
|
output.startRow(rowNum);
|
||||||
@ -222,6 +244,16 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
|
|||||||
} else if ("row".equals(name)) {
|
} else if ("row".equals(name)) {
|
||||||
output.endRow();
|
output.endRow();
|
||||||
}
|
}
|
||||||
|
else if("oddHeader".equals(name) || "evenHeader".equals(name) ||
|
||||||
|
"firstHeader".equals(name)) {
|
||||||
|
hfIsOpen = false;
|
||||||
|
output.headerFooter(headerFooter.toString(), true, name);
|
||||||
|
}
|
||||||
|
else if("oddFooter".equals(name) || "evenFooter".equals(name) ||
|
||||||
|
"firstFooter".equals(name)) {
|
||||||
|
hfIsOpen = false;
|
||||||
|
output.headerFooter(headerFooter.toString(), false, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -236,6 +268,9 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
|
|||||||
if (fIsOpen) {
|
if (fIsOpen) {
|
||||||
formula.append(ch, start, length);
|
formula.append(ch, start, length);
|
||||||
}
|
}
|
||||||
|
if (hfIsOpen) {
|
||||||
|
headerFooter.append(ch, start, length);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -249,5 +284,7 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
|
|||||||
public void endRow();
|
public void endRow();
|
||||||
/** A cell, with the given formatted value, was encountered */
|
/** A cell, with the given formatted value, was encountered */
|
||||||
public void cell(String cellReference, String formattedValue);
|
public void cell(String cellReference, String formattedValue);
|
||||||
|
/** A header or footer has been encountered */
|
||||||
|
public void headerFooter(String text, boolean isHeader, String tagName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,14 +18,20 @@ package org.apache.poi.xssf.extractor;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
import javax.xml.parsers.ParserConfigurationException;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import javax.xml.parsers.SAXParser;
|
import javax.xml.parsers.SAXParser;
|
||||||
import javax.xml.parsers.SAXParserFactory;
|
import javax.xml.parsers.SAXParserFactory;
|
||||||
|
|
||||||
|
import org.apache.poi.POIXMLProperties;
|
||||||
import org.apache.poi.POIXMLTextExtractor;
|
import org.apache.poi.POIXMLTextExtractor;
|
||||||
|
import org.apache.poi.POIXMLProperties.CoreProperties;
|
||||||
|
import org.apache.poi.POIXMLProperties.CustomProperties;
|
||||||
|
import org.apache.poi.POIXMLProperties.ExtendedProperties;
|
||||||
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
import org.apache.poi.openxml4j.exceptions.OpenXML4JException;
|
||||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||||
|
import org.apache.poi.ss.usermodel.DataFormatter;
|
||||||
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
|
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
|
||||||
import org.apache.poi.xssf.eventusermodel.XSSFReader;
|
import org.apache.poi.xssf.eventusermodel.XSSFReader;
|
||||||
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
|
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
|
||||||
@ -43,6 +49,9 @@ import org.xml.sax.XMLReader;
|
|||||||
*/
|
*/
|
||||||
public class XSSFEventBasedExcelExtractor extends POIXMLTextExtractor {
|
public class XSSFEventBasedExcelExtractor extends POIXMLTextExtractor {
|
||||||
private OPCPackage container;
|
private OPCPackage container;
|
||||||
|
private POIXMLProperties properties;
|
||||||
|
|
||||||
|
private Locale locale;
|
||||||
private boolean includeSheetNames = true;
|
private boolean includeSheetNames = true;
|
||||||
private boolean formulasNotResults = false;
|
private boolean formulasNotResults = false;
|
||||||
|
|
||||||
@ -52,6 +61,8 @@ public class XSSFEventBasedExcelExtractor extends POIXMLTextExtractor {
|
|||||||
public XSSFEventBasedExcelExtractor(OPCPackage container) throws XmlException, OpenXML4JException, IOException {
|
public XSSFEventBasedExcelExtractor(OPCPackage container) throws XmlException, OpenXML4JException, IOException {
|
||||||
super(null);
|
super(null);
|
||||||
this.container = container;
|
this.container = container;
|
||||||
|
|
||||||
|
properties = new POIXMLProperties(container);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
@ -79,22 +90,64 @@ public class XSSFEventBasedExcelExtractor extends POIXMLTextExtractor {
|
|||||||
this.formulasNotResults = formulasNotResults;
|
this.formulasNotResults = formulasNotResults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setLocale(Locale locale) {
|
||||||
|
this.locale = locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the opened OPCPackage container.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public OPCPackage getPackage() {
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the core document properties
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CoreProperties getCoreProperties() {
|
||||||
|
return properties.getCoreProperties();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the extended document properties
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public ExtendedProperties getExtendedProperties() {
|
||||||
|
return properties.getExtendedProperties();
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Returns the custom document properties
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CustomProperties getCustomProperties() {
|
||||||
|
return properties.getCustomProperties();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes the given sheet
|
* Processes the given sheet
|
||||||
*/
|
*/
|
||||||
public void processSheet(
|
public void processSheet(
|
||||||
SheetTextExtractor sheetExtractor,
|
SheetContentsHandler sheetContentsExtractor,
|
||||||
StylesTable styles,
|
StylesTable styles,
|
||||||
ReadOnlySharedStringsTable strings,
|
ReadOnlySharedStringsTable strings,
|
||||||
InputStream sheetInputStream)
|
InputStream sheetInputStream)
|
||||||
throws IOException, SAXException {
|
throws IOException, SAXException {
|
||||||
|
|
||||||
|
DataFormatter formatter;
|
||||||
|
if(locale == null) {
|
||||||
|
formatter = new DataFormatter();
|
||||||
|
} else {
|
||||||
|
formatter = new DataFormatter(locale);
|
||||||
|
}
|
||||||
|
|
||||||
InputSource sheetSource = new InputSource(sheetInputStream);
|
InputSource sheetSource = new InputSource(sheetInputStream);
|
||||||
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
|
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
|
||||||
try {
|
try {
|
||||||
SAXParser saxParser = saxFactory.newSAXParser();
|
SAXParser saxParser = saxFactory.newSAXParser();
|
||||||
XMLReader sheetParser = saxParser.getXMLReader();
|
XMLReader sheetParser = saxParser.getXMLReader();
|
||||||
ContentHandler handler = new XSSFSheetXMLHandler(styles, strings, sheetExtractor, formulasNotResults);
|
ContentHandler handler = new XSSFSheetXMLHandler(
|
||||||
|
styles, strings, sheetContentsExtractor, formatter, formulasNotResults);
|
||||||
sheetParser.setContentHandler(handler);
|
sheetParser.setContentHandler(handler);
|
||||||
sheetParser.parse(sheetSource);
|
sheetParser.parse(sheetSource);
|
||||||
} catch(ParserConfigurationException e) {
|
} catch(ParserConfigurationException e) {
|
||||||
@ -162,5 +215,9 @@ public class XSSFEventBasedExcelExtractor extends POIXMLTextExtractor {
|
|||||||
}
|
}
|
||||||
output.append(formattedValue);
|
output.append(formattedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void headerFooter(String text, boolean isHeader, String tagName) {
|
||||||
|
// We don't include headers in the output yet, so ignore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import junit.framework.TestCase;
|
|||||||
import org.apache.poi.openxml4j.opc.OPCPackage;
|
import org.apache.poi.openxml4j.opc.OPCPackage;
|
||||||
import org.apache.poi.util.IOUtils;
|
import org.apache.poi.util.IOUtils;
|
||||||
import org.apache.poi.xssf.XSSFTestDataSamples;
|
import org.apache.poi.xssf.XSSFTestDataSamples;
|
||||||
|
import org.apache.poi.xssf.model.CommentsTable;
|
||||||
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
|
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
|
||||||
import org.apache.poi.POIDataSamples;
|
import org.apache.poi.POIDataSamples;
|
||||||
|
|
||||||
@ -117,6 +118,28 @@ public final class TestXSSFReader extends TestCase {
|
|||||||
assertEquals(4, count);
|
assertEquals(4, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testComments() throws Exception {
|
||||||
|
OPCPackage pkg = XSSFTestDataSamples.openSamplePackage("comments.xlsx");
|
||||||
|
XSSFReader r = new XSSFReader(pkg);
|
||||||
|
XSSFReader.SheetIterator it = (XSSFReader.SheetIterator)r.getSheetsData();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
while(it.hasNext()) {
|
||||||
|
count++;
|
||||||
|
InputStream inp = it.next();
|
||||||
|
inp.close();
|
||||||
|
|
||||||
|
if(count == 1) {
|
||||||
|
assertNotNull(it.getSheetComments());
|
||||||
|
CommentsTable ct = it.getSheetComments();
|
||||||
|
assertEquals(1, ct.getNumberOfAuthors());
|
||||||
|
assertEquals(3, ct.getNumberOfComments());
|
||||||
|
} else {
|
||||||
|
assertNull(it.getSheetComments());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertEquals(3, count);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterating over a workbook with chart sheets in it, using the
|
* Iterating over a workbook with chart sheets in it, using the
|
||||||
|
Loading…
Reference in New Issue
Block a user