Java 使用ApachePOI从具有固定位置的模板复制表

Java 使用ApachePOI从具有固定位置的模板复制表,java,apache-poi,docx,xwpf,Java,Apache Poi,Docx,Xwpf,我在docx模板中有一个表。 根据对象的数量,我必须复制表的次数与复制对象的次数相同。重复表必须位于模板中的表之后。 我在模板中有几个表的行为应该是这样的 XmlCursor取代模板中的第一个表,并将下一个表放在那里。我想在我自己添加的上一个表之后插入下一个表,但是xmlcursor不返回我添加的表项,而是返回“STARTDOC” 不清楚使用cursor.toParent()的目的是什么。我也无法重现只有您的小代码片段的问题。但是有一个完整的工作示例可能会对您有所帮助 假设我们有以下模板: 然

我在docx模板中有一个表。 根据对象的数量,我必须复制表的次数与复制对象的次数相同。重复表必须位于模板中的表之后。 我在模板中有几个表的行为应该是这样的

XmlCursor取代模板中的第一个表,并将下一个表放在那里。我想在我自己添加的上一个表之后插入下一个表,但是xmlcursor不返回我添加的表项,而是返回“STARTDOC”


不清楚使用
cursor.toParent()的目的是什么。我也无法重现只有您的小代码片段的问题。但是有一个完整的工作示例可能会对您有所帮助

假设我们有以下模板:

然后是以下代码:

import java.io.FileOutputStream;
import java.io.FileInputStream;

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

import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;

public class WordCopyTableAfterTable {

 static XmlCursor setCursorToNextStartToken(XmlObject object) {
  XmlCursor cursor = object.newCursor();
  cursor.toEndToken(); //Now we are at end of the XmlObject.
  //There always must be a next start token.
  while(cursor.hasNextToken() && cursor.toNextToken() != org.apache.xmlbeans.XmlCursor.TokenType.START);
  //Now we are at the next start token and can insert new things here.
  return cursor;
 }

 static void removeCellValues(XWPFTableCell cell) {
  for (XWPFParagraph paragraph : cell.getParagraphs()) {
   for (int i = paragraph.getRuns().size()-1; i >= 0; i--) {
    paragraph.removeRun(i);
   }  
  }
 }

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

  //The data. Each row a new table.
  String[][] data= new String[][] {
   new String[] {"John Doe", "5/23/2019", "1234.56"},
   new String[] {"Jane Doe", "12/2/2019", "34.56"},
   new String[] {"Marie Template", "9/20/2019", "4.56"},
   new String[] {"Hans Template", "10/2/2019", "4567.89"}
  };

  String value;
  XWPFDocument document = new XWPFDocument(new FileInputStream("WordTemplate.docx"));
  XWPFTable tableTemplate;
  CTTbl cTTblTemplate;
  XWPFTable tableCopy;
  XWPFTable table;
  XWPFTableRow row;
  XWPFTableCell cell;
  XmlCursor cursor;
  XWPFParagraph paragraph;
  XWPFRun run;

  //get first table (the template)
  tableTemplate = document.getTableArray(0);
  cTTblTemplate = tableTemplate.getCTTbl();
  cursor = setCursorToNextStartToken(cTTblTemplate);

  //fill in first data in first table (the template)
  for (int c = 0; c < data[0].length; c++) {
   value = data[0][c];
   row = tableTemplate.getRow(1);
   cell = row.getCell(c);
   removeCellValues(cell);
   cell.setText(value);
  }

  paragraph = document.insertNewParagraph(cursor); //insert new empty paragraph
  cursor = setCursorToNextStartToken(paragraph.getCTP());

  //fill in next data, each data row in one table
  for (int t = 1; t < data.length; t++) {
   table = document.insertNewTbl(cursor); //insert new empty table at position t
   cursor = setCursorToNextStartToken(table.getCTTbl());

   tableCopy = new XWPFTable((CTTbl)cTTblTemplate.copy(), document); //copy the template table

   //fill in data in tableCopy
   for (int c = 0; c < data[t].length; c++) {
    value = data[t][c];
    row = tableCopy.getRow(1);
    cell = row.getCell(c);
    removeCellValues(cell);
    cell.setText(value);
   }
   document.setTable(t, tableCopy); //set tableCopy at position t instead of table

   paragraph = document.insertNewParagraph(cursor); //insert new empty paragraph
   cursor = setCursorToNextStartToken(paragraph.getCTP());
  }

  paragraph = document.insertNewParagraph(cursor);
  run = paragraph.createRun(); 
  run.setText("Inserted new text below last table.");
  cursor = setCursorToNextStartToken(paragraph.getCTP());

  FileOutputStream out = new FileOutputStream("WordResult.docx");
  document.write(out);
  out.close();
  document.close();
 }
}
import java.io.FileOutputStream;
导入java.io.FileInputStream;
导入org.apache.poi.xwpf.usermodel.*;
导入org.apache.xmlbeans.XmlObject;
导入org.apache.xmlbeans.XmlCursor;
导入org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;
公共类WordCopyTableAfterTable{
静态XmlCursor setCursorToNextStartToken(XmlObject对象){
XmlCursor=object.newCursor();
cursor.toEndToken();//现在我们到了XmlObject的末尾。
//始终必须有下一个开始令牌。
while(cursor.hasNextToken()&&cursor.toNextToken()!=org.apache.xmlbeans.XmlCursor.TokenType.START);
//现在我们在下一个开始令牌,可以在这里插入新的东西。
返回光标;
}
静态空隙清除单元值(XWPFTableCell){
对于(XWPFParagraph段落:cell.getParagraph()){
对于(int i=段落.getRuns().size()-1;i>=0;i--){
第1(i)段;
}  
}
}
公共静态void main(字符串[]args)引发异常{
//数据。每一行都是一个新表。
字符串[][]数据=新字符串[][]{
新字符串[]{“John Doe”、“5/23/2019”、“1234.56”},
新字符串[]{“Jane Doe”,“12/2/2019”,“34.56”},
新字符串[]{“玛丽模板”、“2019年9月20日”、“4.56”},
新字符串[]{“Hans模板”、“2019年2月10日”、“4567.89”}
};
字符串值;
XWPFDocument document=newxwpfdocument(newfileinputstream(“WordTemplate.docx”);
XWPFTable表格模板;
CTTbl cTTblTemplate;
XWPFTable表格副本;
XWPFTable表;
XWPFTableRow行;
XWPFTableCell细胞;
xml光标;
XWPFParagraph段;
XWPFRun;
//获取第一个表(模板)
tableTemplate=document.getTableArray(0);
cTTblTemplate=tableTemplate.getCTTbl();
cursor=setCursorToNextStartToken(cTTblTemplate);
//填写第一个表格中的第一个数据(模板)
对于(int c=0;c
结果如下:

这就是你想要达到的目标吗

请注意我是如何插入附加表的

使用
table=document.insertNewTbl(光标)在位置
t
插入一个新的空表。此表被放置到文档体中。因此,必须使用此表来调整光标

然后
tableCopy=newxwpftable((CTTbl)cTTblTemplate.copy(),document)复制模板表。然后,此副本将填充数据。然后使用
document.setTable(t,tableCopy)在
t
位置将其设置到文档中

不幸的是,
apachepoi
在这里是不完整的
XWPFDocument.setable
仅设置内部
ArrayList
s,而不设置底层
XML
XWPFDocument.insertNewTbl
设置基础
XML
,但仅使用空表。因此,我们必须以一种丑陋而复杂的方式来做

import java.io.FileOutputStream;
import java.io.FileInputStream;

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

import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTbl;

public class WordCopyTableAfterTable {

 static XmlCursor setCursorToNextStartToken(XmlObject object) {
  XmlCursor cursor = object.newCursor();
  cursor.toEndToken(); //Now we are at end of the XmlObject.
  //There always must be a next start token.
  while(cursor.hasNextToken() && cursor.toNextToken() != org.apache.xmlbeans.XmlCursor.TokenType.START);
  //Now we are at the next start token and can insert new things here.
  return cursor;
 }

 static void removeCellValues(XWPFTableCell cell) {
  for (XWPFParagraph paragraph : cell.getParagraphs()) {
   for (int i = paragraph.getRuns().size()-1; i >= 0; i--) {
    paragraph.removeRun(i);
   }  
  }
 }

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

  //The data. Each row a new table.
  String[][] data= new String[][] {
   new String[] {"John Doe", "5/23/2019", "1234.56"},
   new String[] {"Jane Doe", "12/2/2019", "34.56"},
   new String[] {"Marie Template", "9/20/2019", "4.56"},
   new String[] {"Hans Template", "10/2/2019", "4567.89"}
  };

  String value;
  XWPFDocument document = new XWPFDocument(new FileInputStream("WordTemplate.docx"));
  XWPFTable tableTemplate;
  CTTbl cTTblTemplate;
  XWPFTable tableCopy;
  XWPFTable table;
  XWPFTableRow row;
  XWPFTableCell cell;
  XmlCursor cursor;
  XWPFParagraph paragraph;
  XWPFRun run;

  //get first table (the template)
  tableTemplate = document.getTableArray(0);
  cTTblTemplate = tableTemplate.getCTTbl();
  cursor = setCursorToNextStartToken(cTTblTemplate);

  //fill in first data in first table (the template)
  for (int c = 0; c < data[0].length; c++) {
   value = data[0][c];
   row = tableTemplate.getRow(1);
   cell = row.getCell(c);
   removeCellValues(cell);
   cell.setText(value);
  }

  paragraph = document.insertNewParagraph(cursor); //insert new empty paragraph
  cursor = setCursorToNextStartToken(paragraph.getCTP());

  //fill in next data, each data row in one table
  for (int t = 1; t < data.length; t++) {
   table = document.insertNewTbl(cursor); //insert new empty table at position t
   cursor = setCursorToNextStartToken(table.getCTTbl());

   tableCopy = new XWPFTable((CTTbl)cTTblTemplate.copy(), document); //copy the template table

   //fill in data in tableCopy
   for (int c = 0; c < data[t].length; c++) {
    value = data[t][c];
    row = tableCopy.getRow(1);
    cell = row.getCell(c);
    removeCellValues(cell);
    cell.setText(value);
   }
   document.setTable(t, tableCopy); //set tableCopy at position t instead of table

   paragraph = document.insertNewParagraph(cursor); //insert new empty paragraph
   cursor = setCursorToNextStartToken(paragraph.getCTP());
  }

  paragraph = document.insertNewParagraph(cursor);
  run = paragraph.createRun(); 
  run.setText("Inserted new text below last table.");
  cursor = setCursorToNextStartToken(paragraph.getCTP());

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