如何使用 apache poi 在 docx 中计算 =SUM(Above) 函数

How to compute =SUM(Above) function in docx using apache poi

我正在尝试使用 apache poi 处理 docx 格式文件,但我一直坚持使用 table 中的公式。例如看图片:

我曾尝试将文本设置为“=SUM(ABOVE)”,但这种方式不起作用。 我想我可能需要在此处设置自定义 xml 数据,但我不确定如何进行。我尝试了以下代码:

              XWPFTable table = document.createTable();
              //create first row
              XWPFTableRow tableRowOne = table.getRow(0);
              table.getRow(0).createCell();
              table.getRow(0).getCell(0).setText("10");
              table.getRow(0).createCell();
              table.getRow(0).getCell(1).setText("=SUM(ABOVE)");

遇到这样的需求我是这样处理的: 首先,使用 Word GUI 创建包含所需内容的最简单的 Word 文档。然后查看 Word 创建的内容,了解需要使用 apache poi.

创建的内容

具体来说: 在 Word 中创建尽可能简单的 table,其中有一个字段 {=SUM(ABOVE)}。将其保存为 *.docx。现在解压缩 *.docx(Office Open XML 文件,如 *.docx 只是 ZIP 存档)。查看该存档中的 /word/document.xml。在那里你会发现类似的东西:

<w:tc>
 <w:p>
  <w:fldSimple w:instr="=SUM(ABOVE)"/>
 ...
 </w:p>
</w:tc>

这是 XML 的 table 单元格,其段落中有一个 fldSimple 元素,其中 instr 属性包含公式。

现在我们知道了,我们需要 table 单元格 XWPFTableCell 和其中的 XWPFParagraph。然后我们需要在此段落中设置一个 fldSimple 元素,其中 instr 属性包含公式。

这就像

一样简单
paragraphInCell.getCTP().addNewFldSimple().setInstr("=SUM(ABOVE)");

但当然必须告诉 Word 打开文档时需要计算公式。最简单的解决方案是设置字段 "dirty"。这导致需要在 Word 中打开文档时更新字段。它还会导致关于需要更新的确认消息对话框。

使用 apache poi 4.1.0 的完整示例:

import java.io.FileOutputStream;

import org.apache.poi.xwpf.usermodel.*;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSimpleField;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff;

public class CreateWordTableSumAbove {

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

  XWPFDocument document= new XWPFDocument();

  XWPFParagraph paragraph = document.createParagraph();
  XWPFRun run=paragraph.createRun();  
  run.setText("The table:");

  //create the table
  XWPFTable table = document.createTable(4,3);
  table.setWidth("100%");
  for (int row = 0; row < 3; row++) {
   for (int col = 0; col < 3; col++) {
    if (col < 2) table.getRow(row).getCell(col).setText("row " + row + ", col " + col);
    else table.getRow(row).getCell(col).setText("" + ((row + 1) * 1234));
   }
  }

  //set Sum row
  table.getRow(3).getCell(0).setText("Sum:");

  //get paragraph from cell where the sum field shall be contained
  XWPFParagraph paragraphInCell = null;
  if (table.getRow(3).getCell(2).getParagraphs().size() == 0) paragraphInCell = table.getRow(3).getCell(2).addParagraph();
  else paragraphInCell = table.getRow(3).getCell(2).getParagraphs().get(0);

  //set sum field in
  CTSimpleField sumAbove = paragraphInCell.getCTP().addNewFldSimple();
  sumAbove.setInstr("=SUM(ABOVE)");
  //set sum field dirty, so it must be calculated while opening the document
  sumAbove.setDirty(STOnOff.TRUE);

  paragraph = document.createParagraph();

  FileOutputStream out = new FileOutputStream("create_table.docx"); 
  document.write(out);
  out.close();
  document.close();
 }
}

这一切只有在使用 Microsoft Word 打开文档时才能正常工作。 LibreOffice Writer 无法将此类公式字段存储为 Office Open XML (*.docx) 格式,也无法正确读取此类 Office Open XML 公式字段。