diff --git a/src/integrationtest/org/apache/poi/TestAllFiles.java b/src/integrationtest/org/apache/poi/TestAllFiles.java index b7427d4d59..d453da27f9 100644 --- a/src/integrationtest/org/apache/poi/TestAllFiles.java +++ b/src/integrationtest/org/apache/poi/TestAllFiles.java @@ -203,6 +203,7 @@ public class TestAllFiles { // TODO: fails XMLExportTest, is this ok? EXPECTED_FAILURES.add("spreadsheet/CustomXMLMapping-singleattributenamespace.xlsx"); EXPECTED_FAILURES.add("spreadsheet/55864.xlsx"); + EXPECTED_FAILURES.add("spreadsheet/57890.xlsx"); // TODO: these fail now with some NPE/file read error because we now try to compute every value via Cell.toString()! EXPECTED_FAILURES.add("spreadsheet/44958.xls"); diff --git a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java index 1cde38b30a..bc6ce74472 100644 --- a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java +++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFImportFromXML.java @@ -19,8 +19,15 @@ package org.apache.poi.xssf.extractor; import java.io.IOException; import java.io.StringReader; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.Set; import javax.xml.namespace.NamespaceContext; import javax.xml.parsers.DocumentBuilder; @@ -30,7 +37,10 @@ import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.util.CellReference; import org.apache.poi.util.DocumentHelper; +import org.apache.poi.util.LocaleUtil; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; import org.apache.poi.xssf.usermodel.XSSFCell; @@ -39,6 +49,7 @@ import org.apache.poi.xssf.usermodel.XSSFRow; import org.apache.poi.xssf.usermodel.XSSFTable; import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell; import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr; +import org.openxmlformats.schemas.spreadsheetml.x2006.main.STXmlDataType; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; @@ -95,6 +106,7 @@ public class XSSFImportFromXML { for (XSSFSingleXmlCell singleXmlCell : singleXmlCells) { + STXmlDataType.Enum xmlDataType = singleXmlCell.getXmlDataType(); String xpathString = singleXmlCell.getXpath(); Node result = (Node) xpath.evaluate(xpathString, doc, XPathConstants.NODE); // result can be null if value is optional (xsd:minOccurs=0), see bugzilla 55864 @@ -104,7 +116,7 @@ public class XSSFImportFromXML { XSSFCell cell = singleXmlCell.getReferencedCell(); logger.log(POILogger.DEBUG, "Setting '" + textContent + "' to cell " + cell.getColumnIndex() + "-" + cell.getRowIndex() + " in sheet " + cell.getSheet().getSheetName()); - cell.setCellValue(textContent); + setCellValue(textContent, cell, xmlDataType); } } @@ -146,12 +158,74 @@ public class XSSFImportFromXML { } logger.log(POILogger.DEBUG, "Setting '" + value + "' to cell " + cell.getColumnIndex() + "-" + cell.getRowIndex() + " in sheet " + table.getXSSFSheet().getSheetName()); - cell.setCellValue(value.trim()); + setCellValue(value, cell, xmlColumnPr.getXmlDataType()); } } } } + private static enum DataType { + BOOLEAN(STXmlDataType.BOOLEAN), // + DOUBLE(STXmlDataType.DOUBLE), // + INTEGER(STXmlDataType.INT, STXmlDataType.UNSIGNED_INT, STXmlDataType.INTEGER), // + STRING(STXmlDataType.STRING), // + DATE(STXmlDataType.DATE); + + private Set xmlDataTypes; + + private DataType(STXmlDataType.Enum... xmlDataTypes) { + this.xmlDataTypes = new HashSet(Arrays.asList(xmlDataTypes)); + } + + public static DataType getDataType(STXmlDataType.Enum xmlDataType) { + for (DataType dataType : DataType.values()) { + if (dataType.xmlDataTypes.contains(xmlDataType)) { + return dataType; + } + } + return null; + } + } + + private void setCellValue(String value, XSSFCell cell, STXmlDataType.Enum xmlDataType) { + DataType type = DataType.getDataType(xmlDataType); + try { + if (value.isEmpty() || type == null) { + cell.setCellValue((String) null); + } else { + switch (type) { + case BOOLEAN: + cell.setCellValue(Boolean.parseBoolean(value)); + break; + case DOUBLE: + cell.setCellValue(Double.parseDouble(value)); + break; + case INTEGER: + cell.setCellValue(Integer.parseInt(value)); + break; + case DATE: + DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", LocaleUtil.getUserLocale()); + Date date = sdf.parse(value); + cell.setCellValue(date); + if (!DateUtil.isValidExcelDate(cell.getNumericCellValue())) { + cell.setCellValue(value); + } + break; + case STRING: + default: + cell.setCellValue(value.trim()); + break; + } + } + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException(String.format(LocaleUtil.getUserLocale(), "Unable to format value '%s' as %s for cell %s", value, + type, new CellReference(cell).formatAsString())); + } catch (ParseException e) { + throw new IllegalArgumentException(String.format(LocaleUtil.getUserLocale(), "Unable to format value '%s' as %s for cell %s", value, + type, new CellReference(cell).formatAsString())); + } + } + private static final class DefaultNamespaceContext implements NamespaceContext { /** * Node from which to start searching for a xmlns attribute that binds a @@ -219,7 +293,7 @@ public class XSSFImportFromXML { // Dummy implementation - not used! @Override - public Iterator getPrefixes(String val) { + public Iterator getPrefixes(String val) { return null; } diff --git a/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFImportFromXML.java b/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFImportFromXML.java index 16f1ab4714..12a0bbf566 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFImportFromXML.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFImportFromXML.java @@ -17,6 +17,8 @@ package org.apache.poi.xssf.extractor; +import java.text.SimpleDateFormat; +import java.util.Date; import junit.framework.TestCase; @@ -129,10 +131,10 @@ public class TestXSSFImportFromXML extends TestCase { public void testSingleAttributeCellWithNamespace() throws Exception{ XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMapping-singleattributenamespace.xlsx"); try { - String id = "a"; + int id = 1; String displayName = "dispName"; String ref="19"; - String count = "21"; + int count = 21; String testXML = ""+ ""+ @@ -146,16 +148,15 @@ public class TestXSSFImportFromXML extends TestCase { //Check for Schema element XSSFSheet sheet=wb.getSheetAt(0); - assertEquals(id,sheet.getRow(28).getCell(1).getStringCellValue()); - assertEquals(displayName,sheet.getRow(11).getCell(5).getStringCellValue()); - assertEquals(ref,sheet.getRow(14).getCell(7).getStringCellValue()); - assertEquals(count,sheet.getRow(18).getCell(3).getStringCellValue()); + assertEquals(new Double(id), sheet.getRow(28).getCell(1).getNumericCellValue()); + assertEquals(displayName, sheet.getRow(11).getCell(5).getStringCellValue()); + assertEquals(ref, sheet.getRow(14).getCell(7).getStringCellValue()); + assertEquals(new Double(count), sheet.getRow(18).getCell(3).getNumericCellValue()); } finally { wb.close(); } } - - + public void testOptionalFields_Bugzilla_55864() throws Exception { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55864.xlsx"); try { @@ -195,4 +196,36 @@ public class TestXSSFImportFromXML extends TestCase { wb.close(); } } + + public void testOptionalFields_Bugzilla_57890() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("57890.xlsx"); + + String testXML = "" + "" + + "" + "" + Integer.MIN_VALUE + "" + "12345" + + "1.0000123" + "1991-03-14" + "" + ""; + + XSSFMap map = wb.getMapInfo().getXSSFMapByName("TestInfoRoot_Map"); + assertNotNull(map); + XSSFImportFromXML importer = new XSSFImportFromXML(map); + + importer.importFromXML(testXML); + + XSSFSheet sheet = wb.getSheetAt(0); + + XSSFRow rowHeadings = sheet.getRow(0); + XSSFRow rowData = sheet.getRow(1); + + assertEquals("Date", rowHeadings.getCell(0).getStringCellValue()); + Date date = new SimpleDateFormat("yyyy-MM-dd").parse("1991-3-14"); + assertEquals(date, rowData.getCell(0).getDateCellValue()); + + assertEquals("Amount Int", rowHeadings.getCell(1).getStringCellValue()); + assertEquals(new Double(Integer.MIN_VALUE), rowData.getCell(1).getNumericCellValue()); + + assertEquals("Amount Double", rowHeadings.getCell(2).getStringCellValue()); + assertEquals(1.0000123, rowData.getCell(2).getNumericCellValue()); + + assertEquals("Amount UnsignedInt", rowHeadings.getCell(3).getStringCellValue()); + assertEquals(new Double(12345), rowData.getCell(3).getNumericCellValue()); + } } diff --git a/test-data/spreadsheet/57890.xlsx b/test-data/spreadsheet/57890.xlsx new file mode 100644 index 0000000000..91c751baa8 Binary files /dev/null and b/test-data/spreadsheet/57890.xlsx differ