[bug-65096] XLSX Streaming XML not correctly reading multiple inline Strings

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1885770 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
PJ Fanning 2021-01-21 21:04:24 +00:00
parent 4a632f9389
commit 4013ffa220
3 changed files with 137 additions and 72 deletions

View File

@ -204,7 +204,9 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
if (isTextTag(localName)) {
vIsOpen = true;
// Clear contents cache
value.setLength(0);
if (!isIsOpen) {
value.setLength(0);
}
} else if ("is".equals(localName)) {
// Inline string outer tag
isIsOpen = true;
@ -307,86 +309,19 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
return;
}
String thisStr = null;
// v => contents of a cell
if (isTextTag(localName)) {
vIsOpen = false;
// Process the value contents as required, now we have it all
switch (nextDataType) {
case BOOLEAN:
char first = value.charAt(0);
thisStr = first == '0' ? "FALSE" : "TRUE";
break;
case ERROR:
thisStr = "ERROR:" + value;
break;
case FORMULA:
if(formulasNotResults) {
thisStr = formula.toString();
} else {
String fv = value.toString();
if (this.formatString != null) {
try {
// Try to use the value as a formattable number
double d = Double.parseDouble(fv);
thisStr = formatter.formatRawCellContents(d, this.formatIndex, this.formatString);
} catch(NumberFormatException e) {
// Formula is a String result not a Numeric one
thisStr = fv;
}
} else {
// No formatting applied, just do raw value in all cases
thisStr = fv;
}
}
break;
case INLINE_STRING:
// TODO: Can these ever have formatting on them?
XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());
thisStr = rtsi.toString();
break;
case SST_STRING:
String sstIndex = value.toString();
try {
int idx = Integer.parseInt(sstIndex);
RichTextString rtss = sharedStringsTable.getItemAt(idx);
thisStr = rtss.toString();
}
catch (NumberFormatException ex) {
LOG.log(POILogger.ERROR, "Failed to parse SST index '", sstIndex, ex);
}
break;
case NUMBER:
String n = value.toString();
if (this.formatString != null && n.length() > 0)
thisStr = formatter.formatRawCellContents(Double.parseDouble(n), this.formatIndex, this.formatString);
else
thisStr = n;
break;
default:
thisStr = "(TODO: Unexpected type: " + nextDataType + ")";
break;
if (!isIsOpen) {
outputCell();
}
// Do we have a comment for this cell?
checkForEmptyCellComments(EmptyCellCommentsCheckType.CELL);
XSSFComment comment = comments != null ? comments.findCellComment(new CellAddress(cellRef)) : null;
// Output
output.cell(cellRef, thisStr, comment);
} else if ("f".equals(localName)) {
fIsOpen = false;
} else if ("is".equals(localName)) {
isIsOpen = false;
outputCell();
value.setLength(0);
} else if ("row".equals(localName)) {
// Handle any "missing" cells which had comments attached
checkForEmptyCellComments(EmptyCellCommentsCheckType.END_OF_ROW);
@ -433,6 +368,81 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
}
}
private void outputCell() {
String thisStr = null;
// Process the value contents as required, now we have it all
switch (nextDataType) {
case BOOLEAN:
char first = value.charAt(0);
thisStr = first == '0' ? "FALSE" : "TRUE";
break;
case ERROR:
thisStr = "ERROR:" + value;
break;
case FORMULA:
if(formulasNotResults) {
thisStr = formula.toString();
} else {
String fv = value.toString();
if (this.formatString != null) {
try {
// Try to use the value as a formattable number
double d = Double.parseDouble(fv);
thisStr = formatter.formatRawCellContents(d, this.formatIndex, this.formatString);
} catch(NumberFormatException e) {
// Formula is a String result not a Numeric one
thisStr = fv;
}
} else {
// No formatting applied, just do raw value in all cases
thisStr = fv;
}
}
break;
case INLINE_STRING:
// TODO: Can these ever have formatting on them?
XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());
thisStr = rtsi.toString();
break;
case SST_STRING:
String sstIndex = value.toString();
try {
int idx = Integer.parseInt(sstIndex);
RichTextString rtss = sharedStringsTable.getItemAt(idx);
thisStr = rtss.toString();
}
catch (NumberFormatException ex) {
LOG.log(POILogger.ERROR, "Failed to parse SST index '", sstIndex, ex);
}
break;
case NUMBER:
String n = value.toString();
if (this.formatString != null && n.length() > 0)
thisStr = formatter.formatRawCellContents(Double.parseDouble(n), this.formatIndex, this.formatString);
else
thisStr = n;
break;
default:
thisStr = "(TODO: Unexpected type: " + nextDataType + ")";
break;
}
// Do we have a comment for this cell?
checkForEmptyCellComments(EmptyCellCommentsCheckType.CELL);
XSSFComment comment = comments != null ? comments.findCellComment(new CellAddress(cellRef)) : null;
// Output
output.cell(cellRef, thisStr, comment);
}
/**
* Do a check for, and output, comments in otherwise empty cells.
*/

View File

@ -0,0 +1,55 @@
package org.apache.poi.xssf.eventusermodel;
import org.apache.poi.POIDataSamples;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.util.XMLHelper;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.junit.jupiter.api.Test;
import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;
import java.io.InputStream;
import java.util.Iterator;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class TestXSSFSheetXMLHandler {
private static final POIDataSamples _ssTests = POIDataSamples.getSpreadSheetInstance();
@Test
public void testInlineString() throws Exception {
try (OPCPackage xlsxPackage = OPCPackage.open(_ssTests.openResourceAsStream("InlineString.xlsx"))) {
final XSSFReader reader = new XSSFReader(xlsxPackage);
final Iterator<InputStream> iter = reader.getSheetsData();
try (InputStream stream = iter.next()) {
final XMLReader sheetParser = XMLHelper.getSaxParserFactory().newSAXParser().getXMLReader();
sheetParser.setContentHandler(new XSSFSheetXMLHandler(reader.getStylesTable(),
new ReadOnlySharedStringsTable(xlsxPackage), new SheetContentsHandler() {
int cellCount = 0;
@Override
public void startRow(final int rowNum) {
}
@Override
public void endRow(final int rowNum) {
}
@Override
public void cell(final String cellReference, final String formattedValue,
final XSSFComment comment) {
assertEquals("\uD83D\uDE1Cmore text", formattedValue);
assertEquals(cellCount++, 0);
}
}, false));
sheetParser.parse(new InputSource(stream));
}
}
}
}

Binary file not shown.