java - 将行添加到表后,无法更改 .docx 文件中的行文本

标签 java ms-word apache-poi xmlbeans

我的以下代码有问题:

XWPFTable table = <get table somehow>;
CTRow firstRow = table.getRow(0).getCtRow();

for (int i = 0; i < data.getRowCount(); i++) {
    CTRow ctRow = (CTRow) firstRow.copy();
    XWPFTableRow row = new XWPFTableRow(ctRow, table);
    XWPFRun[] cellRuns = row.getTableCells()
            .stream()
            .map(c -> c.getParagraphs().get(0))
            .map(p -> p.getRuns().isEmpty() ? p.createRun() : p.getRuns().get(0))
            .toArray(XWPFRun[]::new);
    for (int j = 0; j < cellRuns.length; j++) {
        cellRuns[j].setText(data.getValueAt(i, j).toString(), 0);
    }
    table.addRow(row);
}


table.getRow(1).getTableCells()
.get(0).getParagraphs()
.get(0).getRuns()
.get(0).setText("FooBar", 0); //change text in some added row

此代码多次复制表的第一行,然后复制 data 中的值。除了最后一个运算符之外,工作得很好(文本样式除外),该运算符应该更改某些添加的表行中的文本。此外,“FooBar”字符串甚至不会出现在创建的 WORD 文档的 document.xml 中。我没有从调试中看到任何线索,因为 table.addRow(row); 运算符似乎只是将 row 指针复制到其内部行列表。另外,我在更改现有行时没有遇到问题。那么您知道为什么会发生这种情况吗?

最佳答案

要重现问题,请使用 source.docx第一个表至少有两行。

然后运行以下代码:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRow;

public class WordInsertTableRow {

 static XWPFTableRow insertNewTableRow(XWPFTableRow sourceTableRow, int pos) throws Exception {
  XWPFTable table = sourceTableRow.getTable();
  CTRow newCTRrow = CTRow.Factory.parse(sourceTableRow.getCtRow().newInputStream());
  XWPFTableRow tableRow = new XWPFTableRow(newCTRrow, table);
  table.addRow(tableRow, pos);
  return tableRow;
 }

 static void commitTableRows(XWPFTable table) {
  int rowNr = 0;
  for (XWPFTableRow tableRow : table.getRows()) {
   table.getCTTbl().setTrArray(rowNr++, tableRow.getCtRow());
  }
 }

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

  XWPFDocument doc = new XWPFDocument(new FileInputStream("source.docx"));
  boolean weMustCommitTableRows = false;

  XWPFTable table = doc.getTableArray(0);

  // insert new row, which is a copy of row 2, as new row 3:
  XWPFTableRow sourceTableRow = table.getRow(1);
  XWPFTableRow newRow3 = insertNewTableRow(sourceTableRow, 2);

  // now changing something in that new row:
  int i = 1;
  for (XWPFTableCell cell : newRow3.getTableCells()) {
   for (XWPFParagraph paragraph : cell.getParagraphs()) {
    for (XWPFRun run : paragraph.getRuns()) {
     run.setText("New row 3 run " + i++, 0);
    }
   }
  }
System.out.println(newRow3.getCtRow()); // was changed
System.out.println(table.getRow(2).getCtRow()); // even this is changed
System.out.println(table.getCTTbl().getTrArray(2)); // but this was not changed, why not?
  weMustCommitTableRows = true;

  if (weMustCommitTableRows) commitTableRows(table); // now it is changed

  FileOutputStream out = new FileOutputStream("result.docx");
  doc.write(out);
  out.close();
  doc.close();

 }
}

此代码创建第二行的副本并将其作为第三行插入表中。然后它确实改变了新的第三行中的某些内容。

问题是,这些变化确实出现在低级别 CTRow行本身的但不出现在低级别 CTTbl表的。对我来说,这不符合逻辑,我无法理解其中的原因。看起来好像是新的CTRow元素不是 CTTbl 的一部分根本不。但它们是使用ctTbl.setTrArray添加到其中的。在 XWPFTable.addRow 。所以我怀疑 setTrArray 有问题在org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl 。似乎正在更新XML正确,但丢失 CTRow 数组(或列表)中的对象关系位于CTTbl 。但这很难确定,因为 org.openxmlformats.schemas 的编程类型。类。至少我没能这么做。也许这里的另一位专业和热情的程序员可能能够?

我使用相同的方法插入与给定源行具有相同样式的行。但完成此操作后,我设置 boolean weMustCommitTableRows = true;然后我正在做if (weMustCommitTableRows) commitTableRows(table);在写出文档之前。然后所有更改都将被提交。

关于java - 将行添加到表后,无法更改 .docx 文件中的行文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53211749/

相关文章:

java - Java 的最佳设计解析具有不同 header 和模型对象的多个 CSV 文件

java - 如何在Java 8中同时按desc中的值和键按自然顺序对Map进行排序

c# - 使用 OpenXML 将图片插入到 Word 文档的标题中

Java POI 堆内存不足 - 批处理

java - 如何使用 apache poi 3.5 和 java 以编程方式读取和更新动态 Excel 文件?

java - 在Java程序中打开Windows虚拟键盘

java - JavaLDAExample不起作用

vba - 减少从 Excel 粘贴到 Word 的图表的文件大小

vba - "Type"中的 Const 变量 - 语句 vba

JAVA - docx中的字体路径而不是字体名称