Невозможно изменить текст строки в файле .docx после добавления строки в таблицу - PullRequest
0 голосов
/ 08 ноября 2018

У меня проблема со следующим кодом:

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» даже не отображается в document.xml созданного документа WORD. Я не смог увидеть никаких подсказок отладки, потому что кажется, что оператор table.addRow(row); просто копирует указатель row на свой внутренний список строк. Кроме того, у меня не было проблем с изменением уже существующих строк. Итак, у вас есть идеи, почему это может произойти?

1 Ответ

0 голосов
/ 11 ноября 2018

Чтобы воспроизвести проблему, нужно иметь 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 s в CTTbl. Но это очень трудно определить из-за вида программирования классов org.openxmlformats.schemas. По крайней мере, я не смог этого сделать. Может быть, кто-то из профессиональных и энтузиастов-программистов здесь сможет?

Я использую тот же подход для вставки строк, имеющих тот же стиль, что и заданная исходная строка. Но после того, как я это сделал, я устанавливаю boolean weMustCommitTableRows = true;, а затем я делаю if (weMustCommitTableRows) commitTableRows(table); перед тем, как выписать документ. Тогда все изменения будут совершены.

...