aboutsummaryrefslogtreecommitdiffstats
path: root/src/ooxml/java
diff options
context:
space:
mode:
authorYegor Kozlov <yegor@apache.org>2009-07-16 05:46:14 +0000
committerYegor Kozlov <yegor@apache.org>2009-07-16 05:46:14 +0000
commit35906116edf297fbe512765cc4728acfca3b20eb (patch)
treeb57959b63798fc8ae04b63ea330539537d19ed8a /src/ooxml/java
parent27832ad35675cab8492cb702b952e2636560ea31 (diff)
downloadpoi-35906116edf297fbe512765cc4728acfca3b20eb.tar.gz
poi-35906116edf297fbe512765cc4728acfca3b20eb.zip
support for custom XML mappings in XSSF, see Bugzilla 47520
git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@794539 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'src/ooxml/java')
-rwxr-xr-xsrc/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java544
-rwxr-xr-xsrc/ooxml/java/org/apache/poi/xssf/model/MapInfo.java148
-rwxr-xr-xsrc/ooxml/java/org/apache/poi/xssf/model/SingleXmlCells.java106
-rwxr-xr-xsrc/ooxml/java/org/apache/poi/xssf/model/Table.java248
-rwxr-xr-xsrc/ooxml/java/org/apache/poi/xssf/usermodel/XSSFMap.java120
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java25
-rw-r--r--src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java22
-rwxr-xr-xsrc/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFSingleXmlCell.java84
-rwxr-xr-xsrc/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFXmlColumnPr.java65
9 files changed, 1356 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
new file mode 100755
index 0000000000..01d96832b2
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xssf/extractor/XSSFExportToXml.java
@@ -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 &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>
+ *
+ * @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;
+
+
+ }
+
+
+}
diff --git a/src/ooxml/java/org/apache/poi/xssf/model/MapInfo.java b/src/ooxml/java/org/apache/poi/xssf/model/MapInfo.java
new file mode 100755
index 0000000000..d301f18a16
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xssf/model/MapInfo.java
@@ -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();
+ }
+
+}
diff --git a/src/ooxml/java/org/apache/poi/xssf/model/SingleXmlCells.java b/src/ooxml/java/org/apache/poi/xssf/model/SingleXmlCells.java
new file mode 100755
index 0000000000..9b118bfdf8
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xssf/model/SingleXmlCells.java
@@ -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;
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xssf/model/Table.java b/src/ooxml/java/org/apache/poi/xssf/model/Table.java
new file mode 100755
index 0000000000..9ab24ac57a
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xssf/model/Table.java
@@ -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;
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFMap.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFMap.java
new file mode 100755
index 0000000000..33c742f6e7
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFMap.java
@@ -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;
+ }
+}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java
index 73fe263a26..c3b97c6c75 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java
@@ -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",
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
index 5d509260e3..5453b33b14 100644
--- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java
@@ -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;
@@ -107,6 +104,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
* book. This ensures that updates from one places is visible
@@ -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();
+ }
}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFSingleXmlCell.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFSingleXmlCell.java
new file mode 100755
index 0000000000..055f2b8145
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFSingleXmlCell.java
@@ -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();
+ }
+
+}
diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFXmlColumnPr.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFXmlColumnPr.java
new file mode 100755
index 0000000000..c03b56e250
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/helpers/XSSFXmlColumnPr.java
@@ -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();
+ }
+
+}