apache poi 或 docx4j 中的 SUM(ABOVE) 功能

SUM(ABOVE) functionality in apache poi or docx4j

我正在尝试在 docx 中实现 =SUM(ABOVE) 函数,该函数用于将上面的所有元素求和到该列。我能够使用 apache poi 实现这个:

    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);

当有人打开文档并计算它时,这是可以的。但是,如果我需要在不打开文档的情况下将其转换为 pdf,则此功能不会 运行。 Aspose 的函数名为:

Document.UpdateFields

它执行所需的功能,但这是付费应用程序。

我们能否使用 apche poi 或 docx4j 实现相同的功能

如果你不想设置脏字段,那么你需要自己计算总和。以下是计算 XWPFTable 的特殊列的 table 单元格值之和的方法的工作草案:

 Double calculateSum(XWPFTable table, int col) {
  Double result = null;
  for (XWPFTableRow row : table.getRows()) {
   if (row.getTableCells().size() > col) {
    XWPFTableCell cell = row.getCell(col);
    String cellContent = cell.getText();
    try {
     Number cellValue = java.text.NumberFormat.getInstance().parse(cellContent);
     if (result == null) result = 0d;
     result += cellValue.doubleValue();
    } catch(Exception ex) {
     //could not parse text to number
     //ex.printStackTrace();
    }
   }
  }
  return result;
 }

如果您有总和,则 CTSimpleField 需要获取将总和设置为文本值的文本 运行。然后这与 Word 为字段设置缓存值相同。

完整示例:

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 {

 static Double calculateSum(XWPFTable table, int col) {
  Double result = null;
  for (XWPFTableRow row : table.getRows()) {
   if (row.getTableCells().size() > col) {
    XWPFTableCell cell = row.getCell(col);
    String cellContent = cell.getText();
    try {
     Number cellValue = java.text.NumberFormat.getInstance().parse(cellContent);
     if (result == null) result = 0d;
     result += cellValue.doubleValue();
    } catch(Exception ex) {
     //could not parse text to number
     //ex.printStackTrace();
    }
   }
  }
  return result;
 }

 static void setText(XWPFTableCell cell, String text) {
  XWPFParagraph par = null;
  if (cell.getParagraphs().size() == 0) par = cell.addParagraph();
  else par = cell.getParagraphs().get(0);
  par.createRun().setText(text);
 }

 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) {
     setText(table.getRow(row).getCell(col), "row " + row + ", col " + col);
    } else {
     setText(table.getRow(row).getCell(col), "" + ((row + 1) * 1234));
    }
   }
  }

  //set Sum row
  setText(table.getRow(3).getCell(0), "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)");
  Double sum = calculateSum(table, 2);
System.out.println(sum);
  if (sum != null) {
   //if there is a sum, set that sum to be the cached result of the field
   sumAbove.addNewR().addNewT().setStringValue(new java.text.DecimalFormat("#.#").format(sum));
  } else {
   //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();
 }
}

如果 Word 到 PDF 转换器不读取该值,则它是不完整的。当然,您可以停止使用该字段并将计算出的总和直接放入 table 单元格中。但是由于不再有字段,因此无法使用 Word 更新总和。