使用Apache POI生成含BAR图表的DOCX无法在Word 365打开
问题描述
- 使用Apache POI生成DOCX文件已有数月,此前所有版本Microsoft Word均可正常打开;近期发现包含
ChartTypes.BAR类型图表的文件无法在Word 365中打开,仅提示文件无法打开 - 已完成OOXML验证,未发现任何验证错误
- 可通过Apache POI官方示例或以下JUnit测试代码复现问题
复现代码
@Test public void barChartTest() throws FileNotFoundException, IOException { String chartTitle = "10 languages with most speakers as first language"; String[] series = { "countries", "speakers", "language" }; // Category Axis Data List<String> listLanguages = new ArrayList<>(3); // Values List<Double> listCountries = new ArrayList<>(3); List<Double> listSpeakers = new ArrayList<>(3); listCountries.add(2d); listCountries.add(4d); listCountries.add(6d); listSpeakers.add(10d); listSpeakers.add(12d); listSpeakers.add(14d); listLanguages.add("A"); listLanguages.add("B"); listLanguages.add("C"); String[] categories = listLanguages.toArray(new String[0]); Double[] values1 = listCountries.toArray(new Double[0]); Double[] values2 = listSpeakers.toArray(new Double[0]); int columnLanguages = 0; int columnCountries = 1; int columnSpeakers = 2; try (XWPFDocument doc = new XWPFDocument()) { XWPFChart chart = doc.createChart(6000000, 5000000); XDDFChartAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM); bottomAxis.setTitle(series[2]); XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT); leftAxis.setTitle(series[0] + "," + series[1]); leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); leftAxis.setMajorTickMark(AxisTickMark.OUT); leftAxis.setCrossBetween(AxisCrossBetween.BETWEEN); final int numOfPoints = categories.length; final String categoryDataRange = chart .formatRange(new CellRangeAddress(1, numOfPoints, columnLanguages, columnLanguages)); final String valuesDataRange = chart .formatRange(new CellRangeAddress(1, numOfPoints, columnCountries, columnCountries)); final String valuesDataRange2 = chart .formatRange(new CellRangeAddress(1, numOfPoints, columnSpeakers, columnSpeakers)); final XDDFDataSource<?> categoriesData = XDDFDataSourcesFactory.fromArray(categories, categoryDataRange, columnLanguages); final XDDFNumericalDataSource<? extends Number> valuesData = XDDFDataSourcesFactory.fromArray(values1, valuesDataRange, columnCountries); valuesData.setFormatCode("General"); // values1[6] = 16.0; // if you ever want to change the underlying data, it has to be done before // // building the data source final XDDFNumericalDataSource<? extends Number> valuesData2 = XDDFDataSourcesFactory.fromArray(values2, valuesDataRange2, columnSpeakers); valuesData2.setFormatCode("General"); XDDFBarChartData bar = (XDDFBarChartData) chart.createData(ChartTypes.BAR, bottomAxis, leftAxis); bar.setBarGrouping(BarGrouping.CLUSTERED); XDDFBarChartData.Series series1 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData); series1.setTitle(series[0], chart.setSheetTitle(series[0], columnCountries)); XDDFBarChartData.Series series2 = (XDDFBarChartData.Series) bar.addSeries(categoriesData, valuesData2); series2.setTitle(series[1], chart.setSheetTitle(series[1], columnSpeakers)); bar.setVaryColors(true); bar.setBarDirection(BarDirection.COL); chart.plot(bar); XDDFChartLegend legend = chart.getOrAddLegend(); legend.setPosition(LegendPosition.LEFT); legend.setOverlay(false); chart.setTitleText(chartTitle); chart.setTitleOverlay(false); chart.setAutoTitleDeleted(false); try (FileOutputStream out = new FileOutputStream("output/chart.docx")) { doc.write(out); } } catch (Exception e) { e.printStackTrace(); } }
解决方案建议
- 升级Apache POI版本:Word 365对OOXML格式的兼容性要求更严格,建议升级到最新稳定版(如5.2.5及以上),新版本通常会修复针对Office 365的兼容性问题
- 调整图表方向设置:尝试移除
bar.setBarDirection(BarDirection.COL)代码,或改为BarDirection.BAR,部分场景下Word 365对垂直柱状图的XML结构解析存在异常 - 禁用自动颜色变化:注释掉
bar.setVaryColors(true),部分版本中该设置生成的XML属性可能触发Word 365的解析错误 - 手动修正OOXML结构:解压DOCX文件,找到
word/charts/chart1.xml,检查<barDir>标签值,确保其符合Word 365预期(如bar),重新打包后测试 - 临时替代图表类型:若上述方法无效,可暂时使用
ChartTypes.LINE生成图表,验证是否为柱状图特有的兼容性问题,同时等待Apache POI官方修复
内容的提问来源于stack exchange,提问作者Mark Us
相关产品推荐
相关产品推荐

