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;
import javax.xml.xpath.XPath;
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.ooxml.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;
import org.apache.poi.xssf.usermodel.XSSFMap;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFTable;
import org.apache.poi.xssf.usermodel.XSSFTableColumn;
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.InputSource;
import org.xml.sax.SAXException;
public class {
private final XSSFMap ;
private static final POILogger = POILogFactory.getLogger(XSSFImportFromXML.class);
public (XSSFMap map) {
_map = map;
}
public void (String xmlInputString) throws SAXException, XPathExpressionException, IOException {
DocumentBuilder builder = DocumentHelper.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(xmlInputString.trim())));
List<XSSFSingleXmlCell> singleXmlCells = _map.getRelatedSingleXMLCell();
List<XSSFTable> tables = _map.getRelatedTables();
XPathFactory xpathFactory = XPathFactory.newInstance();
XPath xpath = xpathFactory.newXPath();
xpath.setNamespaceContext(new DefaultNamespaceContext(doc));
for (XSSFSingleXmlCell singleXmlCell : singleXmlCells) {
STXmlDataType.Enum xmlDataType = singleXmlCell.getXmlDataType();
String xpathString = singleXmlCell.getXpath();
Node result = (Node) xpath.evaluate(xpathString, doc, XPathConstants.NODE);
if (result != null) {
String textContent = result.getTextContent();
logger.log(POILogger.DEBUG, "Extracting with xpath " + xpathString + " : value is '" + textContent + "'");
XSSFCell cell = singleXmlCell.getReferencedCell();
logger.log(POILogger.DEBUG, "Setting '" + textContent + "' to cell " + cell.getColumnIndex() + "-" + cell.getRowIndex() + " in sheet "
+ cell.getSheet().getSheetName());
setCellValue(textContent, cell, xmlDataType);
}
}
for (XSSFTable table : tables) {
String commonXPath = table.getCommonXpath();
NodeList result = (NodeList) xpath.evaluate(commonXPath, doc, XPathConstants.NODESET);
int rowOffset = table.getStartCellReference().getRow() + table.getHeaderRowCount();
int columnOffset = table.getStartCellReference().getCol();
table.setDataRowCount(result.getLength());
for (int i = 0; i < result.getLength(); i++) {
Node singleNode = result.item(i).cloneNode(true);
for (XSSFTableColumn tableColumn : table.getColumns()) {
XSSFXmlColumnPr xmlColumnPr = tableColumn.getXmlColumnPr();
if(xmlColumnPr == null) {
continue;
}
int rowId = rowOffset + i;
int columnId = columnOffset + tableColumn.getColumnIndex();
String localXPath = xmlColumnPr.getLocalXPath();
localXPath = localXPath.substring(localXPath.indexOf('/', 1) + 1);
String value = (String) xpath.evaluate(localXPath, singleNode, XPathConstants.STRING);
logger.log(POILogger.DEBUG, "Extracting with xpath " + localXPath + " : value is '" + value + "'");
XSSFRow row = table.getXSSFSheet().getRow(rowId);
if (row == null) {
row = table.getXSSFSheet().createRow(rowId);
}
XSSFCell cell = row.getCell(columnId);
if (cell == null) {
cell = row.createCell(columnId);
}
logger.log(POILogger.DEBUG, "Setting '" + value + "' to cell " + cell.getColumnIndex() + "-" + cell.getRowIndex() + " in sheet "
+ table.getXSSFSheet().getSheetName());
setCellValue(value, cell, xmlColumnPr.getXmlDataType());
}
}
}
}
private static enum {
BOOLEAN(STXmlDataType.BOOLEAN),
DOUBLE(STXmlDataType.DOUBLE),
INTEGER(STXmlDataType.INT, STXmlDataType.UNSIGNED_INT, STXmlDataType.INTEGER),
STRING(STXmlDataType.STRING),
DATE(STXmlDataType.DATE);
private Set<STXmlDataType.Enum> ;
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 | 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 implements NamespaceContext {
private final Element ;
public (Document doc) {
_docElem = doc.getDocumentElement();
}
@Override
public String (String prefix) {
return getNamespaceForPrefix(prefix);
}
private String (String prefix) {
if (prefix.equals("xml")) {
return "http://www.w3.org/XML/1998/namespace";
}
Node parent = _docElem;
while (parent != null) {
int type = parent.getNodeType();
if (type == Node.ELEMENT_NODE) {
if (parent.getNodeName().startsWith(prefix + ":")) {
return parent.getNamespaceURI();
}
NamedNodeMap nnm = parent.getAttributes();
for (int i = 0; i < nnm.getLength(); i++) {
Node attr = nnm.item(i);
String aname = attr.getNodeName();
boolean isPrefix = aname.startsWith("xmlns:");
if (isPrefix || aname.equals("xmlns")) {
int index = aname.indexOf(':');
String p = isPrefix ? aname.substring(index + 1) : "";
if (p.equals(prefix)) {
return attr.getNodeValue();
}
}
}
} else if (type == Node.ENTITY_REFERENCE_NODE) {
continue;
} else {
break;
}
parent = parent.getParentNode();
}
return null;
}
@Override
public Iterator<String> (String val) {
return null;
}
@Override
public String (String uri) {
return null;
}
}
}