Removed @author tag.

Dealt with exceprions properly.
General reformatting.

git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@827907 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Ugo Cei 2009-10-21 07:15:37 +00:00
parent 3e82ec8035
commit 47086ce5bd
1 changed files with 363 additions and 369 deletions

View File

@ -74,441 +74,435 @@ import org.xml.sax.SAXException;
* <li> no mixed content: an element can't contain simple text and child element(s) together </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> * <li> no &lt;substitutionGroup&gt; in complex type/element declaration </li>
* </ul> * </ul>
*
* @author Roberto Manicardi
*/ */
public class XSSFExportToXml implements Comparator<String>{ public class XSSFExportToXml implements Comparator<String>{
private XSSFMap map; private XSSFMap map;
/** /**
* Creates a new exporter and sets the mapping to be used when generating the XML output document * 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 * @param map the mapping rule to be used
*/ */
public XSSFExportToXml(XSSFMap map) { public XSSFExportToXml(XSSFMap map) {
this.map = 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
* Exports the data in an XML stream *
* * @param os OutputStream in which will contain the output XML
* @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 * @param validate if true, validates the XML againts the XML Schema
* @throws SAXException * @throws SAXException
*/ * @throws ParserConfigurationException
public void exportToXML(OutputStream os, boolean validate) throws SAXException{ * @throws TransformerException
exportToXML(os,"UTF-8", validate); * @throws InvalidFormatException
} */
public void exportToXML(OutputStream os, String encoding, boolean validate) throws SAXException, ParserConfigurationException, TransformerException{
List<XSSFSingleXmlCell> singleXMLCells = map.getRelatedSingleXMLCell();
List<Table> tables = map.getRelatedTables();
private Document getEmptyDocument() throws ParserConfigurationException{ String rootElement = map.getCtMap().getRootElement();
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document doc = docBuilder.newDocument();
return doc; Document doc = getEmptyDocument();
}
/** Element root = null;
* 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 InvalidFormatException
*/
public void exportToXML(OutputStream os, String encoding, boolean validate) throws SAXException{
List<XSSFSingleXmlCell> singleXMLCells = map.getRelatedSingleXMLCell();
List<Table> tables = map.getRelatedTables();
String rootElement = map.getCtMap().getRootElement(); if (isNamespaceDeclared()) {
root=doc.createElementNS(getNamespace(),rootElement);
} else {
root=doc.createElement(rootElement);
}
doc.appendChild(root);
try{
Document doc = getEmptyDocument(); List<String> xpaths = new Vector<String>();
Map<String,XSSFSingleXmlCell> singleXmlCellsMappings = new HashMap<String,XSSFSingleXmlCell>();
Map<String,Table> tableMappings = new HashMap<String,Table>();
Element root = null; for(XSSFSingleXmlCell simpleXmlCell : singleXMLCells) {
xpaths.add(simpleXmlCell.getXpath());
singleXmlCellsMappings.put(simpleXmlCell.getXpath(), simpleXmlCell);
}
for(Table table : tables) {
String commonXPath = table.getCommonXpath();
xpaths.add(commonXPath);
tableMappings.put(commonXPath, table);
}
if (isNamespaceDeclared()) {
root=doc.createElementNS(getNamespace(),rootElement);
} else {
root=doc.createElement(rootElement);
}
doc.appendChild(root);
Collections.sort(xpaths,this);
List<String> xpaths = new Vector<String>(); for(String xpath : xpaths) {
Map<String,XSSFSingleXmlCell> singleXmlCellsMappings = new HashMap<String,XSSFSingleXmlCell>();
Map<String,Table> tableMappings = new HashMap<String,Table>();
for(XSSFSingleXmlCell simpleXmlCell : singleXMLCells) { XSSFSingleXmlCell simpleXmlCell = singleXmlCellsMappings.get(xpath);
xpaths.add(simpleXmlCell.getXpath()); Table table = tableMappings.get(xpath);
singleXmlCellsMappings.put(simpleXmlCell.getXpath(), simpleXmlCell);
}
for(Table table : tables) {
String commonXPath = table.getCommonXpath();
xpaths.add(commonXPath);
tableMappings.put(commonXPath, table);
}
if (!xpath.matches(".*\\[.*")) {
Collections.sort(xpaths,this); // 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);
}
}
for(String xpath : xpaths) { // Exports elements and attributes mapped with tables
if (table!=null) {
XSSFSingleXmlCell simpleXmlCell = singleXmlCellsMappings.get(xpath); List<XSSFXmlColumnPr> tableColumns = table.getXmlColumnPrs();
Table table = tableMappings.get(xpath);
if (!xpath.matches(".*\\[.*")) { XSSFSheet sheet = table.getXSSFSheet();
// Exports elements and attributes mapped with simpleXmlCell int startRow = table.getStartCellReference().getRow();
if (simpleXmlCell!=null) { // In mappings created with Microsoft Excel the first row contains the table header and must be skipped
XSSFCell cell = simpleXmlCell.getReferencedCell(); startRow +=1;
if (cell!=null) {
Node currentNode = getNodeByXPath(xpath,doc.getFirstChild(),doc,false);
STXmlDataType.Enum dataType = simpleXmlCell.getXmlDataType();
mapCellOnNode(cell,currentNode,dataType);
}
}
// Exports elements and attributes mapped with tables int endRow = table.getEndCellReference().getRow();
if (table!=null) {
List<XSSFXmlColumnPr> tableColumns = table.getXmlColumnPrs(); for(int i = startRow; i<= endRow; i++) {
XSSFRow row = sheet.getRow(i);
XSSFSheet sheet = table.getXSSFSheet(); Node tableRootNode = getNodeByXPath(table.getCommonXpath(),doc.getFirstChild(),doc,true);
int startRow = table.getStartCellReference().getRow(); short startColumnIndex = table.getStartCellReference().getCol();
// In mappings created with Microsoft Excel the first row contains the table header and must be skipped for(int j = startColumnIndex; j<= table.getEndCellReference().getCol();j++) {
startRow +=1; 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();
int endRow = table.getEndCellReference().getRow();
for(int i = startRow; i<= endRow; i++) { mapCellOnNode(cell,currentNode,dataType);
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) {
} else {
// TODO: implement filtering management in xpath
}
}
boolean isValid = true; /////////////////
if (validate) { //Output the XML
isValid =isValid(doc);
}
//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
if (isValid) { StreamResult result = new StreamResult(os);
DOMSource source = new DOMSource(doc);
trans.transform(source, result);
///////////////// }
//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 /**
* Validate the generated XML against the XML Schema associated with the XSSFMap
*
* @param xml the XML to validate
* @return
*/
private boolean isValid(Document xml) throws SAXException{
boolean isValid = false;
try{
String language = XMLConstants.W3C_XML_SCHEMA_NS_URI;
SchemaFactory factory = SchemaFactory.newInstance(language);
StreamResult result = new StreamResult(os); Source source = new DOMSource(map.getSchema());
DOMSource source = new DOMSource(doc); Schema schema = factory.newSchema(source);
trans.transform(source, result); Validator validator = schema.newValidator();
validator.validate(new DOMSource(xml));
//if no exceptions where raised, the document is valid
isValid=true;
}
}catch(ParserConfigurationException e) {
e.printStackTrace();
}catch(TransformerException e) {
e.printStackTrace();
}
} catch(IOException e) {
e.printStackTrace();
}
return isValid;
}
}
/** private void mapCellOnNode(XSSFCell cell, Node node, STXmlDataType.Enum outputDataType) {
* Validate the generated XML against the XML Schema associated with the XSSFMap
*
* @param xml the XML to validate
* @return
*/
private boolean isValid(Document xml) throws SAXException{
boolean isValid = false;
try{
String language = XMLConstants.W3C_XML_SCHEMA_NS_URI;
SchemaFactory factory = SchemaFactory.newInstance(language);
Source source = new DOMSource(map.getSchema()); String value ="";
Schema schema = factory.newSchema(source); switch (cell.getCellType()) {
Validator validator = schema.newValidator();
validator.validate(new DOMSource(xml));
//if no exceptions where raised, the document is valid
isValid=true;
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: value = cell.getStringCellValue(); break;
case XSSFCell.CELL_TYPE_NUMERIC: value += cell.getRawValue(); break;
default: ;
} catch(IOException e) { }
e.printStackTrace(); if (node instanceof Element) {
} Element currentElement = (Element) node;
return isValid; currentElement.setTextContent(value);
} } else {
node.setNodeValue(value);
}
}
private String removeNamespace(String elementName) {
return elementName.matches(".*:.*")?elementName.split(":")[1]:elementName;
}
private void mapCellOnNode(XSSFCell cell, Node node, STXmlDataType.Enum outputDataType) {
String value ="";
switch (cell.getCellType()) {
case XSSFCell.CELL_TYPE_STRING: value = cell.getStringCellValue(); break; private Node getNodeByXPath(String xpath,Node rootNode,Document doc,boolean createMultipleInstances) {
case XSSFCell.CELL_TYPE_BOOLEAN: value += cell.getBooleanCellValue(); break; String[] xpathTokens = xpath.split("/");
case XSSFCell.CELL_TYPE_ERROR: value = cell.getErrorCellString(); break;
case XSSFCell.CELL_TYPE_FORMULA: value = cell.getStringCellValue(); break;
case XSSFCell.CELL_TYPE_NUMERIC: 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) { Node currentNode =rootNode;
return elementName.matches(".*:.*")?elementName.split(":")[1]:elementName; // The first token is empty, the second is the root node
} for(int i =2; i<xpathTokens.length;i++) {
String axisName = removeNamespace(xpathTokens[i]);
private Node getNodeByXPath(String xpath,Node rootNode,Document doc,boolean createMultipleInstances) { if (!axisName.startsWith("@")) {
String[] xpathTokens = xpath.split("/");
NodeList list =currentNode.getChildNodes();
Node currentNode =rootNode; Node selectedNode = null;
// The first token is empty, the second is the root node if (!(createMultipleInstances && i==xpathTokens.length-1) ) {
for(int i =2; i<xpathTokens.length;i++) { // 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 {
String axisName = removeNamespace(xpathTokens[i]);
Node attribute = createAttribute(doc, currentNode, axisName);
currentNode = attribute;
}
}
return currentNode;
}
if (!axisName.startsWith("@")) { 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.createAttribute(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.createElement(axisName);
}
currentNode.appendChild(selectedNode);
return selectedNode;
}
NodeList list =currentNode.getChildNodes(); 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;
}
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; private boolean isNamespaceDeclared() {
} String schemaNamespace = getNamespace();
} return schemaNamespace!=null && !schemaNamespace.equals("");
return currentNode; }
}
private String getNamespace() {
private Node createAttribute(Document doc, Node currentNode, String axisName) { return map.getCTSchema().getNamespace();
String attributeName = axisName.substring(1); }
NamedNodeMap attributesMap = currentNode.getAttributes();
Node attribute = attributesMap.getNamedItem(attributeName);
if (attribute==null) { /**
attribute = doc.createAttribute(attributeName); * Compares two xpaths to define an ordering according to the XML Schema
attributesMap.setNamedItem(attribute); *
} */
return attribute; public int compare(String leftXpath, String rightXpath) {
}
int result = 0;
private Node createElement(Document doc, Node currentNode, String axisName) { Node xmlSchema = map.getSchema();
Node selectedNode;
if (isNamespaceDeclared()) {
selectedNode =doc.createElementNS(getNamespace(),axisName); String[] leftTokens = leftXpath.split("/");
} else { String[] rightTokens = rightXpath.split("/");
selectedNode =doc.createElement(axisName);
} int minLenght = leftTokens.length< rightTokens.length? leftTokens.length : rightTokens.length;
currentNode.appendChild(selectedNode);
return selectedNode; Node localComplexTypeRootNode = xmlSchema;
}
private Node selectNode(String axisName, NodeList list) { for(int i =1;i <minLenght; i++) {
Node selectedNode = null;
for(int j=0;j<list.getLength();j++) { String leftElementName =leftTokens[i];
Node node = list.item(j); String rightElementName = rightTokens[i];
if (node.getNodeName().equals(axisName)) {
selectedNode=node; if (leftElementName.equals(rightElementName)) {
break;
}
} Node complexType = getComplexTypeForElement(leftElementName, xmlSchema,localComplexTypeRootNode);
return selectedNode; localComplexTypeRootNode = complexType;
} } else {
int leftIndex = indexOfElementInComplexType(leftElementName,localComplexTypeRootNode);
int rightIndex = indexOfElementInComplexType(rightElementName,localComplexTypeRootNode);
private boolean isNamespaceDeclared() { if (leftIndex!=-1 && rightIndex!=-1) {
String schemaNamespace = getNamespace(); if ( leftIndex < rightIndex) {
return schemaNamespace!=null && !schemaNamespace.equals(""); result = -1;
} }if ( leftIndex > rightIndex) {
result = 1;
private String getNamespace() { }
return map.getCTSchema().getNamespace(); } else {
} // NOTE: the xpath doesn't match correctly in the schema
}
}
/** }
* Compares two xpaths to define an ordering according to the XML Schema
* return result;
*/ }
public int compare(String leftXpath, String rightXpath) {
private int indexOfElementInComplexType(String elementName,Node complexType) {
int result = 0;
Node xmlSchema = map.getSchema(); NodeList list = complexType.getChildNodes();
int indexOf = -1;
String[] leftTokens = leftXpath.split("/"); for(int i=0; i< list.getLength();i++) {
String[] rightTokens = rightXpath.split("/"); Node node = list.item(i);
if (node instanceof Element) {
int minLenght = leftTokens.length< rightTokens.length? leftTokens.length : rightTokens.length; if (node.getLocalName().equals("element")) {
Node nameAttribute = node.getAttributes().getNamedItem("name");
Node localComplexTypeRootNode = xmlSchema; if (nameAttribute.getNodeValue().equals(removeNamespace(elementName))) {
indexOf = i;
break;
for(int i =1;i <minLenght; i++) { }
String leftElementName =leftTokens[i]; }
String rightElementName = rightTokens[i]; }
}
if (leftElementName.equals(rightElementName)) { return indexOf;
}
Node complexType = getComplexTypeForElement(leftElementName, xmlSchema,localComplexTypeRootNode); private Node getComplexTypeForElement(String elementName,Node xmlSchema,Node localComplexTypeRootNode) {
localComplexTypeRootNode = complexType; Node complexTypeNode = null;
} else {
int leftIndex = indexOfElementInComplexType(leftElementName,localComplexTypeRootNode); String elementNameWithoutNamespace = removeNamespace(elementName);
int rightIndex = indexOfElementInComplexType(rightElementName,localComplexTypeRootNode);
if (leftIndex!=-1 && rightIndex!=-1) {
if ( leftIndex < rightIndex) { NodeList list = localComplexTypeRootNode.getChildNodes();
result = -1; String complexTypeName = "";
}if ( leftIndex > rightIndex) {
result = 1;
}
} else { for(int i=0; i< list.getLength();i++) {
// NOTE: the xpath doesn't match correctly in the schema 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)) {
return result; Node complexTypeAttribute = node.getAttributes().getNamedItem("type");
} if (complexTypeAttribute!=null) {
complexTypeName = complexTypeAttribute.getNodeValue();
private int indexOfElementInComplexType(String elementName,Node complexType) { break;
}
NodeList list = complexType.getChildNodes(); }
int indexOf = -1; }
}
for(int i=0; i< list.getLength();i++) { }
Node node = list.item(i); // Note: we expect that all the complex types are defined at root level
if (node instanceof Element) { if (!"".equals(complexTypeName)) {
if (node.getLocalName().equals("element")) { NodeList complexTypeList = xmlSchema.getChildNodes();
Node nameAttribute = node.getAttributes().getNamedItem("name"); for(int i=0; i< complexTypeList.getLength();i++) {
if (nameAttribute.getNodeValue().equals(removeNamespace(elementName))) { Node node = list.item(i);
indexOf = i; if ( node instanceof Element) {
break; 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++) {
return indexOf; Node sequence = complexTypeChildList.item(j);
}
if ( sequence instanceof Element) {
private Node getComplexTypeForElement(String elementName,Node xmlSchema,Node localComplexTypeRootNode) { if (sequence.getLocalName().equals("sequence")) {
Node complexTypeNode = null; complexTypeNode = sequence;
break;
String elementNameWithoutNamespace = removeNamespace(elementName); }
}
}
NodeList list = localComplexTypeRootNode.getChildNodes(); if (complexTypeNode!=null) {
String complexTypeName = ""; break;
}
}
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"); return complexTypeNode;
if (nameAttribute.getNodeValue().equals(elementNameWithoutNamespace)) { }
Node complexTypeAttribute = node.getAttributes().getNamedItem("type");
if (complexTypeAttribute!=null) {
complexTypeName = complexTypeAttribute.getNodeValue();
break;
}
}
}
}
}
// Note: we expect that all the complex types are defined at root level
if (!"".equals(complexTypeName)) {
NodeList complexTypeList = xmlSchema.getChildNodes();
for(int i=0; i< complexTypeList.getLength();i++) {
Node node = list.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;
}
} }