[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)) { if (isTextTag(localName)) {
vIsOpen = true; vIsOpen = true;
// Clear contents cache // Clear contents cache
if (!isIsOpen) {
value.setLength(0); value.setLength(0);
}
} else if ("is".equals(localName)) { } else if ("is".equals(localName)) {
// Inline string outer tag // Inline string outer tag
isIsOpen = true; isIsOpen = true;
@ -307,12 +309,68 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
return; return;
} }
String thisStr = null;
// v => contents of a cell // v => contents of a cell
if (isTextTag(localName)) { if (isTextTag(localName)) {
vIsOpen = false; vIsOpen = false;
if (!isIsOpen) {
outputCell();
}
} 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);
// Finish up the row
output.endRow(rowNum);
// some sheets do not have rowNum set in the XML, Excel can read them so we should try to read them as well
nextRowNum = rowNum + 1;
} else if ("sheetData".equals(localName)) {
// Handle any "missing" cells which had comments attached
checkForEmptyCellComments(EmptyCellCommentsCheckType.END_OF_SHEET_DATA);
// indicate that this sheet is now done
output.endSheet();
}
else if("oddHeader".equals(localName) || "evenHeader".equals(localName) ||
"firstHeader".equals(localName)) {
hfIsOpen = false;
output.headerFooter(headerFooter.toString(), true, localName);
}
else if("oddFooter".equals(localName) || "evenFooter".equals(localName) ||
"firstFooter".equals(localName)) {
hfIsOpen = false;
output.headerFooter(headerFooter.toString(), false, localName);
}
}
/**
* Captures characters only if a suitable element is open.
* Originally was just "v"; extended for inlineStr also.
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (vIsOpen) {
value.append(ch, start, length);
}
if (fIsOpen) {
formula.append(ch, start, length);
}
if (hfIsOpen) {
headerFooter.append(ch, start, length);
}
}
private void outputCell() {
String thisStr = null;
// Process the value contents as required, now we have it all // Process the value contents as required, now we have it all
switch (nextDataType) { switch (nextDataType) {
case BOOLEAN: case BOOLEAN:
@ -383,54 +441,6 @@ public class XSSFSheetXMLHandler extends DefaultHandler {
// Output // Output
output.cell(cellRef, thisStr, comment); output.cell(cellRef, thisStr, comment);
} else if ("f".equals(localName)) {
fIsOpen = false;
} else if ("is".equals(localName)) {
isIsOpen = false;
} else if ("row".equals(localName)) {
// Handle any "missing" cells which had comments attached
checkForEmptyCellComments(EmptyCellCommentsCheckType.END_OF_ROW);
// Finish up the row
output.endRow(rowNum);
// some sheets do not have rowNum set in the XML, Excel can read them so we should try to read them as well
nextRowNum = rowNum + 1;
} else if ("sheetData".equals(localName)) {
// Handle any "missing" cells which had comments attached
checkForEmptyCellComments(EmptyCellCommentsCheckType.END_OF_SHEET_DATA);
// indicate that this sheet is now done
output.endSheet();
}
else if("oddHeader".equals(localName) || "evenHeader".equals(localName) ||
"firstHeader".equals(localName)) {
hfIsOpen = false;
output.headerFooter(headerFooter.toString(), true, localName);
}
else if("oddFooter".equals(localName) || "evenFooter".equals(localName) ||
"firstFooter".equals(localName)) {
hfIsOpen = false;
output.headerFooter(headerFooter.toString(), false, localName);
}
}
/**
* Captures characters only if a suitable element is open.
* Originally was just "v"; extended for inlineStr also.
*/
@Override
public void characters(char[] ch, int start, int length)
throws SAXException {
if (vIsOpen) {
value.append(ch, start, length);
}
if (fIsOpen) {
formula.append(ch, start, length);
}
if (hfIsOpen) {
headerFooter.append(ch, start, length);
}
} }
/** /**

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.