aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDominik Stadler <centic@apache.org>2014-03-15 17:29:17 +0000
committerDominik Stadler <centic@apache.org>2014-03-15 17:29:17 +0000
commitcc51d8eeb62ca138b72d37785cade16d7267a859 (patch)
treeb460778a2409e959280e44dd6ae3c461eef9d16d /src
parent847e64cf35eae288d1de1e9551c2b8e6d383336b (diff)
downloadpoi-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')
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java11
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java.orig536
-rw-r--r--src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java34
-rw-r--r--src/ooxml/testcases/org/apache/poi/xssf/extractor/TestXSSFExportToXML.java.orig548
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 &lt;any&gt; in complex type/element declaration </li>
+ * <li> no &lt;anyAttribute&gt; 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 &lt;substitutionGroup&gt; 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);
+ }
+}