Apache POI - When editing chart data in a Word file, it returns to the data defined in the form

旧街凉风 提交于 2019-12-02 18:01:46

问题


I have developed a Word function that includes a Chart. When editing chart data in a Word file, it returns to the data defined in the form.

Here are the steps:

  • I edit word(docx) xml data and workbook.
  • I open microsoft office - the data shown is normal.
  • I click Chart data edit function - it returns the original data.

library - ooxml-schemas-1.3, poi-4.0.0-SNAPSHOT

public static void main(String[] args) throws Exception {
    // TODO Auto-generated method stub

    String inFilePath = "../file/temp/TEMP_Chart_Simple.docx";
    String outFilePath = "../file/out/NEW_Chart_" + System.currentTimeMillis() + ".docx";

    Map<String, Map<String, String>> CHART_MAP_DATA = new LinkedHashMap<>();
    Map<String, String> inData = new LinkedHashMap<>();
    inData.put("1", "8.3");
    inData.put("2", "7.3");

    CHART_MAP_DATA.put("temp", inData);

    Path path = Paths.get(inFilePath);
    byte[] byteData = Files.readAllBytes(path);

    // read as XWPFDocument from byte[]
    XWPFDocument document = new XWPFDocument(new ByteArrayInputStream(byteData));

    XWPFChart xChart = null;
    CTChart ctChart = null;
    XSSFWorkbook wb = null;

    for (POIXMLDocumentPart part : document.getRelations()) {
        if (part instanceof XWPFChart) {
            xChart = (XWPFChart) part;
            wb = xChart.getWorkbook();
            ctChart = xChart.getCTChart();

            if(getTitle(ctChart).equals("FIELD_CHART")) {
                break;
            }
        }
    }

    CTPlotArea plotArea = ctChart.getPlotArea();

    List<CTBarChart> arBarChart = plotArea.getBarChartList();
    List<CTBarSer> arBarSer = arBarChart.get(0).getSerList();

    if(CHART_MAP_DATA != null && !CHART_MAP_DATA.isEmpty()) {
        Set<String> keys = CHART_MAP_DATA.keySet();
        Iterator<String> itKeys = keys.iterator();

        while(itKeys.hasNext()) {
            String inKey = itKeys.next();
            Map<String, String> barData = CHART_MAP_DATA.get(inKey);
            setBarChartData(ctChart, serCnt, inKey, barData);
        }
    }

    XSSFSheet sheet = wb.getSheetAt(0);
    sheet.getRow(1).getCell(1).setCellValue(8.3);
    sheet.getRow(2).getCell(1).setCellValue(7.3);

    FileOutputStream fos = new FileOutputStream(new File(outFilePath));
    document.write(fos);

    fos.close();
    document.close();
}

public static void setBarChartData(CTChart ctChart, int serIdx, String series, Map<String, String> data) {
    CTPlotArea plotArea = ctChart.getPlotArea();

    List<CTBarChart> arBarChart = plotArea.getBarChartList();

    if(arBarChart.size() > 0) {
        List<CTBarSer> arBarSer = arBarChart.get(0).getSerList();
        CTBarSer barSer = arBarSer.get(serIdx);    
        CTSerTx serTx = barSer.getTx();
        CTStrRef strRef = serTx.getStrRef();
        CTStrData strData = strRef.getStrCache();
        List<CTStrVal> arStrVal = strData.getPtList();
        for(int b=0; b<arStrVal.size(); b++) {
            arStrVal.get(b).setV(series);
        }

        CTAxDataSource dataSource = barSer.getCat();
        CTStrRef dStrRef = dataSource.getStrRef();

        boolean isCatDataTypeStr = true;
        List<CTStrVal> arDStrVal = null;
        List<CTNumVal> arDNumVal = null;
        CTStrData dStrData = null;
        CTNumData dNumData = null;

        if(dStrRef != null) {
            dStrData = dStrRef.getStrCache();
            arDStrVal = dStrData.getPtList();

            dStrData.getPtCount().setVal(data.size());
            if(arDStrVal.size() > data.size()) {
                for(int i=arDStrVal.size(); i>data.size(); i--) {
                    dStrData.removePt(i-1);
                }
            }

            isCatDataTypeStr = true;
        } else {
            CTNumRef dNumRef = dataSource.getNumRef();
            dNumData = dNumRef.getNumCache();
            arDNumVal = dNumData.getPtList();

            dNumData.getPtCount().setVal(data.size());
            if(arDNumVal.size() > data.size()) {
                for(int i=arDNumVal.size(); i>data.size(); i--) {
                    dNumData.removePt(i-1);
                }
            }

            isCatDataTypeStr = false;
        }

        CTNumDataSource numDataSource = barSer.getVal();
        CTNumRef numRef = numDataSource.getNumRef();
        CTNumData numData = numRef.getNumCache();
        List<CTNumVal> arNumVal = numData.getPtList();

        numData.getPtCount().setVal(data.size());
        if(arNumVal.size() > data.size()) {
            for(int i=arNumVal.size(); i>data.size(); i--) {
                numData.removePt(i-1);
            }
        }

        Set<String> keys = data.keySet();
        Iterator<String> itKeys = keys.iterator();

        int valSize = 0;
        if(isCatDataTypeStr) {
            valSize = arDStrVal.size();
        } else {
            valSize = arDNumVal.size();
        }

        int idx = 0;
        while(itKeys.hasNext()) {
            String stKey = itKeys.next();

            if(valSize > idx) {
                if(isCatDataTypeStr) {
                    arDStrVal.get(idx).setV(stKey);
                } else {
                    arDNumVal.get(idx).setV(stKey);
                }
            } else {
                if(isCatDataTypeStr) {
                    CTStrVal val = dStrData.addNewPt();
                    val.setIdx(idx);
                    val.setV(stKey);
                } else {
                    CTNumVal val = dNumData.addNewPt();
                    val.setIdx(idx);
                    val.setV(stKey);
                }
            }

            if(arNumVal.size() > idx) {
                arNumVal.get(idx).setV(data.get(stKey));
            } else {
                CTNumVal val = numData.addNewPt();
                val.setIdx(idx);
                val.setV(data.get(stKey));
            }

            idx++;
        }
    }
}

public static String getTitle(CTChart chart) {
    CTTitle title = chart.getTitle();
    if (title != null) {
        CTTx tx = title.getTx();
        CTTextBody tb = tx.getRich();

        return tb.getPArray(0).getRArray(0).getT();
    }

    return "";
}

回答1:


Using apache poi 4.0.1 changing XDDFChart data needs parallel updating all changes in underlying chart data workbook and the chart itself. The chart holds the cached data while the workbook holds the source data. But both is possible using the high level apache poiclasses. No access to underlying XML beans needed.

Example

Word template which has template chart having 2 series and 3 categories:

Code:

import java.io.FileInputStream;
import java.io.FileOutputStream;

import org.apache.poi.xwpf.usermodel.*;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xssf.usermodel.*;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.ss.util.CellRangeAddress;

public class WordChangeChartData {

 public static void main(String[] args) throws Exception {

  String filePath = "TEMP_Chart_SimpleBar.docx"; // has template chart having 2 series, 3 categories
  String filePathNew = "New_Chart_Simple.docx";

  Object[][] data = new Object[][] { // 2 series, 3 categories
   {"", "male", "female"}, // series titles
   {"health", 123d, 234d}, // category 1
   {"amount", 345d, 123d}, // category 2
   {"size", 180d, 160d} // category 3
  };

  XWPFDocument document = new XWPFDocument(new FileInputStream(filePath));

  XWPFChart chart = document.getCharts().get(0);
  XSSFWorkbook chartDataWorkbook = chart.getWorkbook();
  String sheetName = chartDataWorkbook.getSheetName(0);
  XSSFSheet chartDataSheet = chartDataWorkbook.getSheet(sheetName);

  if (chart.getChartSeries().size() == 1) { // only one chart data
   XDDFChartData chartData = chart.getChartSeries().get(0);
   if (chartData.getSeries().size() == 2) { // exact two series

    int rMin = 1;
    int rMax = 3;

    // set new category data (both series)
    XDDFCategoryDataSource category = null;
    int c = 0;
    for (int r = rMin; r < rMax+1; r++) {
     chartDataSheet.getRow(r).getCell(c).setCellValue((String)data[r][c]); // in sheet
    }
    category = XDDFDataSourcesFactory.fromStringCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); // in chart

    // series 1
    XDDFChartData.Series series1 = chartData.getSeries().get(0);
    c = 1;
    // set new title
    String series1Title = (String)data[0][c];
    chartDataSheet.getRow(0).getCell(c).setCellValue(series1Title); // in sheet
    if (chartDataSheet.getTables().size() > 0) {
     if (chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().size() > c)
      chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().get(c).setName(series1Title);
    }
    series1.setTitle(series1Title, new CellReference(sheetName, 0, c, true, true)); // in chart

    // set new values
    XDDFNumericalDataSource<Double> values = null;
    for (int r = rMin; r < rMax+1; r++) {
     chartDataSheet.getRow(r).getCell(c).setCellValue((Double)data[r][c]); // in sheet
    }
    values = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); 
    series1.replaceData(category, values);
    series1.plot(); //in chart

    // series 2
    XDDFChartData.Series series2 = chartData.getSeries().get(1);
    c = 2;
    // set new title
    String series2Title = (String)data[0][c];
    chartDataSheet.getRow(0).getCell(c).setCellValue(series2Title); // in sheet
    if (chartDataSheet.getTables().size() > 0) {
     if (chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().size() > c)
      chartDataSheet.getTables().get(0).getCTTable().getTableColumns().getTableColumnList().get(c).setName(series2Title);
    }
    series2.setTitle(series2Title, new CellReference(sheetName, 0, c, true, true)); // in chart

    // set new values
    for (int r = rMin; r < rMax+1; r++) {
     chartDataSheet.getRow(r).getCell(c).setCellValue((Double)data[r][c]); // in sheet
    }
    values = XDDFDataSourcesFactory.fromNumericCellRange(chartDataSheet, new CellRangeAddress(rMin,rMax,c,c)); 
    series2.replaceData(category, values);
    series2.plot(); // in chart

   }
  }

  FileOutputStream out = new FileOutputStream(filePathNew); 
  document.write(out);
  out.close();
  document.close();
 }

}

Result:



来源:https://stackoverflow.com/questions/54681481/apache-poi-when-editing-chart-data-in-a-word-file-it-returns-to-the-data-defi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!