Reputation: 23
I want to insert a varying amount of text into a word document. E.g.
Heading 1
Subheading 1
Table 1
Subheading 2
Table 2
I used a cursor after finding the right spot in the word document, but don't know how I can create multiple stuff at that position. I got it to work with a single paragraph with text. I also tried using a for-loop after the while-statement but the createRun method referenced a paragraph that is null and therefore threw an error.
XmlCursor cursor = table.getCTTbl().newCursor();
cursor.toEndToken();
while (cursor.toNextToken() != org.apache.xmlbeans.XmlCursor.TokenType.START);
XWPFParagraph newParagraph = document.insertNewParagraph(cursor);
XWPFRun run = newParagraph.createRun();
run.setText("inserted new text " + "\n");
Upvotes: 1
Views: 575
Reputation: 61945
The XmlCursor
needs to be created on the correct position in document. That must not be a position, which is not before a start token. And that must not be a position inside any other body element which cannot contain a paragraph or a table.
To adjust the cursor properly before a start token, following method cn be used:
/*modifiers*/ 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;
}
But the XmlObject object
needs to be an body element which is at a position of the text body which allows to add a paragraph or a table.
Let`s have a complete example again:
If WordTemplate.docx looks like...
...then following code
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 Heading 2 style
XWPFStyles styles = document.getStyles();
XWPFStyle style = styles.getStyleWithName("Heading 2"); if (style == null) style = styles.getStyleWithName("heading 2");
String heading2StyleId = (style != null)?style.getStyleId():"";
//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++) {
paragraph = document.insertNewParagraph(cursor); //insert new empty paragraph
paragraph.setStyle(heading2StyleId); //style it Heading 2
run = paragraph.createRun();
run.setText("Subheading " + (t+1));
cursor = setCursorToNextStartToken(paragraph.getCTP());
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());
}
FileOutputStream out = new FileOutputStream("WordResult.docx");
document.write(out);
out.close();
document.close();
}
}
...produces following WordResult.docx
.
Upvotes: 2