git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@794539 13f79535-47bb-0310-9956-ffa450edef68tags/REL_3_5-FINAL
@@ -33,6 +33,7 @@ | |||
<changes> | |||
<release version="3.5-beta7" date="2009-??-??"> | |||
<action dev="POI-DEVELOPERS" type="add">47520 - Initial support for custom XML mappings in XSSF</action> | |||
<action dev="POI-DEVELOPERS" type="fix">47460 - Fixed NPE when retrieving core properties from a newly created workbook</action> | |||
<action dev="POI-DEVELOPERS" type="fix">47498 - Fixed HyperlinkRecord to properly handle URL monikers</action> | |||
<action dev="POI-DEVELOPERS" type="fix">47504 - Fixed XSSFWorkbook to read files with hyperlinks to document locations</action> |
@@ -0,0 +1,42 @@ | |||
/* ==================================================================== | |||
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.usermodel.examples; | |||
import org.apache.poi.xssf.extractor.XSSFExportToXml; | |||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; | |||
import org.apache.poi.xssf.usermodel.XSSFMap; | |||
import java.io.ByteArrayOutputStream; | |||
/** | |||
* Print all custom XML mappings registered in the given workbook | |||
*/ | |||
public class CustomXMLMapping { | |||
public static void main(String[] args) throws Exception { | |||
XSSFWorkbook wb = new XSSFWorkbook(args[0]); | |||
for (XSSFMap map : wb.getCustomXMLMappings()) { | |||
XSSFExportToXml exporter = new XSSFExportToXml(map); | |||
ByteArrayOutputStream os = new ByteArrayOutputStream(); | |||
exporter.exportToXML(os, true); | |||
String xml = os.toString("UTF-8"); | |||
System.out.println(xml); | |||
} | |||
} | |||
} |
@@ -0,0 +1,544 @@ | |||
/* ==================================================================== | |||
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.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.XMLConstants; | |||
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.xssf.model.Table; | |||
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.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 </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> | |||
* | |||
* @author Roberto Manicardi | |||
* | |||
* | |||
* | |||
*/ | |||
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 | |||
*/ | |||
public void exportToXML(OutputStream os, boolean validate) throws SAXException{ | |||
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 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(); | |||
try{ | |||
Document doc = getEmptyDocument(); | |||
Element root = null; | |||
if(isNamespaceDeclared()){ | |||
root=doc.createElementNS(getNamespace(),rootElement); | |||
}else{ | |||
root=doc.createElement(rootElement); | |||
} | |||
doc.appendChild(root); | |||
List<String> xpaths = new Vector<String>(); | |||
Map<String,XSSFSingleXmlCell> singleXmlCellsMappings = new HashMap<String,XSSFSingleXmlCell>(); | |||
Map<String,Table> tableMappings = new HashMap<String,Table>(); | |||
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); | |||
} | |||
Collections.sort(xpaths,this); | |||
for(String xpath : xpaths){ | |||
XSSFSingleXmlCell simpleXmlCell = singleXmlCellsMappings.get(xpath); | |||
Table 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); | |||
} | |||
} | |||
// 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); | |||
} | |||
}catch(ParserConfigurationException e){ | |||
e.printStackTrace(); | |||
}catch(TransformerException e){ | |||
e.printStackTrace(); | |||
} | |||
} | |||
/** | |||
* 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()); | |||
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(); | |||
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){ | |||
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.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; | |||
} | |||
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 | |||
* | |||
*/ | |||
public int compare(String leftXpath, String rightXpath) { | |||
int result = 0; | |||
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){ | |||
result = -1; | |||
}if( leftIndex > rightIndex){ | |||
result = 1; | |||
} | |||
}else{ | |||
// NOTE: the xpath doesn't match correctly in the schema | |||
} | |||
} | |||
} | |||
return result; | |||
} | |||
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){ | |||
Node complexTypeNode = null; | |||
String elementNameWithoutNamespace = removeNamespace(elementName); | |||
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; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
// Note: we expect that all the complex types are defined at root level | |||
if(!complexTypeName.equals("")){ | |||
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; | |||
} | |||
} |
@@ -0,0 +1,148 @@ | |||
/* ==================================================================== | |||
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.model; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.util.Collection; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Iterator; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.xssf.usermodel.XSSFMap; | |||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMap; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMapInfo; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSchema; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.MapInfoDocument; | |||
/** | |||
* | |||
* This class implements the Custom XML Mapping Part (Open Office XML Part 1: | |||
* chapter 12.3.6) | |||
* | |||
* An instance of this part type contains a schema for an XML file, and | |||
* information on the behavior that is used when allowing this custom XML schema | |||
* to be mapped into the spreadsheet. | |||
* | |||
* @author Roberto Manicardi | |||
*/ | |||
public class MapInfo extends POIXMLDocumentPart { | |||
private CTMapInfo mapInfo; | |||
private Map<Integer, XSSFMap> maps ; | |||
public MapInfo() { | |||
super(); | |||
mapInfo = CTMapInfo.Factory.newInstance(); | |||
} | |||
public MapInfo(PackagePart part, PackageRelationship rel) | |||
throws IOException { | |||
super(part, rel); | |||
readFrom(part.getInputStream()); | |||
} | |||
public void readFrom(InputStream is) throws IOException { | |||
try { | |||
MapInfoDocument doc = MapInfoDocument.Factory.parse(is); | |||
mapInfo = doc.getMapInfo(); | |||
maps= new HashMap<Integer, XSSFMap>(); | |||
for(CTMap map :mapInfo.getMapArray()){ | |||
maps.put((int)map.getID(), new XSSFMap(map,this)); | |||
} | |||
} catch (XmlException e) { | |||
throw new IOException(e.getLocalizedMessage()); | |||
} | |||
} | |||
/** | |||
* Returns the parent XSSFWorkbook | |||
* | |||
* @return the parent XSSFWorkbook | |||
*/ | |||
public XSSFWorkbook getWorkbook() { | |||
return (XSSFWorkbook)getParent(); | |||
} | |||
/** | |||
* | |||
* @return the internal data object | |||
*/ | |||
public CTMapInfo getCTMapInfo(){ | |||
return mapInfo; | |||
} | |||
/** | |||
* Gets the CTSchema buy it's ID | |||
* @param schemaId the schema ID | |||
* @return | |||
*/ | |||
public CTSchema getCTSchemaById(String schemaId){ | |||
CTSchema xmlSchema = null; | |||
CTSchema[] schemas = mapInfo.getSchemaArray(); | |||
for(CTSchema schema: schemas){ | |||
if(schema.getID().equals(schemaId)){ | |||
xmlSchema = schema; | |||
break; | |||
} | |||
} | |||
return xmlSchema; | |||
} | |||
public XSSFMap getXSSFMapById(int id){ | |||
return maps.get(id); | |||
} | |||
/** | |||
* | |||
* @return all the mappings configured in this document | |||
*/ | |||
public Collection<XSSFMap> getAllXSSFMaps(){ | |||
return maps.values(); | |||
} | |||
protected void writeTo(OutputStream out) throws IOException { | |||
MapInfoDocument doc = MapInfoDocument.Factory.newInstance(); | |||
doc.setMapInfo(mapInfo); | |||
doc.save(out, DEFAULT_XML_OPTIONS); | |||
} | |||
@Override | |||
protected void commit() throws IOException { | |||
PackagePart part = getPackagePart(); | |||
OutputStream out = part.getOutputStream(); | |||
writeTo(out); | |||
out.close(); | |||
} | |||
} |
@@ -0,0 +1,106 @@ | |||
/* ==================================================================== | |||
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.model; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.util.List; | |||
import java.util.Vector; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.xssf.usermodel.XSSFSheet; | |||
import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSingleXmlCell; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSingleXmlCells; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.SingleXmlCellsDocument; | |||
/** | |||
* | |||
* This class implements the Single Cell Tables Part (Open Office XML Part 4: | |||
* chapter 3.5.2) | |||
* | |||
* | |||
* @author Roberto Manicardi | |||
*/ | |||
public class SingleXmlCells extends POIXMLDocumentPart { | |||
private CTSingleXmlCells singleXMLCells; | |||
public SingleXmlCells() { | |||
super(); | |||
singleXMLCells = CTSingleXmlCells.Factory.newInstance(); | |||
} | |||
public SingleXmlCells(PackagePart part, PackageRelationship rel) | |||
throws IOException { | |||
super(part, rel); | |||
readFrom(part.getInputStream()); | |||
} | |||
public void readFrom(InputStream is) throws IOException { | |||
try { | |||
SingleXmlCellsDocument doc = SingleXmlCellsDocument.Factory.parse(is); | |||
singleXMLCells = doc.getSingleXmlCells(); | |||
} catch (XmlException e) { | |||
throw new IOException(e.getLocalizedMessage()); | |||
} | |||
} | |||
public XSSFSheet getXSSFSheet(){ | |||
return (XSSFSheet) getParent(); | |||
} | |||
protected void writeTo(OutputStream out) throws IOException { | |||
SingleXmlCellsDocument doc = SingleXmlCellsDocument.Factory.newInstance(); | |||
doc.setSingleXmlCells(singleXMLCells); | |||
doc.save(out, DEFAULT_XML_OPTIONS); | |||
} | |||
@Override | |||
protected void commit() throws IOException { | |||
PackagePart part = getPackagePart(); | |||
OutputStream out = part.getOutputStream(); | |||
writeTo(out); | |||
out.close(); | |||
} | |||
public CTSingleXmlCells getCTSingleXMLCells(){ | |||
return singleXMLCells; | |||
} | |||
/** | |||
* | |||
* @return all the SimpleXmlCell contained in this SingleXmlCells element | |||
*/ | |||
public List<XSSFSingleXmlCell> getAllSimpleXmlCell(){ | |||
List<XSSFSingleXmlCell> list = new Vector<XSSFSingleXmlCell>(); | |||
CTSingleXmlCell[] singleXMLCellArray = singleXMLCells.getSingleXmlCellArray(); | |||
for(CTSingleXmlCell singleXmlCell: singleXMLCellArray){ | |||
list.add(new XSSFSingleXmlCell(singleXmlCell,this)); | |||
} | |||
return list; | |||
} | |||
} |
@@ -0,0 +1,248 @@ | |||
/* ==================================================================== | |||
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.model; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.util.Arrays; | |||
import java.util.List; | |||
import java.util.Vector; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.openxml4j.opc.PackagePart; | |||
import org.apache.poi.openxml4j.opc.PackageRelationship; | |||
import org.apache.poi.ss.util.CellReference; | |||
import org.apache.poi.xssf.usermodel.XSSFSheet; | |||
import org.apache.poi.xssf.usermodel.helpers.XSSFXmlColumnPr; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTable; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.TableDocument; | |||
/** | |||
* | |||
* This class implements the Table Part (Open Office XML Part 4: | |||
* chapter 3.5.1) | |||
* | |||
* This implementation works under the assumption that a table contains mappings to a subtree of an XML. | |||
* The root element of this subtree an occur multiple times (one for each row of the table). The child nodes | |||
* of the root element can be only attributes or element with maxOccurs=1 property set | |||
* | |||
* | |||
* @author Roberto Manicardi | |||
*/ | |||
public class Table extends POIXMLDocumentPart { | |||
private CTTable ctTable; | |||
private List<XSSFXmlColumnPr> xmlColumnPr; | |||
private CellReference startCellReference; | |||
private CellReference endCellReference; | |||
private String commonXPath; | |||
public Table() { | |||
super(); | |||
ctTable = CTTable.Factory.newInstance(); | |||
} | |||
public Table(PackagePart part, PackageRelationship rel) | |||
throws IOException { | |||
super(part, rel); | |||
readFrom(part.getInputStream()); | |||
} | |||
public void readFrom(InputStream is) throws IOException { | |||
try { | |||
TableDocument doc = TableDocument.Factory.parse(is); | |||
ctTable = doc.getTable(); | |||
} catch (XmlException e) { | |||
throw new IOException(e.getLocalizedMessage()); | |||
} | |||
} | |||
public XSSFSheet getXSSFSheet(){ | |||
return (XSSFSheet) getParent(); | |||
} | |||
public void writeTo(OutputStream out) throws IOException { | |||
TableDocument doc = TableDocument.Factory.newInstance(); | |||
doc.setTable(ctTable); | |||
doc.save(out, DEFAULT_XML_OPTIONS); | |||
} | |||
@Override | |||
protected void commit() throws IOException { | |||
PackagePart part = getPackagePart(); | |||
OutputStream out = part.getOutputStream(); | |||
writeTo(out); | |||
out.close(); | |||
} | |||
public CTTable getCTTable(){ | |||
return ctTable; | |||
} | |||
/** | |||
* Checks if this Table element contains even a single mapping to the map identified by id | |||
* @param id the XSSFMap ID | |||
* @return true if the Table element contain mappings | |||
*/ | |||
public boolean mapsTo(long id){ | |||
boolean maps =false; | |||
List<XSSFXmlColumnPr> pointers = getXmlColumnPrs(); | |||
for(XSSFXmlColumnPr pointer: pointers){ | |||
if(pointer.getMapId()==id){ | |||
maps=true; | |||
break; | |||
} | |||
} | |||
return maps; | |||
} | |||
/** | |||
* | |||
* Calculates the xpath of the root element for the table. This will be the common part | |||
* of all the mapping's xpaths | |||
* | |||
* @return the xpath of the table's root element | |||
*/ | |||
public String getCommonXpath() { | |||
if(commonXPath == null){ | |||
String[] commonTokens ={}; | |||
for(CTTableColumn column :ctTable.getTableColumns().getTableColumnArray()){ | |||
if(column.getXmlColumnPr()!=null){ | |||
String xpath = column.getXmlColumnPr().getXpath(); | |||
String[] tokens = xpath.split("/"); | |||
if(commonTokens.length==0){ | |||
commonTokens = tokens; | |||
}else{ | |||
int maxLenght = commonTokens.length>tokens.length? tokens.length:commonTokens.length; | |||
for(int i =0; i<maxLenght;i++){ | |||
if(!commonTokens[i].equals(tokens[i])){ | |||
List<String> subCommonTokens = Arrays.asList(commonTokens).subList(0, i); | |||
String[] container = {}; | |||
commonTokens = subCommonTokens.toArray(container); | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
commonXPath =""; | |||
for(int i = 1 ; i< commonTokens.length;i++){ | |||
commonXPath +="/"+commonTokens[i]; | |||
} | |||
} | |||
return commonXPath; | |||
} | |||
public List<XSSFXmlColumnPr> getXmlColumnPrs() { | |||
if(xmlColumnPr==null){ | |||
xmlColumnPr = new Vector<XSSFXmlColumnPr>(); | |||
for(CTTableColumn column:ctTable.getTableColumns().getTableColumnArray()){ | |||
if(column.getXmlColumnPr()!=null){ | |||
XSSFXmlColumnPr columnPr = new XSSFXmlColumnPr(this,column,column.getXmlColumnPr()); | |||
xmlColumnPr.add(columnPr); | |||
} | |||
} | |||
} | |||
return xmlColumnPr; | |||
} | |||
/** | |||
* the number of mapped table columns (see Open Office XML Part 4: chapter 3.5.1.4) | |||
* @return | |||
*/ | |||
public long getNumerOfMappedColumns(){ | |||
return ctTable.getTableColumns().getCount(); | |||
} | |||
/** | |||
* The reference for the cell in the top-left part of the table | |||
* (see Open Office XML Part 4: chapter 3.5.1.2, attribute ref) | |||
* @return | |||
*/ | |||
public CellReference getStartCellReference() { | |||
if(startCellReference==null){ | |||
String ref = ctTable.getRef(); | |||
String[] boundaries = ref.split(":"); | |||
String from = boundaries[0]; | |||
startCellReference = new CellReference(from); | |||
} | |||
return startCellReference; | |||
} | |||
/** | |||
* The reference for the cell in the bottom-right part of the table | |||
* (see Open Office XML Part 4: chapter 3.5.1.2, attribute ref) | |||
* @return | |||
*/ | |||
public CellReference getEndCellReference() { | |||
if(endCellReference==null){ | |||
String ref = ctTable.getRef(); | |||
String[] boundaries = ref.split(":"); | |||
String from = boundaries[1]; | |||
endCellReference = new CellReference(from); | |||
} | |||
return endCellReference; | |||
} | |||
/** | |||
* Gets the total number of rows in the selection. (Note: in this version autofiltering is ignored) | |||
* @return | |||
*/ | |||
public int getRowCount(){ | |||
CellReference from = getStartCellReference(); | |||
CellReference to = getEndCellReference(); | |||
int rowCount = -1; | |||
if (from!=null && to!=null){ | |||
rowCount = to.getRow()-from.getRow(); | |||
} | |||
return rowCount; | |||
} | |||
} |
@@ -0,0 +1,120 @@ | |||
/* ==================================================================== | |||
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.usermodel; | |||
import java.util.List; | |||
import java.util.Vector; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.xssf.model.MapInfo; | |||
import org.apache.poi.xssf.model.SingleXmlCells; | |||
import org.apache.poi.xssf.model.Table; | |||
import org.apache.poi.xssf.usermodel.helpers.XSSFSingleXmlCell; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMap; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSchema; | |||
import org.w3c.dom.Node; | |||
/** | |||
* This class implements the Map element (Open Office XML Part 4: | |||
* chapter 3.16.2) | |||
* <p/> | |||
* This element contains all of the properties related to the XML map, | |||
* and the behaviors expected during data refresh operations. | |||
* | |||
* @author Roberto Manicardi | |||
*/ | |||
public class XSSFMap { | |||
private CTMap ctMap; | |||
private MapInfo mapInfo; | |||
public XSSFMap(CTMap ctMap, MapInfo mapInfo) { | |||
this.ctMap = ctMap; | |||
this.mapInfo = mapInfo; | |||
} | |||
public CTMap getCtMap() { | |||
return ctMap; | |||
} | |||
public CTSchema getCTSchema() { | |||
String schemaId = ctMap.getSchemaID(); | |||
return mapInfo.getCTSchemaById(schemaId); | |||
} | |||
public Node getSchema() { | |||
Node xmlSchema = null; | |||
CTSchema schema = getCTSchema(); | |||
xmlSchema = schema.getDomNode().getFirstChild(); | |||
return xmlSchema; | |||
} | |||
/** | |||
* @return the list of Single Xml Cells that provide a map rule to this mapping. | |||
*/ | |||
public List<XSSFSingleXmlCell> getRelatedSingleXMLCell() { | |||
List<XSSFSingleXmlCell> relatedSimpleXmlCells = new Vector<XSSFSingleXmlCell>(); | |||
int sheetNumber = mapInfo.getWorkbook().getNumberOfSheets(); | |||
for (int i = 0; i < sheetNumber; i++) { | |||
XSSFSheet sheet = mapInfo.getWorkbook().getSheetAt(i); | |||
for (POIXMLDocumentPart p : sheet.getRelations()) { | |||
if (p instanceof SingleXmlCells) { | |||
SingleXmlCells singleXMLCells = (SingleXmlCells) p; | |||
for (XSSFSingleXmlCell cell : singleXMLCells.getAllSimpleXmlCell()) { | |||
if (cell.getMapId() == ctMap.getID()) { | |||
relatedSimpleXmlCells.add(cell); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
return relatedSimpleXmlCells; | |||
} | |||
/** | |||
* @return the list of all Tables that provide a map rule to this mapping | |||
*/ | |||
public List<Table> getRelatedTables() { | |||
List<Table> tables = new Vector<Table>(); | |||
int sheetNumber = mapInfo.getWorkbook().getNumberOfSheets(); | |||
for (int i = 0; i < sheetNumber; i++) { | |||
XSSFSheet sheet = mapInfo.getWorkbook().getSheetAt(i); | |||
for (POIXMLDocumentPart p : sheet.getRelations()) { | |||
if (p.getPackageRelationship().getRelationshipType().equals(XSSFRelation.TABLE.getRelation())) { | |||
Table table = (Table) p; | |||
if (table.mapsTo(ctMap.getID())) { | |||
tables.add(table); | |||
} | |||
} | |||
} | |||
} | |||
return tables; | |||
} | |||
} |
@@ -25,10 +25,13 @@ import java.util.HashMap; | |||
import org.apache.poi.POIXMLDocument; | |||
import org.apache.poi.POIXMLRelation; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.xssf.model.MapInfo; | |||
import org.apache.poi.xssf.model.SingleXmlCells; | |||
import org.apache.poi.xssf.model.StylesTable; | |||
import org.apache.poi.xssf.model.SharedStringsTable; | |||
import org.apache.poi.xssf.model.CommentsTable; | |||
import org.apache.poi.xssf.model.CalculationChain; | |||
import org.apache.poi.xssf.model.Table; | |||
import org.apache.poi.util.POILogFactory; | |||
import org.apache.poi.util.POILogger; | |||
import org.apache.poi.openxml4j.exceptions.InvalidFormatException; | |||
@@ -93,6 +96,28 @@ public final class XSSFRelation extends POIXMLRelation { | |||
"/xl/drawings/vmlDrawing#.vml", | |||
null | |||
); | |||
public static final XSSFRelation CUSTOM_XML_MAPPINGS = new XSSFRelation( | |||
"application/xml", | |||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/xmlMaps", | |||
"/xl/xmlMaps.xml", | |||
MapInfo.class | |||
); | |||
public static final XSSFRelation SINGLE_XML_CELLS = new XSSFRelation( | |||
"application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml", | |||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/tableSingleCells", | |||
"/tables/tableSingleCells#.xml", | |||
SingleXmlCells.class | |||
); | |||
public static final XSSFRelation TABLE = new XSSFRelation( | |||
"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml", | |||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/table", | |||
"/tables/table#.xml", | |||
Table.class | |||
); | |||
public static final XSSFRelation IMAGES = new XSSFRelation( | |||
null, | |||
"http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", |
@@ -22,12 +22,7 @@ import java.io.ByteArrayOutputStream; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.Iterator; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.*; | |||
import java.util.regex.Pattern; | |||
import javax.xml.namespace.QName; | |||
@@ -56,6 +51,8 @@ import org.apache.poi.util.PackageHelper; | |||
import org.apache.poi.xssf.model.CalculationChain; | |||
import org.apache.poi.xssf.model.SharedStringsTable; | |||
import org.apache.poi.xssf.model.StylesTable; | |||
import org.apache.poi.xssf.model.MapInfo; | |||
import org.apache.poi.xssf.extractor.XSSFExportToXml; | |||
import org.apache.xmlbeans.XmlException; | |||
import org.apache.xmlbeans.XmlObject; | |||
import org.apache.xmlbeans.XmlOptions; | |||
@@ -106,6 +103,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X | |||
*/ | |||
private CalculationChain calcChain; | |||
/** | |||
* A collection of custom XML mappings | |||
*/ | |||
private MapInfo mapInfo; | |||
/** | |||
* Used to keep track of the data formatter so that all | |||
* createDataFormatter calls return the same one for a given | |||
@@ -174,6 +176,7 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X | |||
if(p instanceof SharedStringsTable) sharedStringSource = (SharedStringsTable)p; | |||
else if(p instanceof StylesTable) stylesSource = (StylesTable)p; | |||
else if(p instanceof CalculationChain) calcChain = (CalculationChain)p; | |||
else if(p instanceof MapInfo) mapInfo = (MapInfo)p; | |||
else if (p instanceof XSSFSheet) { | |||
shIdMap.put(p.getPackageRelationship().getId(), (XSSFSheet)p); | |||
} | |||
@@ -1282,4 +1285,11 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook, Iterable<X | |||
return calcChain; | |||
} | |||
/** | |||
* | |||
* @return a collection of custom XML mappings defined in this workbook | |||
*/ | |||
public Collection<XSSFMap> getCustomXMLMappings(){ | |||
return mapInfo == null ? new ArrayList<XSSFMap>() : mapInfo.getAllXSSFMaps(); | |||
} | |||
} |
@@ -0,0 +1,84 @@ | |||
/* ==================================================================== | |||
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.usermodel.helpers; | |||
import org.apache.poi.ss.util.CellReference; | |||
import org.apache.poi.xssf.model.SingleXmlCells; | |||
import org.apache.poi.xssf.usermodel.XSSFCell; | |||
import org.apache.poi.xssf.usermodel.XSSFRow; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSingleXmlCell; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXmlCellPr; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXmlPr; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STXmlDataType.Enum; | |||
/** | |||
* | |||
* This class is a wrapper around the CTSingleXmlCell (Open Office XML Part 4: | |||
* chapter 3.5.2.1) | |||
* | |||
* | |||
* @author Roberto Manicardi | |||
* | |||
*/ | |||
public class XSSFSingleXmlCell { | |||
private CTSingleXmlCell singleXmlCell; | |||
private SingleXmlCells parent; | |||
public XSSFSingleXmlCell(CTSingleXmlCell singleXmlCell, SingleXmlCells parent){ | |||
this.singleXmlCell = singleXmlCell; | |||
this.parent = parent; | |||
} | |||
/** | |||
* Gets the XSSFCell referenced by the R attribute | |||
* @return the referenced XSSFCell, null if the cell reference is invalid | |||
*/ | |||
public XSSFCell getReferencedCell(){ | |||
XSSFCell cell = null; | |||
CellReference cellReference = new CellReference(singleXmlCell.getR()); | |||
XSSFRow row = parent.getXSSFSheet().getRow(cellReference.getRow()); | |||
cell = row.getCell(cellReference.getCol()); | |||
return cell; | |||
} | |||
public String getXpath(){ | |||
CTXmlCellPr xmlCellPr = singleXmlCell.getXmlCellPr(); | |||
CTXmlPr xmlPr = xmlCellPr.getXmlPr(); | |||
String xpath = xmlPr.getXpath(); | |||
return xpath; | |||
} | |||
public long getMapId(){ | |||
return singleXmlCell.getXmlCellPr().getXmlPr().getMapId(); | |||
} | |||
public Enum getXmlDataType() { | |||
CTXmlCellPr xmlCellPr = singleXmlCell.getXmlCellPr(); | |||
CTXmlPr xmlPr = xmlCellPr.getXmlPr(); | |||
return xmlPr.getXmlDataType(); | |||
} | |||
} |
@@ -0,0 +1,65 @@ | |||
/* ==================================================================== | |||
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.usermodel.helpers; | |||
import org.apache.poi.xssf.model.Table; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTTableColumn; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTXmlColumnPr; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.STXmlDataType.Enum; | |||
/** | |||
* | |||
* This class is a wrapper around the CTXmlColumnPr (Open Office XML Part 4: | |||
* chapter 3.5.1.7) | |||
* | |||
* | |||
* @author Roberto Manicardi | |||
*/ | |||
public class XSSFXmlColumnPr { | |||
private Table table; | |||
private CTTableColumn ctTableColumn; | |||
private CTXmlColumnPr ctXmlColumnPr; | |||
public XSSFXmlColumnPr(Table table ,CTTableColumn ctTableColum,CTXmlColumnPr ctXmlColumnPr){ | |||
this.table = table; | |||
this.ctTableColumn = ctTableColum; | |||
this.ctXmlColumnPr = ctXmlColumnPr; | |||
} | |||
public long getMapId(){ | |||
return ctXmlColumnPr.getMapId(); | |||
} | |||
public String getLocalXPath(){ | |||
String localXPath = ""; | |||
int numberOfCommonXPathAxis = table.getCommonXpath().split("/").length-1; | |||
String[] xPathTokens = ctXmlColumnPr.getXpath().split("/"); | |||
for(int i=numberOfCommonXPathAxis; i<xPathTokens.length;i++){ | |||
localXPath += "/" +xPathTokens[i]; | |||
} | |||
return localXPath; | |||
} | |||
public Enum getXmlDataType() { | |||
return ctXmlColumnPr.getXmlDataType(); | |||
} | |||
} |
@@ -0,0 +1,220 @@ | |||
/* ==================================================================== | |||
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.ByteArrayOutputStream; | |||
import java.util.regex.Matcher; | |||
import java.util.regex.Pattern; | |||
import junit.framework.TestCase; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.xssf.XSSFTestDataSamples; | |||
import org.apache.poi.xssf.model.MapInfo; | |||
import org.apache.poi.xssf.usermodel.XSSFMap; | |||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; | |||
/** | |||
* | |||
* @author Roberto Manicardi | |||
* | |||
*/ | |||
public class TestXSSFExportToXML extends TestCase{ | |||
public void testExportToXML() throws Exception{ | |||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXmlMappings.xlsx"); | |||
MapInfo mapInfo = null; | |||
for(POIXMLDocumentPart p : wb.getRelations()){ | |||
if(p instanceof 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); | |||
assertTrue(!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); | |||
} | |||
} | |||
} | |||
public void testExportToXMLInverseOrder() throws Exception{ | |||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXmlMappings-inverse-order.xlsx"); | |||
MapInfo mapInfo = null; | |||
for(POIXMLDocumentPart p : wb.getRelations()){ | |||
if(p instanceof 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); | |||
assertTrue(!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); | |||
} | |||
} | |||
} | |||
public void testXPathOrdering() throws Exception{ | |||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXmlMappings-inverse-order.xlsx"); | |||
MapInfo mapInfo = null; | |||
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")); | |||
} | |||
} | |||
} | |||
public void testMultiTable() throws Exception{ | |||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXMLMappings-complex-type.xlsx"); | |||
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()); | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,84 @@ | |||
/* ==================================================================== | |||
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.model; | |||
import org.apache.poi.POIXMLDocumentPart; | |||
import org.apache.poi.xssf.XSSFTestDataSamples; | |||
import org.apache.poi.xssf.usermodel.XSSFMap; | |||
import org.apache.poi.xssf.usermodel.XSSFSheet; | |||
import org.apache.poi.xssf.usermodel.XSSFWorkbook; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTSchema; | |||
import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTMapInfo; | |||
import org.w3c.dom.Node; | |||
import junit.framework.TestCase; | |||
/** | |||
* @author Roberto Manicardi | |||
*/ | |||
public class TestMapInfo extends TestCase { | |||
public void testMapInfoExists() throws Exception { | |||
XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("CustomXmlMappings.xlsx"); | |||
MapInfo mapInfo = null; | |||
SingleXmlCells singleXMLCells = null; | |||
for (POIXMLDocumentPart p : wb.getRelations()) { | |||
if (p instanceof MapInfo) { | |||
mapInfo = (MapInfo) p; | |||
CTMapInfo ctMapInfo = mapInfo.getCTMapInfo(); | |||
assertNotNull(ctMapInfo); | |||
CTSchema[] schemas = ctMapInfo.getSchemaArray(); | |||
assertEquals(1, schemas.length); | |||
for (XSSFMap map : mapInfo) { | |||
Node xmlSchema = map.getSchema(); | |||
assertNotNull(xmlSchema); | |||
} | |||
} | |||
} | |||
XSSFSheet sheet1 = wb.getSheetAt(0); | |||
for (POIXMLDocumentPart p : sheet1.getRelations()) { | |||
if (p instanceof SingleXmlCells) { | |||
singleXMLCells = (SingleXmlCells) p; | |||
} | |||
} | |||
assertNotNull(mapInfo); | |||
assertNotNull(singleXMLCells); | |||
} | |||
} |