XWPFChart
is of type application/vnd.openxmlformats-officedocument.drawingml.chart+xml
while waterfall chart is of type application/vnd.ms-office.chartex+xml
. This is because the waterfall chart is an extended chart type which is not available in versions of Office Open XML
which apache poi
provides. I don't believe apache poi
will provide such extended charts in near future since it not even provides all native charts of type application/vnd.openxmlformats-officedocument.drawingml.chart+xml
until now.
So until now there only is the option to work on those chart types on very low level by changing the XML directly. I have shown this for a sunburst chart here How to change the graphical attributes of a point in an Excel sunburst chart through Apache POI and here How to set the text attributes of the individual data labels in an Excel Sunburst Chart through Apache POI?.
Following working draft provides a very basic class XWPFChartEx
which up to now only provides method getChartExXmlObject
which returns the plain XML
of the extended chart as a XmlObject
. This XML
could be programmatically changed using low level XML
methods. Because XWPFChartEx
extends POIXMLDocumentPart
, it's commit
method will write that changes into the new Word
document then while document.write(out)
. And it provides getWorkbookPart
which returns the PackagePart
of the XSSFWorkbook
containing the chart's data. This workbook content also would mus be changed, if present.
The file Waterfall_Chart.docx
must have at least one waterfall chart.
import java.io.IOException;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.FileInputStream;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFRelation;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ooxml.POIXMLDocumentPart;
import org.apache.poi.ooxml.POIXMLRelation;
import org.apache.poi.openxml4j.opc.PackagePart;
import org.apache.xmlbeans.XmlObject;
public class WordGetWaterfallChart {
static XWPFChartEx getFirstXWPFChartEx(XWPFDocument document) throws Exception {
XWPFChartEx xwpfChartEx = null;
for (POIXMLDocumentPart dpart : document.getRelations()) {
PackagePart ppart = dpart.getPackagePart();
if ("application/vnd.ms-office.chartex+xml".equals(ppart.getContentType())) {
xwpfChartEx = new XWPFChartEx(dpart);
String rId = document.getRelationId(dpart);
document.addRelation(
rId,
new XSSFChartExRelation(
"application/vnd.ms-office.chartex+xml",
"http://schemas.microsoft.com/office/2014/relationships/chartEx",
"/word/charts/chartEx#.xml"),
xwpfChartEx
);
return xwpfChartEx;
}
}
return xwpfChartEx;
}
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument(new FileInputStream("Waterfall_Chart.docx"));
XWPFChartEx waterfallChart = getFirstXWPFChartEx(document);
System.out.println(waterfallChart.getChartExXmlObject());
//TODO: change the XML
System.out.println(waterfallChart.getWorkbookPart());
if (waterfallChart.getWorkbookPart() != null) {
XSSFWorkbook workbook = new XSSFWorkbook(waterfallChart.getWorkbookPart().getInputStream());
for (Sheet sheet : workbook) {
for (Row row : sheet) {
for (Cell cell : row) {
System.out.println(cell);
//TODO: change the cell contents
}
}
}
OutputStream wbOut = waterfallChart.getWorkbookPart().getOutputStream();
workbook.write(wbOut);
wbOut.close();
workbook.close();
}
FileOutputStream out = new FileOutputStream("Waterfall_Chart_Changed.docx");
document.write(out);
out.close();
document.close();
}
private static class XWPFChartEx extends POIXMLDocumentPart {
private XmlObject chartExXmlObject;
private PackagePart workbookPart;
private XWPFChartEx(POIXMLDocumentPart dpart) throws Exception {
super(dpart.getPackagePart());
this.chartExXmlObject = XmlObject.Factory.parse(dpart.getPackagePart().getInputStream());
for (POIXMLDocumentPart.RelationPart rpart : dpart.getRelationParts()) {
if ("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
.equals(rpart.getDocumentPart().getPackagePart().getContentType())) {
this.addRelation(
rpart.getRelationship().getId(),
XWPFRelation.getInstance(rpart.getRelationship().getRelationshipType()),
rpart.getDocumentPart()
);
this.workbookPart = rpart.getDocumentPart().getPackagePart();
}
}
}
private XmlObject getChartExXmlObject() {
return this.chartExXmlObject;
}
private PackagePart getWorkbookPart() {
return this.workbookPart;
}
@Override
protected void commit() throws IOException {
PackagePart part = getPackagePart();
OutputStream out = part.getOutputStream();
chartExXmlObject.save(out);
out.close();
}
}
private static class XSSFChartExRelation extends POIXMLRelation {
private XSSFChartExRelation(String type, String rel, String defaultName) {
super(type, rel, defaultName);
}
}
}
XWPFChart
is of typeapplication/vnd.openxmlformats-officedocument.drawingml.chart+xml
while waterfall chart is of typeapplication/vnd.ms-office.chartex+xml
. This is because the waterfall chart is an extended chart type which is not available in versions ofOffice Open XML
whichapache poi
provides. I don't believeapache poi
will provide such extended charts in near future since it not even provides all native charts until now. – Axel RichterXML
directly. I have shown this for a sunburst chart here stackoverflow.com/questions/52324851/… and here stackoverflow.com/questions/54974045/…. – Axel Richtervnd.ms-office.chartex+xml
, because of your reason. The tricky part is I now that I don't have a template chart to start altering like the example you shared with the sunburst chart. What would be the best way to generate such a chart in Word either via template of from scatch? – Ivo Sturm