I have Java code to create a table and some texts to a Word document using Apache POI, but it adds table in last document. I want to write some text, then add table and write some text again.
Currently it adds table first and last document add 2 texts (Hi & Bye)
My code :
public static void main(String[] args)throws Exception {
//Blank Document
XWPFDocument document= new XWPFDocument();
//Write the Document in file system
FileOutputStream out = new FileOutputStream(
new File("create_table.docx"));
//create table
XWPFTable table = document.createTable();
XWPFParagraph para = document.createParagraph();
XWPFRun run = para.createRun();
run.setText("Hi");
//create first row
XWPFTableRow tableRowOne = table.getRow(0);
tableRowOne.getCell(0).setText("col one, row one");
tableRowOne.addNewTableCell().setText("col two, row one");
tableRowOne.addNewTableCell().setText("col three, row one");
//create second row
XWPFTableRow tableRowTwo = table.createRow();
tableRowTwo.getCell(0).setText("col one, row two");
tableRowTwo.getCell(1).setText("col two, row two");
tableRowTwo.getCell(2).setText("col three, row two");
//create third row
XWPFTableRow tableRowThree = table.createRow();
tableRowThree.getCell(0).setText("col one, row three");
tableRowThree.getCell(1).setText("col two, row three");
tableRowThree.getCell(2).setText("col three, row three");
run.setText("Bye");
document.write(out);
out.close();
System.out.println("create_table.docx written successully");
}
How can i print Hi first of page and add table and print Bye after table?
And how can i save document every time when i want add content to it and finally write it and open it ?
Thanks
You have to keep the right order and more importantly : You have to create a new paragraph.
This is the code, you'll need :
public static void main(String[] args) throws IOException {
//Blank Document
XWPFDocument document = new XWPFDocument();
//Write the Document in file system
FileOutputStream out = new FileOutputStream(new File("create_table.docx"));
//Write first Text in the beginning
XWPFParagraph para = document.createParagraph();
XWPFRun run = para.createRun();
run.setText("Hi");
//create table
XWPFTable table = document.createTable();
//create first row
XWPFTableRow tableRowOne = table.getRow(0);
tableRowOne.getCell(0).setText("col one, row one");
tableRowOne.addNewTableCell().setText("col two, row one");
tableRowOne.addNewTableCell().setText("col three, row one");
//create second row
XWPFTableRow tableRowTwo = table.createRow();
tableRowTwo.getCell(0).setText("col one, row two");
tableRowTwo.getCell(1).setText("col two, row two");
tableRowTwo.getCell(2).setText("col three, row two");
//create third row
XWPFTableRow tableRowThree = table.createRow();
tableRowThree.getCell(0).setText("col one, row three");
tableRowThree.getCell(1).setText("col two, row three");
tableRowThree.getCell(2).setText("col three, row three");
//Write second Text after the table (by creating a new paragraph)
XWPFParagraph para2 = document.createParagraph();
XWPFRun run2 = para2.createRun();
run2.setText("Bye");
document.write(out);
out.close();
System.out.println("create_table.docx written successully");
}
This is the output, you'll get:
Related
Can you make a table in the compartment inside the table like case 2?
Can you make a table in the compartment inside the table like case 2?
enter image description here
public class PoiTest3 {
public static void main(String[] args) throws Exception {
try (XWPFDocument doc = new XWPFDocument()) {
XWPFTable table = doc.createTable();
//Creating first Row
XWPFTableRow row1 = table.getRow(0);
row1.getCell(0).setText("First Row, First Column");
row1.addNewTableCell().setText("First Row, Second Column");
row1.addNewTableCell().setText("First Row, Third Column");
//Creating second Row
XWPFTableRow row2 = table.createRow();
row2.getCell(0).setText("Second Row, First Column");
row2.getCell(1).setText("Second Row, Second Column");
row2.getCell(2).setText("Second Row, Third Column");
//create third row
XWPFTableRow row3 = table.createRow();
row3.getCell(0).setText("Third Row, First Column");
row3.getCell(1).setText("Third Row, Second Column");
row3.getCell(2).setText("Third Row, Third Column");
// save to .docx file
try (FileOutputStream out = new FileOutputStream("c:\\excel\\table.docx")) {
doc.write(out);
}
}
}
}
XWPFTableCell is a IBody. So it provides XWPFTable insertNewTbl(org.apache.xmlbeans.XmlCursor cursor). So yes, it is possible to add a table into a table cell.
But the usage of that org.apache.xmlbeans.XmlCursor is not well documented.
To create that cursor we need the table cell, the cursor shall be in, and an new empty paragrsph in that cell. The empty paragrsph is needed because all content we insert using that cursor will be before the element the cursor points to. So that element should be an empty paragraph to avoid inserting content into existing elements like paragraphs with content or other content containing elements.
The following shows the simplest possible complete example.
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
public class CreateWordTableInTable {
public static void main(String[] args) throws Exception {
try (XWPFDocument doc = new XWPFDocument()) {
//create main table
XWPFTable table = doc.createTable();
//create rows and cells
XWPFTableRow row = table.getRow(0);
row.getCell(0).setText("Main table A1");
row.addNewTableCell().setText("Main table B1");
row.addNewTableCell().setText("Main table C1");
row = table.createRow();
row.getCell(0).setText("Main table A2");
row.getCell(1).setText("Main table B2");
row.getCell(2).setText("Main table C2");
//create inner table
//we need the first table cell and an new empty paragrsph in that first cell
row = table.getRow(0);
XWPFTableCell cell = row.getTableCells().get(0);
XWPFParagraph paragraph = cell.addParagraph();
//now we can insert a table there
org.apache.xmlbeans.XmlCursor cursor = paragraph.getCTP().newCursor();
XWPFTable innerTable = cell.insertNewTbl(cursor);
//set table borders
innerTable.setTopBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setRightBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setBottomBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setLeftBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setInsideHBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
innerTable.setInsideVBorder(XWPFTable.XWPFBorderType.SINGLE, 4, 0, "000000");
//create rows and cells
XWPFTableRow rowInInnerTable = innerTable.createRow();
XWPFTableCell cellInInnerTable = rowInInnerTable.createCell();
cellInInnerTable.setText("Inner table A1");
cellInInnerTable = rowInInnerTable.createCell();
cellInInnerTable.setText("Inner table B1");
cellInInnerTable = rowInInnerTable.createCell();
cellInInnerTable.setText("Inner table C1");
rowInInnerTable = innerTable.createRow();
cellInInnerTable = rowInInnerTable.getCell(0);
cellInInnerTable.setText("Inner table A2");
cellInInnerTable = rowInInnerTable.getCell(1);
cellInInnerTable.setText("Inner table B2");
cellInInnerTable = rowInInnerTable.getCell(2);
cellInInnerTable.setText("Inner table C2");
//save to .docx file
try (FileOutputStream out = new FileOutputStream("./CreateWordTableInTable.docx")) {
doc.write(out);
}
}
}
}
It produces:
This code is tested an works using the current Apache POI version 5.2.3. Download: https://poi.apache.org/download.html#POI-5.2.3. Needed components see https://poi.apache.org/components/index.html#components.
I have a table in the docx template.
Depending on the number of objects, I have to duplicate the table as many times as I have objects. Duplicate tables must be after the table from the template.
I have several tables in the template that should behave like this.
XmlCursor take the place of the first table from the template and put the next one there. I want to insert the next table after the previous one, which I added myself, but xmlcursor does not return the table item I added, but returns "STARTDOC"
XmlCursor cursor = docx.getTables().get(pointer).getCTTbl().newCursor();
cursor.toEndToken();
while (cursor.toNextToken() != XmlCursor.TokenType.START) ;
XWPFParagraph newParagraph = docx.insertNewParagraph(cursor);
newParagraph.createRun().setText("", 0);
cursor.toParent();
cursor.toEndToken();
while (cursor.toNextToken() != XmlCursor.TokenType.START) ;
docx.insertNewTbl(cursor);
CTTbl ctTbl = CTTbl.Factory.newInstance();
ctTbl.set(docx.getTables().get(numberTableFromTemplate).getCTTbl());
XWPFTable tableCopy = new XWPFTable(ctTbl, docx);
docx.setTable(index + 1, tableCopy);
Not clear what you are aiming for with the cursor.toParent();. And I also cannot reproduce the issue having only your small code snippet. But having a complete working example may possible help you.
Assuming we have following template:
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 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();
}
}
leads to following result:
Is that about what you wanted to achieve?
Please note how I insert the additional tables.
Using table = document.insertNewTbl(cursor); a new empty table is inserted at position t. This table is placed into the document body. So this table must be taken for adjusting the cursor.
Then tableCopy = new XWPFTable((CTTbl)cTTblTemplate.copy(), document); copys the template table. Then this copy is filled with data. And then it is set into the document at position t using document.setTable(t, tableCopy);.
Unfortunately apache poi is incomplete here. XWPFDocument.setTable only sets the internally ArrayLists but not the underlying XML. XWPFDocument.insertNewTbl sets the underlying XML but only using an empty table. So we must do it that ugly complicated way.
Hi I am trying to copy a table from a docx file to another but what happens is that the value of the table are copied down bellow the table in the new document and outside of it (see pictures bellow)
Table in original docx
Talbe in the new docx
As you can see the values of the table are copied outside the table.
I am using Libre Office, apache poi version 3.17 and my computer runs Ubuntu 16.04
The code I am using to perform the copy is the following
public static void copyTable(XWPFDocument input_doc,XWPFDocument output_doc,
int table_index_input, int table_index_output) {
XWPFTable template_table = input_doc.getTables().get(table_index_input);
CTTbl ctTbl = CTTbl.Factory.newInstance(); // Create a new CTTbl for the new table
ctTbl.set(template_table.getCTTbl()); // Copy the template table's CTTbl
XWPFTable new_table = new XWPFTable(ctTbl, output_doc); // Create a new table using the CTTbl upon
output_doc.createParagraph();
output_doc.createTable();// Create a empty table in the document
output_doc.setTable(table_index_output, new_table); // Replace the empty table to table2
}
XWPFTable newTbl = output_doc.insertNewTbl(cursor);
copyTable(table, newTbl);
and the copyTable() method
private void copyTable(XWPFTable source, XWPFTable target) {
target.getCTTbl().setTblPr(source.getCTTbl().getTblPr());
target.getCTTbl().setTblGrid(source.getCTTbl().getTblGrid());
for (int r = 0; r<source.getRows().size(); r++) {
XWPFTableRow targetRow = target.createRow();
XWPFTableRow row = source.getRows().get(r);
targetRow.getCtRow().setTrPr(row.getCtRow().getTrPr());
for (int c=0; c<row.getTableCells().size(); c++) {
//newly created row has 1 cell
XWPFTableCell targetCell = c==0 ? targetRow.getTableCells().get(0) : targetRow.createCell();
XWPFTableCell cell = row.getTableCells().get(c);
targetCell.getCTTc().setTcPr(cell.getCTTc().getTcPr());
XmlCursor cursor = targetCell.getParagraphArray(0).getCTP().newCursor();
for (int p = 0; p < cell.getBodyElements().size(); p++) {
IBodyElement elem = cell.getBodyElements().get(p);
if (elem instanceof XWPFParagraph) {
XWPFParagraph targetPar = targetCell.insertNewParagraph(cursor);
cursor.toNextToken();
XWPFParagraph par = (XWPFParagraph) elem;
copyParagraph(par, targetPar);
} else if (elem instanceof XWPFTable) {
XWPFTable targetTable = targetCell.insertNewTbl(cursor);
XWPFTable table = (XWPFTable) elem;
copyTable(table, targetTable);
cursor.toNextToken();
}
}
//newly created cell has one default paragraph we need to remove
targetCell.removeParagraph(targetCell.getParagraphs().size()-1);
}
}
//newly created table has one row by default. we need to remove the default row.
target.removeRow(0);
}
the copyParagraph()
private void copyParagraph(XWPFParagraph source, XWPFParagraph target) {
target.getCTP().setPPr(source.getCTP().getPPr());
for (int i=0; i<source.getRuns().size(); i++ ) {
XWPFRun run = source.getRuns().get(i);
XWPFRun targetRun = target.createRun();
//copy formatting
targetRun.getCTR().setRPr(run.getCTR().getRPr());
//no images just copy text
targetRun.setText(run.getText(0));
}
}
I think easier and more reliable form of copyTable function would be something like this.
private void copyTable(XWPFTable source, XWPFTable target) {
CTTbl sourceCTTbl = source.getCTTbl();
CTTbl targetCTTbl = target.getCTTbl();
targetCTTbl.setTblPr(sourceCTTbl.getTblPr());
targetCTTbl.setTrArray(sourceCTTbl.getTrArray());
}
(It works for me at least)
I create a Table using apache poi like this:
XWPFDocument document= new XWPFDocument();
//Write the Document in file system
FileOutputStream out = new FileOutputStream(new File("create_table.docx"));
//create table
XWPFTable table = document.createTable();
//create first row
XWPFTableRow tableRowOne = table.getRow(0);
tableRowOne.getCell(0).setText("col one, row one");
tableRowOne.addNewTableCell().setText("col two, row one");
tableRowOne.addNewTableCell().setText("col three, row one");
//create second row
XWPFTableRow tableRowTwo = table.createRow();
tableRowTwo.getCell(0).setText("col one, row two");
tableRowTwo.getCell(1).setText("col two, row two");
tableRowTwo.getCell(2).setText("col three, row two");
//create third row
XWPFTableRow tableRowThree = table.createRow();
tableRowThree.getCell(0).setText("col one, row three");
tableRowThree.getCell(1).setText("col two, row three");
tableRowThree.getCell(2).setText("col three, row three");
Now I would like get table format and data in a String variable like:
<w:style w:type="table"...>
<w:rPr><w:t> data </w:t> </w:rPr>
Can I do this?
If the Office OpenXML of the XWPFTable is meant, then:
XWPFTable.getCTTbl() returns a CTTbl and this extends XmlObject which provides a XmlObject.toString() which returns an XML string for this XML object.
So
String tableXML = table.getCTTbl().toString();
I'm using itext-rtf 2.1.7 to generate an RTF document.
The parameter table below for the method writeSectionHeaderTableInACell() will have two columns.
For each column, I need to insert a new inner Table, with two columns as well. This inner table will have the first column as left-aligned, and the second as right-aligned.
However, the code below causes a corrupted Table in the generated RTF document. The two inner Tables which supposed to be both on a single row, they appear as one row for each inner Table.
Anyone, has any idea why it seems we cannot add an inner Table within a Cell for RTF document? Thanks.
private static void writeSectionHeaderTableInACell(PdfPTable table) {
PdfPTable sectionTable1 = new PdfPTable(2);
Phrase phrase1 = new Phrase("? 1 ?", FontFactory.getFont("MS Mincho", 10, Font.NORMAL));
Paragraph p1 = new Paragraph(phrase1);
p1.setAlignment(Element.ALIGN_LEFT);
PdfPCell cell1 = new PdfPCell(p1);
sectionTable1.addCell(cell1);
Phrase phrase2 = new Phrase("2 Chi", FontFactory.getFont("MS Mincho", 10, Font.NORMAL));
Paragraph p2 = new Paragraph(phrase2);
p2.setAlignment(Element.ALIGN_RIGHT);
PdfPCell cell2 = new PdfPCell(p2);
sectionTable1.addCell(cell2);
table.addCell(new PdfPCell(sectionTable1));
PdfPTable sectionTable2 = new PdfPTable(2);
Phrase phrase3 = new Phrase("Section 1", FontFactory.getFont("Times New Roman", 10, Font.NORMAL));
Paragraph p3 = new Paragraph(phrase3);
p3.setAlignment(Element.ALIGN_LEFT);
PdfPCell cell3 = new PdfPCell(p3);
sectionTable2.addCell(cell3);
Phrase phrase4 = new Phrase("2 Eng", FontFactory.getFont("Times New Roman", 10, Font.NORMAL));
Paragraph p4 = new Paragraph(phrase4);
p4.setAlignment(Element.ALIGN_RIGHT);
PdfPCell cell4 = new PdfPCell(p4);
sectionTable2.addCell(cell4);
table.addCell(new PdfPCell(sectionTable2));
}