Apache POI - при редактировании данных диаграммы в файле Word возвращается к данным, определенным в форме - PullRequest
0 голосов
/ 14 февраля 2019

Я разработал функцию Word, которая включает диаграмму.При редактировании данных диаграммы в файле Word он возвращается к данным, определенным в форме.

Вот шаги:

  • Я редактирую слово (docx) XML-данные и рабочую книгу.
  • Я открываю офис Microsoft - показанные данные нормальные.
  • Я щелкаю функцию редактирования данных диаграммы - она ​​возвращает исходные данные.

библиотека - ooxml-схемы-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 Ответ

0 голосов
/ 16 февраля 2019

Использование apache poi 4.0.1 изменение XDDFChart данные требуют параллельного обновления всех изменений в базовой книге данных диаграммы и самой диаграмме.Диаграмма содержит кэшированные данные, а рабочая книга содержит исходные данные.Но и то и другое возможно с использованием классов высокого уровня apache poi.Нет необходимости в доступе к базовым XML-компонентам.

Пример

Шаблон Word, в котором шаблонная таблица имеет 2 серии и 3 категории:

enter image description here

Код:

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_Simple.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
    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
    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();
 }

}

Результат:

enter image description here

...