poi生成的折线图和柱形图,用wps打开正常,用office打开显示损坏,报错“已删除的部件: 部件 /xl/drawings/drawing1.xml。 (绘图形状)”修复

poi生成的折线图和柱形图,用wps打开正常,用office打开显示损坏,报错“已删除的部件: 部件 /xl/drawings/drawing1.xml。 (绘图形状)”

poi生成的折线图和柱形图,用wps打开正常,用office打开显示损坏,报错“已删除的部件: 部件 /xl/drawings/drawing1.xml。 (绘图形状)”修复_第1张图片

测试版本:poi 4.1.2  、Office 2021

1、修复思路

既然wps能正常打开,那就使用wps打开另存为新的excel,发现新的excel在office中能正常打开,对比新旧两个excel的xml,找出不同的地方的xml,最后根据这个xml使用代码来修复。

2、生成一个简单的折线图

复杂的折线图、柱状图、饼图可以参考我的另一篇文章:https://blog.csdn.net/u014644574/article/details/105695787

package com.study.test;


import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.*;

import java.io.FileOutputStream;
import java.io.IOException;

/**
 * POI EXCEL 图表-折线图
 */
public class PoiLineChart {

    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            XSSFWorkbook wb = new XSSFWorkbook();
            XSSFSheet sheet = wb.createSheet("Sheet1");
            // 创建一个画布
            XSSFDrawing drawing = sheet.createDrawingPatriarch();
            // 画布起始位置(左上角):x=0,y=3。画布占列数:7-0=7列。画布占行数:26-3=23行
            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 3, 7, 26);
            // 创建一个chart对象
            XSSFChart chart = drawing.createChart(anchor);
            // X轴
            XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
            // Y轴
            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
            // X轴数据
            XDDFCategoryDataSource category = XDDFDataSourcesFactory.fromArray(new String[]{"俄罗斯", "加拿大", "美国", "中国", "巴西", "澳大利亚", "印度"});
            // Y轴数据
            XDDFNumericalDataSource values = XDDFDataSourcesFactory.fromArray(new Integer[]{17098242, 9984670, 9826675, 9596961, 8514877, 7741220, 3287263});
            // 创建折线图
            XDDFLineChartData line = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
            // 折线图,加载数据
            line.addSeries(category, values);
            // 绘制
            chart.plot(line);
            // 打印图表的xml
            System.out.println(chart.getCTChart());
            // 将输出写入excel文件
            String filename = "排行榜前七的国家.xlsx";
            fos = new FileOutputStream(filename);
            wb.write(fos);
            wb.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

生成的excel在wps中正常打开,Office 2021打开异常。

3、使用wps打开生成的excel自动修复

使用wps打开生成的excel自动修复后,另存为一个新的excel,新的excel在Office 2021中打开依然报错,但是图表已经能正常打开,这时可以在Office再另存为一个新的excel。

对比新旧两个excel的xml,找出缺失的xml,使用代码来修复缺失的xml。

package com.study.test;

import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart;

import java.io.FileInputStream;

/**
 * 打印EXCEL的XML
 */
public class PrintXml {

    public static void main(String[] args) throws Exception {
        String path = "D:\\poi\\排行榜前七的国家.xlsx";
        FileInputStream fis = new FileInputStream(path);
        XSSFWorkbook wb = new XSSFWorkbook(fis);
        XSSFSheet sheet = wb.getSheetAt(0);
        XSSFDrawing drawing = sheet.getDrawingPatriarch();
        CTChart ctChart = drawing.getCharts().get(0).getCTChart();
        System.out.println(ctChart);
        fis.close();
        wb.close();

    }
}

这里我对比poi生成excel缺失xml如下:


        
        
        
          
            
              
                
              
              
              
              
            
          
          
        
      

4、修复方式一:

使用xml直接转换后赋值。使用方式一,当xml非常大时非常方便,用来调试还是很方便的。

观察发现缺失标签里面有命名空间a,比如,所以需要在xml外包裹一层命名空间a。最后效果如下:


    
    
    
        
            
                
                    
                
                
                
                
            
        
        
    

修复代码如下:

    /**
     * 修复图表
     */
    private static void fixChart(XSSFChart chart) throws Exception {
        String xml = "\n" +
                "    \n" +
                "    \n" +
                "    \n" +
                "        \n" +
                "            \n" +
                "                \n" +
                "                    \n" +
                "                \n" +
                "                \n" +
                "                \n" +
                "                \n" +
                "            \n" +
                "        \n" +
                "        \n" +
                "    \n" +
                "";
        XmlObject xmlObject = XmlObject.Factory.parse(xml);
        CTPlotArea plotArea = chart.getCTChart().getPlotArea();
        List catAxList = plotArea.getCatAxList();
        for (int i = 0; i < catAxList.size(); i++) {
            catAxList.get(i).getNumFmt().setFormatCode("General");
            CTTextBody txPr = catAxList.get(i).addNewTxPr();
            txPr.set(xmlObject);
        }
        List valAxList = plotArea.getValAxList();
        for (int i = 0; i < valAxList.size(); i++) {
            valAxList.get(i).addNewNumFmt().setFormatCode("General");
            CTTextBody txPr = valAxList.get(i).addNewTxPr();
            txPr.set(xmlObject);
        }
    }

5、修复方式二(推荐):

根据方式一,不断缩减xml,最终精简只需几个xml标签就行了。

    /**
     * 修复图表
     */
    private static void fixChart(XSSFChart chart) {
        CTPlotArea plotArea = chart.getCTChart().getPlotArea();
        List catAxList = plotArea.getCatAxList();
        for (int i = 0; i < catAxList.size(); i++) {
            catAxList.get(i).getNumFmt().setFormatCode("General");
            CTTextBody txPr = catAxList.get(i).addNewTxPr();
            txPr.addNewBodyPr();
            txPr.addNewP().addNewPPr().addNewDefRPr();
        }
        List valAxList = plotArea.getValAxList();
        for (int i = 0; i < valAxList.size(); i++) {
            valAxList.get(i).addNewNumFmt().setFormatCode("General");
            CTTextBody txPr = valAxList.get(i).addNewTxPr();
            txPr.addNewBodyPr();
            txPr.addNewP().addNewPPr().addNewDefRPr();
        }
    }

6、完整示例

package com.study.test;


import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx;
import org.openxmlformats.schemas.drawingml.x2006.main.CTTextBody;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

/**
 * POI EXCEL 图表-折线图
 */
public class PoiLineChart2 {

    public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            XSSFWorkbook wb = new XSSFWorkbook();
            XSSFSheet sheet = wb.createSheet("Sheet1");
            // 创建一个画布
            XSSFDrawing drawing = sheet.createDrawingPatriarch();
            // 画布起始位置(左上角):x=0,y=3。画布占列数:7-0=7列。画布占行数:26-3=23行
            XSSFClientAnchor anchor = drawing.createAnchor(0, 0, 0, 0, 0, 3, 7, 26);
            // 创建一个chart对象
            XSSFChart chart = drawing.createChart(anchor);
            // X轴
            XDDFCategoryAxis bottomAxis = chart.createCategoryAxis(AxisPosition.BOTTOM);
            // Y轴
            XDDFValueAxis leftAxis = chart.createValueAxis(AxisPosition.LEFT);
            // X轴数据
            XDDFCategoryDataSource category = XDDFDataSourcesFactory.fromArray(new String[]{"俄罗斯", "加拿大", "美国", "中国", "巴西", "澳大利亚", "印度"});
            // Y轴数据
            XDDFNumericalDataSource values = XDDFDataSourcesFactory.fromArray(new Integer[]{17098242, 9984670, 9826675, 9596961, 8514877, 7741220, 3287263});
            // 创建折线图
            XDDFLineChartData line = (XDDFLineChartData) chart.createData(ChartTypes.LINE, bottomAxis, leftAxis);
            // 折线图,加载数据
            line.addSeries(category, values);
            // 绘制
            chart.plot(line);
            // 修复Office打开异常
            fixChart(chart);
            // 打印图表的xml
            System.out.println(chart.getCTChart());
            // 将输出写入excel文件
            String filename = "排行榜前七的国家.xlsx";
            fos = new FileOutputStream(filename);
            wb.write(fos);
            wb.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 修复图表
     */
    private static void fixChart(XSSFChart chart) {
        CTPlotArea plotArea = chart.getCTChart().getPlotArea();
        List catAxList = plotArea.getCatAxList();
        for (int i = 0; i < catAxList.size(); i++) {
            catAxList.get(i).getNumFmt().setFormatCode("General");
            CTTextBody txPr = catAxList.get(i).addNewTxPr();
            txPr.addNewBodyPr();
            txPr.addNewP().addNewPPr().addNewDefRPr();
        }
        List valAxList = plotArea.getValAxList();
        for (int i = 0; i < valAxList.size(); i++) {
            valAxList.get(i).addNewNumFmt().setFormatCode("General");
            CTTextBody txPr = valAxList.get(i).addNewTxPr();
            txPr.addNewBodyPr();
            txPr.addNewP().addNewPPr().addNewDefRPr();
        }
    }

}

测试版本:poi 4.1.2  、Office 2021

你可能感兴趣的:(POI,poi,poi折线图修复,poi柱状图修复,poi图表修复)