diff options
author | Dominik Stadler <centic@apache.org> | 2014-03-15 17:29:17 +0000 |
---|---|---|
committer | Dominik Stadler <centic@apache.org> | 2014-03-15 17:29:17 +0000 |
commit | cc51d8eeb62ca138b72d37785cade16d7267a859 (patch) | |
tree | b460778a2409e959280e44dd6ae3c461eef9d16d /src | |
parent | 847e64cf35eae288d1de1e9551c2b8e6d383336b (diff) | |
download | poi-cc51d8eeb62ca138b72d37785cade16d7267a859.tar.gz poi-cc51d8eeb62ca138b72d37785cade16d7267a859.zip |
Bug 56169: Fix NPE during export to XML with xs:all
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1577907 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src')
4 files changed, 1123 insertions, 6 deletions
diff --git a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java index e0ee1ef882..910741f511 100644 --- a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java +++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java @@ -261,7 +261,6 @@ public class XSSFExportToXml implements Comparator<String>{ * @return true, if document is valid */ private boolean isValid(Document xml) throws SAXException{ - boolean isValid = false; try{ String language = "http://www.w3.org/2001/XMLSchema"; SchemaFactory factory = SchemaFactory.newInstance(language); @@ -270,14 +269,14 @@ public class XSSFExportToXml implements Comparator<String>{ Schema schema = factory.newSchema(source); Validator validator = schema.newValidator(); validator.validate(new DOMSource(xml)); + //if no exceptions where raised, the document is valid - isValid=true; - - + return true; } catch(IOException e) { e.printStackTrace(); } - return isValid; + + return false; } @@ -517,7 +516,7 @@ public class XSSFExportToXml implements Comparator<String>{ Node sequence = complexTypeChildList.item(j); if ( sequence instanceof Element) { - if (sequence.getLocalName().equals("sequence")) { + if (sequence.getLocalName().equals("sequence") || sequence.getLocalName().equals("all")) { complexTypeNode = sequence; break; } diff --git a/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java.orig b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java.orig new file mode 100644 index 0000000000..e0ee1ef882 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java.orig @@ -0,0 +1,536 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.xssf.extractor; + +import java.io.IOException; +import java.io.OutputStream; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.validation.Schema; +import javax.xml.validation.SchemaFactory; +import javax.xml.validation.Validator; + +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFMap; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +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; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +/** + * + * Maps an XLSX to an XML according to one of the mapping defined. + * + * + * The output XML Schema must respect this limitations: + * + * <ul> + * <li> all mandatory elements and attributes must be mapped (enable validation to check this)</li> + * + * <li> no <any> in complex type/element declaration </li> + * <li> no <anyAttribute> attributes declaration </li> + * <li> no recursive structures: recursive structures can't be nested more than one level </li> + * <li> no abstract elements: abstract complex types can be declared but must not be used in elements. </li> + * <li> no mixed content: an element can't contain simple text and child element(s) together </li> + * <li> no <substitutionGroup> in complex type/element declaration </li> + * </ul> + */ +public class XSSFExportToXml implements Comparator<String>{ + + private XSSFMap map; + + /** + * Creates a new exporter and sets the mapping to be used when generating the XML output document + * + * @param map the mapping rule to be used + */ + public XSSFExportToXml(XSSFMap map) { + this.map = map; + } + + /** + * + * Exports the data in an XML stream + * + * @param os OutputStream in which will contain the output XML + * @param validate if true, validates the XML againts the XML Schema + * @throws SAXException + * @throws TransformerException + * @throws ParserConfigurationException + */ + public void exportToXML(OutputStream os, boolean validate) throws SAXException, ParserConfigurationException, TransformerException { + exportToXML(os, "UTF-8", validate); + } + + private Document getEmptyDocument() throws ParserConfigurationException{ + + DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); + DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); + Document doc = docBuilder.newDocument(); + + return doc; + } + + /** + * Exports the data in an XML stream + * + * @param os OutputStream in which will contain the output XML + * @param encoding the output charset encoding + * @param validate if true, validates the XML againts the XML Schema + * @throws SAXException + * @throws ParserConfigurationException + * @throws TransformerException + * @throws InvalidFormatException + */ + public void exportToXML(OutputStream os, String encoding, boolean validate) throws SAXException, ParserConfigurationException, TransformerException{ + List<XSSFSingleXmlCell> singleXMLCells = map.getRelatedSingleXMLCell(); + List<XSSFTable> tables = map.getRelatedTables(); + + String rootElement = map.getCtMap().getRootElement(); + + Document doc = getEmptyDocument(); + + Element root = null; + + if (isNamespaceDeclared()) { + root=doc.createElementNS(getNamespace(),rootElement); + } else { + root = doc.createElementNS("", rootElement); + } + doc.appendChild(root); + + + List<String> xpaths = new Vector<String>(); + Map<String,XSSFSingleXmlCell> singleXmlCellsMappings = new HashMap<String,XSSFSingleXmlCell>(); + Map<String,XSSFTable> tableMappings = new HashMap<String,XSSFTable>(); + + for(XSSFSingleXmlCell simpleXmlCell : singleXMLCells) { + xpaths.add(simpleXmlCell.getXpath()); + singleXmlCellsMappings.put(simpleXmlCell.getXpath(), simpleXmlCell); + } + for(XSSFTable table : tables) { + String commonXPath = table.getCommonXpath(); + xpaths.add(commonXPath); + tableMappings.put(commonXPath, table); + } + + + Collections.sort(xpaths,this); + + for(String xpath : xpaths) { + + XSSFSingleXmlCell simpleXmlCell = singleXmlCellsMappings.get(xpath); + XSSFTable table = tableMappings.get(xpath); + + if (!xpath.matches(".*\\[.*")) { + + // Exports elements and attributes mapped with simpleXmlCell + if (simpleXmlCell!=null) { + XSSFCell cell = simpleXmlCell.getReferencedCell(); + if (cell!=null) { + Node currentNode = getNodeByXPath(xpath,doc.getFirstChild(),doc,false); + STXmlDataType.Enum dataType = simpleXmlCell.getXmlDataType(); + mapCellOnNode(cell,currentNode,dataType); + + //remove nodes which are empty in order to keep the output xml valid + if("".equals(currentNode.getTextContent()) && currentNode.getParentNode() != null) { + currentNode.getParentNode().removeChild(currentNode); + } + } + } + + // Exports elements and attributes mapped with tables + if (table!=null) { + + List<XSSFXmlColumnPr> tableColumns = table.getXmlColumnPrs(); + + XSSFSheet sheet = table.getXSSFSheet(); + + int startRow = table.getStartCellReference().getRow(); + // In mappings created with Microsoft Excel the first row contains the table header and must be skipped + startRow +=1; + + int endRow = table.getEndCellReference().getRow(); + + for(int i = startRow; i<= endRow; i++) { + XSSFRow row = sheet.getRow(i); + + Node tableRootNode = getNodeByXPath(table.getCommonXpath(),doc.getFirstChild(),doc,true); + + short startColumnIndex = table.getStartCellReference().getCol(); + for(int j = startColumnIndex; j<= table.getEndCellReference().getCol();j++) { + XSSFCell cell = row.getCell(j); + if (cell!=null) { + XSSFXmlColumnPr pointer = tableColumns.get(j-startColumnIndex); + String localXPath = pointer.getLocalXPath(); + Node currentNode = getNodeByXPath(localXPath,tableRootNode,doc,false); + STXmlDataType.Enum dataType = pointer.getXmlDataType(); + + + mapCellOnNode(cell,currentNode,dataType); + } + + } + + } + + + + } + } else { + // TODO: implement filtering management in xpath + } + } + + boolean isValid = true; + if (validate) { + isValid =isValid(doc); + } + + + + if (isValid) { + + ///////////////// + //Output the XML + + //set up a transformer + TransformerFactory transfac = TransformerFactory.newInstance(); + Transformer trans = transfac.newTransformer(); + trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); + trans.setOutputProperty(OutputKeys.INDENT, "yes"); + trans.setOutputProperty(OutputKeys.ENCODING, encoding); + + //create string from xml tree + + StreamResult result = new StreamResult(os); + DOMSource source = new DOMSource(doc); + trans.transform(source, result); + + } + } + + + /** + * Validate the generated XML against the XML Schema associated with the XSSFMap + * + * @param xml the XML to validate + * @return true, if document is valid + */ + private boolean isValid(Document xml) throws SAXException{ + boolean isValid = false; + try{ + String language = "http://www.w3.org/2001/XMLSchema"; + SchemaFactory factory = SchemaFactory.newInstance(language); + + Source source = new DOMSource(map.getSchema()); + Schema schema = factory.newSchema(source); + Validator validator = schema.newValidator(); + validator.validate(new DOMSource(xml)); + //if no exceptions where raised, the document is valid + isValid=true; + + + } catch(IOException e) { + e.printStackTrace(); + } + return isValid; + } + + + private void mapCellOnNode(XSSFCell cell, Node node, STXmlDataType.Enum outputDataType) { + + String value =""; + switch (cell.getCellType()) { + + case XSSFCell.CELL_TYPE_STRING: value = cell.getStringCellValue(); break; + case XSSFCell.CELL_TYPE_BOOLEAN: value += cell.getBooleanCellValue(); break; + case XSSFCell.CELL_TYPE_ERROR: value = cell.getErrorCellString(); break; + case XSSFCell.CELL_TYPE_FORMULA: + if (cell.getCachedFormulaResultType() == Cell.CELL_TYPE_STRING) { + value = cell.getStringCellValue(); + } else { + value += cell.getNumericCellValue(); + } + break; + + case XSSFCell.CELL_TYPE_NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); + value += sdf.format(cell.getDateCellValue()); + } else { + value += cell.getRawValue(); + } + break; + + default: ; + + } + if (node instanceof Element) { + Element currentElement = (Element) node; + currentElement.setTextContent(value); + } else { + node.setNodeValue(value); + } + } + + private String removeNamespace(String elementName) { + return elementName.matches(".*:.*")?elementName.split(":")[1]:elementName; + } + + + + private Node getNodeByXPath(String xpath,Node rootNode,Document doc,boolean createMultipleInstances) { + String[] xpathTokens = xpath.split("/"); + + + Node currentNode =rootNode; + // The first token is empty, the second is the root node + for(int i =2; i<xpathTokens.length;i++) { + + String axisName = removeNamespace(xpathTokens[i]); + + + if (!axisName.startsWith("@")) { + + NodeList list =currentNode.getChildNodes(); + + Node selectedNode = null; + if (!(createMultipleInstances && i==xpathTokens.length-1) ) { + // select the last child node only if we need to map to a single cell + selectedNode = selectNode(axisName, list); + } + if (selectedNode==null) { + selectedNode = createElement(doc, currentNode, axisName); + } + currentNode = selectedNode; + } else { + + + Node attribute = createAttribute(doc, currentNode, axisName); + + currentNode = attribute; + } + } + return currentNode; + } + + private Node createAttribute(Document doc, Node currentNode, String axisName) { + String attributeName = axisName.substring(1); + NamedNodeMap attributesMap = currentNode.getAttributes(); + Node attribute = attributesMap.getNamedItem(attributeName); + if (attribute==null) { + attribute = doc.createAttributeNS("", attributeName); + attributesMap.setNamedItem(attribute); + } + return attribute; + } + + private Node createElement(Document doc, Node currentNode, String axisName) { + Node selectedNode; + if (isNamespaceDeclared()) { + selectedNode =doc.createElementNS(getNamespace(),axisName); + } else { + selectedNode = doc.createElementNS("", axisName); + } + currentNode.appendChild(selectedNode); + return selectedNode; + } + + private Node selectNode(String axisName, NodeList list) { + Node selectedNode = null; + for(int j=0;j<list.getLength();j++) { + Node node = list.item(j); + if (node.getNodeName().equals(axisName)) { + selectedNode=node; + break; + } + } + return selectedNode; + } + + + private boolean isNamespaceDeclared() { + String schemaNamespace = getNamespace(); + return schemaNamespace!=null && !schemaNamespace.equals(""); + } + + private String getNamespace() { + return map.getCTSchema().getNamespace(); + } + + + /** + * Compares two xpaths to define an ordering according to the XML Schema + * + */ + @Override + public int compare(String leftXpath, String rightXpath) { + Node xmlSchema = map.getSchema(); + + String[] leftTokens = leftXpath.split("/"); + String[] rightTokens = rightXpath.split("/"); + + int minLenght = leftTokens.length< rightTokens.length? leftTokens.length : rightTokens.length; + + Node localComplexTypeRootNode = xmlSchema; + + for(int i =1;i <minLenght; i++) { + + String leftElementName =leftTokens[i]; + String rightElementName = rightTokens[i]; + + if (leftElementName.equals(rightElementName)) { + Node complexType = getComplexTypeForElement(leftElementName, xmlSchema,localComplexTypeRootNode); + localComplexTypeRootNode = complexType; + } else { + int leftIndex = indexOfElementInComplexType(leftElementName,localComplexTypeRootNode); + int rightIndex = indexOfElementInComplexType(rightElementName,localComplexTypeRootNode); + if (leftIndex!=-1 && rightIndex!=-1) { + if ( leftIndex < rightIndex) { + return -1; + }if ( leftIndex > rightIndex) { + return 1; + } + } else { + // NOTE: the xpath doesn't match correctly in the schema + } + } + } + + return 0; + } + + private int indexOfElementInComplexType(String elementName,Node complexType) { + + NodeList list = complexType.getChildNodes(); + int indexOf = -1; + + for(int i=0; i< list.getLength();i++) { + Node node = list.item(i); + if (node instanceof Element) { + if (node.getLocalName().equals("element")) { + Node nameAttribute = node.getAttributes().getNamedItem("name"); + if (nameAttribute.getNodeValue().equals(removeNamespace(elementName))) { + indexOf = i; + break; + } + + } + } + } + return indexOf; + } + + private Node getComplexTypeForElement(String elementName,Node xmlSchema,Node localComplexTypeRootNode) { + String elementNameWithoutNamespace = removeNamespace(elementName); + + String complexTypeName = getComplexTypeNameFromChildren(localComplexTypeRootNode, elementNameWithoutNamespace); + + // Note: we expect that all the complex types are defined at root level + Node complexTypeNode = null; + if (!"".equals(complexTypeName)) { + complexTypeNode = getComplexTypeNodeFromSchemaChildren(xmlSchema, complexTypeNode, complexTypeName); + } + + return complexTypeNode; + } + + private String getComplexTypeNameFromChildren(Node localComplexTypeRootNode, + String elementNameWithoutNamespace) { + NodeList list = localComplexTypeRootNode.getChildNodes(); + String complexTypeName = ""; + + for(int i=0; i< list.getLength();i++) { + Node node = list.item(i); + if ( node instanceof Element) { + if (node.getLocalName().equals("element")) { + Node nameAttribute = node.getAttributes().getNamedItem("name"); + if (nameAttribute.getNodeValue().equals(elementNameWithoutNamespace)) { + Node complexTypeAttribute = node.getAttributes().getNamedItem("type"); + if (complexTypeAttribute!=null) { + complexTypeName = complexTypeAttribute.getNodeValue(); + break; + } + } + } + } + } + return complexTypeName; + } + + private Node getComplexTypeNodeFromSchemaChildren(Node xmlSchema, Node complexTypeNode, + String complexTypeName) { + NodeList complexTypeList = xmlSchema.getChildNodes(); + for(int i=0; i< complexTypeList.getLength();i++) { + Node node = complexTypeList.item(i); + if ( node instanceof Element) { + if (node.getLocalName().equals("complexType")) { + Node nameAttribute = node.getAttributes().getNamedItem("name"); + if (nameAttribute.getNodeValue().equals(complexTypeName)) { + + NodeList complexTypeChildList =node.getChildNodes(); + for(int j=0; j<complexTypeChildList.getLength();j++) { + Node sequence = complexTypeChildList.item(j); + + if ( sequence instanceof Element) { + if (sequence.getLocalName().equals("sequence")) { + complexTypeNode = sequence; + break; + } + } + } + if (complexTypeNode!=null) { + break; + } + + } + } + } + } + return complexTypeNode; + } +}
\ No newline at end of file diff --git a/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java b/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java index 4e112d268f..7726fc37fb 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java @@ -361,6 +361,40 @@ public final class TestXSSFExportToXML extends TestCase { assertTrue(found); } + public void testXmlExportSchemaWithXSAllTag_Bugzilla_56169() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("56169.xlsx"); + + for (XSSFMap map : wb.getCustomXMLMappings()) { + XSSFExportToXml exporter = new XSSFExportToXml(map); + + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xmlData = os.toString("UTF-8"); + + assertNotNull(xmlData); + assertTrue(!xmlData.equals("")); + + String a = xmlData.split("<A>")[1].split("</A>")[0].trim(); + String a_b = a.split("<B>")[1].split("</B>")[0].trim(); + String a_b_c = a_b.split("<C>")[1].split("</C>")[0].trim(); + String a_b_c_e = a_b_c.split("<E>")[1].split("</EA>")[0].trim(); + String a_b_c_e_euro = a_b_c_e.split("<EUR>")[1].split("</EUR>")[0].trim(); + String a_b_c_e_chf = a_b_c_e.split("<CHF>")[1].split("</CHF>")[0].trim(); + + assertEquals("1", a_b_c_e_euro); + assertEquals("2", a_b_c_e_chf); + + String a_b_d = a_b.split("<D>")[1].split("</Dd>")[0].trim(); + String a_b_d_e = a_b_d.split("<E>")[1].split("</EA>")[0].trim(); + + String a_b_d_e_euro = a_b_d_e.split("<EUR>")[1].split("</EUR>")[0].trim(); + String a_b_d_e_chf = a_b_d_e.split("<CHF>")[1].split("</CHF>")[0].trim(); + + assertEquals("3", a_b_d_e_euro); + assertEquals("4", a_b_d_e_chf); + } + } + public void testXmlExportCompare_Bug_55923() throws Exception { XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55923.xlsx"); diff --git a/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java.orig b/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java.orig new file mode 100644 index 0000000000..4e112d268f --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java.orig @@ -0,0 +1,548 @@ +/* ==================================================================== + Licensed to the Apache Software Foundation (ASF) under one or more + contributor license agreements. See the NOTICE file distributed with + this work for additional information regarding copyright ownership. + The ASF licenses this file to You under the Apache License, Version 2.0 + (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +==================================================================== */ + +package org.apache.poi.xssf.extractor; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Date; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import junit.framework.TestCase; + +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.xssf.XSSFTestDataSamples; +import org.apache.poi.xssf.model.MapInfo; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFMap; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.Test; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * @author Roberto Manicardi + */ +public final class TestXSSFExportToXML extends TestCase { + public void testExportToXML() throws Exception { + + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMappings.xlsx"); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(1); + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xml = os.toString("UTF-8"); + + assertNotNull(xml); + assertFalse(xml.equals("")); + + String docente = xml.split("<DOCENTE>")[1].split("</DOCENTE>")[0].trim(); + String nome = xml.split("<NOME>")[1].split("</NOME>")[0].trim(); + String tutor = xml.split("<TUTOR>")[1].split("</TUTOR>")[0].trim(); + String cdl = xml.split("<CDL>")[1].split("</CDL>")[0].trim(); + String durata = xml.split("<DURATA>")[1].split("</DURATA>")[0].trim(); + String argomento = xml.split("<ARGOMENTO>")[1].split("</ARGOMENTO>")[0].trim(); + String progetto = xml.split("<PROGETTO>")[1].split("</PROGETTO>")[0].trim(); + String crediti = xml.split("<CREDITI>")[1].split("</CREDITI>")[0].trim(); + + assertEquals("ro", docente); + assertEquals("ro", nome); + assertEquals("ds", tutor); + assertEquals("gs", cdl); + assertEquals("g", durata); + assertEquals("gvvv", argomento); + assertEquals("aaaa", progetto); + assertEquals("aa", crediti); + + parseXML(xml); + + found = true; + } + assertTrue(found); + } + + public void testExportToXMLInverseOrder() throws Exception { + + XSSFWorkbook wb = XSSFTestDataSamples + .openSampleWorkbook("CustomXmlMappings-inverse-order.xlsx"); + + MapInfo mapInfo = null; + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(1); + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xml = os.toString("UTF-8"); + + assertNotNull(xml); + assertFalse(xml.equals("")); + + String docente = xml.split("<DOCENTE>")[1].split("</DOCENTE>")[0].trim(); + String nome = xml.split("<NOME>")[1].split("</NOME>")[0].trim(); + String tutor = xml.split("<TUTOR>")[1].split("</TUTOR>")[0].trim(); + String cdl = xml.split("<CDL>")[1].split("</CDL>")[0].trim(); + String durata = xml.split("<DURATA>")[1].split("</DURATA>")[0].trim(); + String argomento = xml.split("<ARGOMENTO>")[1].split("</ARGOMENTO>")[0].trim(); + String progetto = xml.split("<PROGETTO>")[1].split("</PROGETTO>")[0].trim(); + String crediti = xml.split("<CREDITI>")[1].split("</CREDITI>")[0].trim(); + + assertEquals("aa", nome); + assertEquals("aaaa", docente); + assertEquals("gvvv", tutor); + assertEquals("g", cdl); + assertEquals("gs", durata); + assertEquals("ds", argomento); + assertEquals("ro", progetto); + assertEquals("ro", crediti); + + parseXML(xml); + + found = true; + } + assertTrue(found); + } + + public void testXPathOrdering() { + + XSSFWorkbook wb = XSSFTestDataSamples + .openSampleWorkbook("CustomXmlMappings-inverse-order.xlsx"); + + MapInfo mapInfo = null; + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (p instanceof MapInfo) { + mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(1); + XSSFExportToXml exporter = new XSSFExportToXml(map); + + assertEquals(1, exporter.compare("/CORSO/DOCENTE", "/CORSO/NOME")); + assertEquals(-1, exporter.compare("/CORSO/NOME", "/CORSO/DOCENTE")); + } + + found = true; + } + assertTrue(found); + } + + public void testMultiTable() throws Exception { + + XSSFWorkbook wb = XSSFTestDataSamples + .openSampleWorkbook("CustomXMLMappings-complex-type.xlsx"); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (p instanceof MapInfo) { + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(2); + + assertNotNull(map); + + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xml = os.toString("UTF-8"); + + assertNotNull(xml); + + String[] regexConditions = { + "<MapInfo", "</MapInfo>", + "<Schema ID=\"1\" Namespace=\"\" SchemaRef=\"\"/>", + "<Schema ID=\"4\" Namespace=\"\" SchemaRef=\"\"/>", + "DataBinding", + "Map Append=\"false\" AutoFit=\"false\" ID=\"1\"", + "Map Append=\"false\" AutoFit=\"false\" ID=\"5\"", + }; + + for (String condition : regexConditions) { + Pattern pattern = Pattern.compile(condition); + Matcher matcher = pattern.matcher(xml); + assertTrue(matcher.find()); + } + } + + found = true; + } + assertTrue(found); + } + + public void test55850ComplexXmlExport() throws Exception { + + XSSFWorkbook wb = XSSFTestDataSamples + .openSampleWorkbook("55850.xlsx"); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(2); + + assertNotNull("XSSFMap is null", map); + + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xmlData = os.toString("UTF-8"); + + assertNotNull(xmlData); + assertFalse(xmlData.equals("")); + + String a = xmlData.split("<A>")[1].split("</A>")[0].trim(); + String b = a.split("<B>")[1].split("</B>")[0].trim(); + String c = b.split("<C>")[1].split("</C>")[0].trim(); + String d = c.split("<D>")[1].split("</Dd>")[0].trim(); + String e = d.split("<E>")[1].split("</EA>")[0].trim(); + + String euro = e.split("<EUR>")[1].split("</EUR>")[0].trim(); + String chf = e.split("<CHF>")[1].split("</CHF>")[0].trim(); + + assertEquals("15", euro); + assertEquals("19", chf); + + parseXML(xmlData); + + found = true; + } + assertTrue(found); + } + + public void testFormulaCells_Bugzilla_55927() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55927.xlsx"); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(1); + + assertNotNull("XSSFMap is null", map); + + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xmlData = os.toString("UTF-8"); + + assertNotNull(xmlData); + assertFalse(xmlData.equals("")); + + String date = xmlData.split("<DATE>")[1].split("</DATE>")[0].trim(); + assertEquals("2012-01-13", date); + + parseXML(xmlData); + + found = true; + } + assertTrue(found); + } + + public void testFormulaCells_Bugzilla_55926() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55926.xlsx"); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(1); + + assertNotNull("XSSFMap is null", map); + + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xmlData = os.toString("UTF-8"); + + assertNotNull(xmlData); + assertFalse(xmlData.equals("")); + + String a = xmlData.split("<A>")[1].split("</A>")[0].trim(); + String doubleValue = a.split("<DOUBLE>")[1].split("</DOUBLE>")[0].trim(); + String stringValue = a.split("<STRING>")[1].split("</STRING>")[0].trim(); + + assertEquals("Hello World", stringValue); + assertEquals("5.1", doubleValue); + + parseXML(xmlData); + + found = true; + } + assertTrue(found); + } + + @Test + public void testXmlExportIgnoresEmptyCells_Bugzilla_55924() throws Exception { + + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55924.xlsx"); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(1); + + assertNotNull("XSSFMap is null", map); + + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xmlData = os.toString("UTF-8"); + + assertNotNull(xmlData); + assertFalse(xmlData.equals("")); + + String a = xmlData.split("<A>")[1].split("</A>")[0].trim(); + String euro = a.split("<EUR>")[1].split("</EUR>")[0].trim(); + assertEquals("1",euro); + + parseXML(xmlData); + + found = true; + } + assertTrue(found); + } + + public void testXmlExportCompare_Bug_55923() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55923.xlsx"); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(4); + + assertNotNull("XSSFMap is null", map); + + XSSFExportToXml exporter = new XSSFExportToXml(map); + assertEquals(0, exporter.compare("", "")); + assertEquals(0, exporter.compare("/", "/")); + assertEquals(0, exporter.compare("//", "//")); + assertEquals(0, exporter.compare("/a/", "/b/")); + + assertEquals(-1, exporter.compare("/ns1:Entry/ns1:A/ns1:B/ns1:C/ns1:E/ns1:EUR", + "/ns1:Entry/ns1:A/ns1:B/ns1:C/ns1:E/ns1:CHF")); + + found = true; + } + assertTrue(found); + } + + public void testXmlExportSchemaOrderingBug_Bugzilla_55923() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55923.xlsx"); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(4); + + assertNotNull("XSSFMap is null", map); + + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xmlData = os.toString("UTF-8"); + + assertNotNull(xmlData); + assertFalse(xmlData.equals("")); + + String a = xmlData.split("<A>")[1].split("</A>")[0].trim(); + String a_b = a.split("<B>")[1].split("</B>")[0].trim(); + String a_b_c = a_b.split("<C>")[1].split("</C>")[0].trim(); + String a_b_c_e = a_b_c.split("<E>")[1].split("</EA>")[0].trim(); + String a_b_c_e_euro = a_b_c_e.split("<EUR>")[1].split("</EUR>")[0].trim(); + String a_b_c_e_chf = a_b_c_e.split("<CHF>")[1].split("</CHF>")[0].trim(); + + assertEquals("1",a_b_c_e_euro); + assertEquals("2",a_b_c_e_chf); + + String a_b_d = a_b.split("<D>")[1].split("</Dd>")[0].trim(); + String a_b_d_e = a_b_d.split("<E>")[1].split("</EA>")[0].trim(); + + String a_b_d_e_euro = a_b_d_e.split("<EUR>")[1].split("</EUR>")[0].trim(); + String a_b_d_e_chf = a_b_d_e.split("<CHF>")[1].split("</CHF>")[0].trim(); + + assertEquals("3",a_b_d_e_euro); + assertEquals("4",a_b_d_e_chf); + + found = true; + } + assertTrue(found); + } + + private void parseXML(String xmlData) throws IOException, SAXException, ParserConfigurationException { + DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance(); + docBuilderFactory.setNamespaceAware(true); + docBuilderFactory.setValidating(false); + DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder(); + docBuilder.setEntityResolver(new DummyEntityResolver()); + + docBuilder.parse(new ByteArrayInputStream(xmlData.getBytes("UTF-8"))); + } + + private static class DummyEntityResolver implements EntityResolver + { + @Override + public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException + { + return null; + } + } + + public void testExportDataTypes() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55923.xlsx"); + + Sheet sheet = wb.getSheetAt(0); + Row row = sheet.getRow(0); + + Cell cString = row.createCell(0); + cString.setCellValue("somestring"); + cString.setCellType(XSSFCell.CELL_TYPE_STRING); + + Cell cBoolean = row.createCell(1); + cBoolean.setCellValue(true); + cBoolean.setCellType(XSSFCell.CELL_TYPE_BOOLEAN); + + Cell cError = row.createCell(2); + cError.setCellType(XSSFCell.CELL_TYPE_ERROR); + + Cell cFormulaString = row.createCell(3); + cFormulaString.setCellFormula("A1"); + cFormulaString.setCellType(XSSFCell.CELL_TYPE_FORMULA); + + Cell cFormulaNumeric = row.createCell(4); + cFormulaNumeric.setCellFormula("F1"); + cFormulaNumeric.setCellType(XSSFCell.CELL_TYPE_FORMULA); + + Cell cNumeric = row.createCell(5); + cNumeric.setCellValue(1.2); + cNumeric.setCellType(XSSFCell.CELL_TYPE_NUMERIC); + + Cell cDate = row.createCell(6); + cDate.setCellValue(new Date()); + cDate.setCellType(XSSFCell.CELL_TYPE_NUMERIC); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(4); + + assertNotNull("XSSFMap is null", map); + + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, true); + String xmlData = os.toString("UTF-8"); + + assertNotNull(xmlData); + assertFalse(xmlData.equals("")); + + parseXML(xmlData); + + found = true; + } + assertTrue(found); + } + + public void testValidateFalse() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("55923.xlsx"); + + boolean found = false; + for (POIXMLDocumentPart p : wb.getRelations()) { + + if (!(p instanceof MapInfo)) { + continue; + } + MapInfo mapInfo = (MapInfo) p; + + XSSFMap map = mapInfo.getXSSFMapById(4); + + assertNotNull("XSSFMap is null", map); + + XSSFExportToXml exporter = new XSSFExportToXml(map); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + exporter.exportToXML(os, false); + String xmlData = os.toString("UTF-8"); + + assertNotNull(xmlData); + assertFalse(xmlData.equals("")); + + parseXML(xmlData); + + found = true; + } + assertTrue(found); + } +} |