From 09470f80baaed68a42c1fa608119eb068931f5fe Mon Sep 17 00:00:00 2001 From: Nick Burch Date: Fri, 8 Apr 2011 20:51:52 +0000 Subject: [PATCH] Initial support for XSSF Charts. Provides easy access to the underlying CTChart object via the Sheet Drawing, but no high level interface onto the chart contents as yet. git-svn-id: https://svn.apache.org/repos/asf/poi/trunk@1090442 13f79535-47bb-0310-9956-ffa450edef68 --- src/documentation/content/xdocs/status.xml | 1 + .../apache/poi/xssf/usermodel/XSSFChart.java | 147 ++++++++++++++++++ .../poi/xssf/usermodel/XSSFDrawing.java | 23 ++- .../poi/xssf/usermodel/XSSFRelation.java | 10 +- .../poi/xssf/usermodel/TestXSSFChart.java | 58 +++++++ .../xssf/usermodel/TestXSSFChartSheet.java | 13 ++ 6 files changed, 247 insertions(+), 5 deletions(-) create mode 100644 src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java create mode 100644 src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChart.java diff --git a/src/documentation/content/xdocs/status.xml b/src/documentation/content/xdocs/status.xml index f6b693360..93500e662 100644 --- a/src/documentation/content/xdocs/status.xml +++ b/src/documentation/content/xdocs/status.xml @@ -34,6 +34,7 @@ + Initial support for XSSF Charts. Provides easy access to the underlying CTChart object via the Sheet Drawing, but no high level interface onto the chart contents as yet. 50884 - XSSF and HSSF freeze panes now behave the same Support for adding a table to a XSSFSheet Improve HSMF MAPIMessage access to the HTML and RTF versions of the message body (where available) diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java new file mode 100644 index 000000000..6f2accf28 --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFChart.java @@ -0,0 +1,147 @@ +/* ==================================================================== + 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.io.IOException; +import java.io.OutputStream; +import java.util.HashMap; +import java.util.Map; + +import org.apache.poi.POIXMLDocumentPart; +import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.openxml4j.opc.PackageRelationship; +import org.apache.poi.util.Internal; +import org.apache.xmlbeans.XmlException; +import org.apache.xmlbeans.XmlObject; +import org.apache.xmlbeans.XmlOptions; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTChartSpace; +import org.openxmlformats.schemas.drawingml.x2006.chart.CTTitle; +import org.openxmlformats.schemas.drawingml.x2006.chart.ChartSpaceDocument; +import org.openxmlformats.schemas.officeDocument.x2006.relationships.STRelationshipId; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; + +/** + * Represents a SpreadsheetML Chart + */ +public final class XSSFChart extends POIXMLDocumentPart { + /** + * Root element of the SpreadsheetML Chart part + */ + private CTChartSpace chartSpace; + /** + * The Chart within that + */ + private CTChart chart; + + /** + * Create a new SpreadsheetML chart + */ + protected XSSFChart() { + super(); + createChart(); + } + + /** + * Construct a SpreadsheetML chart from a package part + * + * @param part the package part holding the chart data, + * the content type must be application/vnd.openxmlformats-officedocument.drawingml.chart+xml + * @param rel the package relationship holding this chart, + * the relationship type must be http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart + */ + protected XSSFChart(PackagePart part, PackageRelationship rel) throws IOException, XmlException { + super(part, rel); + + chartSpace = ChartSpaceDocument.Factory.parse(part.getInputStream()).getChartSpace(); + chart = chartSpace.getChart(); + } + + /** + * Construct a new CTChartSpace bean. By default, it's just an empty placeholder for chart objects + * + * @return a new CTChartSpace bean + */ + private void createChart() { + chartSpace = CTChartSpace.Factory.newInstance(); + chart = chartSpace.addNewChart(); + } + + /** + * Return the underlying CTChartSpace bean, the root element of the SpreadsheetML Chart part. + * + * @return the underlying CTChartSpace bean + */ + @Internal + public CTChartSpace getCTChartSpace(){ + return chartSpace; + } + + /** + * Return the underlying CTChart bean, within the Chart Space + * + * @return the underlying CTChart bean + */ + @Internal + public CTChart getCTChart(){ + return chart; + } + + @Override + protected void commit() throws IOException { + XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS); + + Map map = new HashMap(); + map.put(XSSFDrawing.NAMESPACE_A, "a"); + map.put(STRelationshipId.type.getName().getNamespaceURI(), "r"); + xmlOptions.setSaveSuggestedPrefixes(map); + + PackagePart part = getPackagePart(); + OutputStream out = part.getOutputStream(); + chartSpace.save(out, xmlOptions); + out.close(); + } + + /** + * Returns the title, or null if none is set + */ + public XSSFRichTextString getTitle() { + if(! chart.isSetTitle()) { + return null; + } + + // TODO Do properly + CTTitle title = chart.getTitle(); + + StringBuffer text = new StringBuffer(); + XmlObject[] t = title + .selectPath("declare namespace a='"+XSSFDrawing.NAMESPACE_A+"' .//a:t"); + for (int m = 0; m < t.length; m++) { + NodeList kids = t[m].getDomNode().getChildNodes(); + for (int n = 0; n < kids.getLength(); n++) { + if (kids.item(n) instanceof Text) { + text.append(kids.item(n).getNodeValue()); + } + } + } + + return new XSSFRichTextString(text.toString()); + } + +} diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java index ae5410cc6..956f08f11 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFDrawing.java @@ -19,20 +19,22 @@ package org.apache.poi.xssf.usermodel; import java.io.IOException; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.xml.namespace.QName; import org.apache.poi.POIXMLDocumentPart; -import org.apache.poi.util.Internal; -import org.apache.poi.xssf.model.CommentsTable; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.openxml4j.opc.PackagePartName; import org.apache.poi.openxml4j.opc.PackageRelationship; import org.apache.poi.openxml4j.opc.TargetMode; import org.apache.poi.ss.usermodel.ClientAnchor; import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.util.Internal; +import org.apache.poi.xssf.model.CommentsTable; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlOptions; import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTConnector; @@ -55,6 +57,8 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing { */ private CTDrawing drawing; private boolean isNew; + + protected static final String NAMESPACE_A = "http://schemas.openxmlformats.org/drawingml/2006/main"; /** * Create a new SpreadsheetML drawing @@ -111,7 +115,7 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing { */ if(isNew) xmlOptions.setSaveSyntheticDocumentElement(new QName(CTDrawing.type.getName().getNamespaceURI(), "wsDr", "xdr")); Map map = new HashMap(); - map.put("http://schemas.openxmlformats.org/drawingml/2006/main", "a"); + map.put(NAMESPACE_A, "a"); map.put(STRelationshipId.type.getName().getNamespaceURI(), "r"); xmlOptions.setSaveSuggestedPrefixes(map); @@ -262,6 +266,19 @@ public final class XSSFDrawing extends POIXMLDocumentPart implements Drawing { shape.setRow(ca.getRow1()); return shape; } + + /** + * Returns all charts in this drawing. + */ + public List getCharts() { + List charts = new ArrayList(); + for(POIXMLDocumentPart part : getRelations()) { + if(part instanceof XSSFChart) { + charts.add((XSSFChart)part); + } + } + return charts; + } /** * Create and initialize a CTTwoCellAnchor that anchors a shape against top-left and bottom-right cells. 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 f11ebd655..cae8b5f80 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFRelation.java @@ -91,12 +91,12 @@ public final class XSSFRelation extends POIXMLRelation { "/xl/worksheets/sheet#.xml", XSSFSheet.class ); - public static final XSSFRelation CHARTSHEET = new XSSFRelation( + public static final XSSFRelation CHARTSHEET = new XSSFRelation( "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet", "/xl/chartsheets/sheet#.xml", XSSFChartSheet.class - ); + ); public static final XSSFRelation SHARED_STRINGS = new XSSFRelation( "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings", @@ -121,6 +121,12 @@ public final class XSSFRelation extends POIXMLRelation { "/xl/drawings/vmlDrawing#.vml", XSSFVMLDrawing.class ); + public static final XSSFRelation CHART = new XSSFRelation( + "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", + "/xl/charts/chart#.xml", + XSSFChart.class + ); public static final XSSFRelation CUSTOM_XML_MAPPINGS = new XSSFRelation( "application/xml", diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChart.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChart.java new file mode 100644 index 000000000..3ddd636a8 --- /dev/null +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChart.java @@ -0,0 +1,58 @@ +/* ==================================================================== + 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 junit.framework.TestCase; + +import org.apache.poi.xssf.XSSFTestDataSamples; + +public final class TestXSSFChart extends TestCase { + + public void testGetAccessors() { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithThreeCharts.xlsx"); + XSSFSheet s1 = wb.getSheetAt(0); + XSSFSheet s2 = wb.getSheetAt(1); + XSSFSheet s3 = wb.getSheetAt(2); + + assertEquals(0, s1.getRelations().size()); + assertEquals(1, s2.getRelations().size()); + assertEquals(1, s3.getRelations().size()); + } + + public void testGetCharts() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("WithThreeCharts.xlsx"); + + XSSFSheet s1 = wb.getSheetAt(0); + XSSFSheet s2 = wb.getSheetAt(1); + XSSFSheet s3 = wb.getSheetAt(2); + + assertEquals(0, s1.createDrawingPatriarch().getCharts().size()); + assertEquals(2, s2.createDrawingPatriarch().getCharts().size()); + assertEquals(1, s3.createDrawingPatriarch().getCharts().size()); + + // Check the titles + XSSFChart chart = s2.createDrawingPatriarch().getCharts().get(0); + assertEquals(null, chart.getTitle()); + + chart = s2.createDrawingPatriarch().getCharts().get(1); + assertEquals("Pie Chart Title Thingy", chart.getTitle().getString()); + + chart = s3.createDrawingPatriarch().getCharts().get(0); + assertEquals("Sheet 3 Chart with Title", chart.getTitle().getString()); + } +} diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChartSheet.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChartSheet.java index e31bbed41..a5de464e5 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChartSheet.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFChartSheet.java @@ -55,4 +55,17 @@ public final class TestXSSFChartSheet extends TestCase { assertEquals(0, sheet.getColumnBreaks().length); assertEquals(true, sheet.getRowSumsBelow()); } + + public void testGetCharts() throws Exception { + XSSFWorkbook wb = XSSFTestDataSamples.openSampleWorkbook("chart_sheet.xlsx"); + + XSSFSheet ns = wb.getSheetAt(0); + XSSFChartSheet cs = (XSSFChartSheet)wb.getSheetAt(2); + + assertEquals(0, ns.createDrawingPatriarch().getCharts().size()); + assertEquals(1, cs.createDrawingPatriarch().getCharts().size()); + + XSSFChart chart = cs.createDrawingPatriarch().getCharts().get(0); + assertEquals(null, chart.getTitle()); + } }