如何用APACHE POI对单词表进行colspan

我有一个代码,但是对于rowspan来说是一个表。 你能帮我把它转换成colspan代码吗?

private static void mergeCellVertically(XWPFTable table, int col, int fromRow, int toRow){ for(int rowIndex = fromRow; rowIndex <= toRow; rowIndex++){ XWPFTableCell cell = table.getRow(rowIndex).getCell(col); if(rowIndex == fromRow){ // The first merged cell is set with RESTART merge value cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART); }else{ // Cells which join (merge) the first one, are set with CONTINUE cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE); } } } 

原理与org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHMerge相同,而不是org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge

但我会仔细研究细胞中的TcPr元素。 您的实际代码每次TcPr创建新的TcPr元素。 如果细胞中已经存在这样的元素怎么办?

例:

 import java.io.File; import java.io.FileOutputStream; import java.math.BigInteger; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTHMerge; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber; public class CreateWordTableMerge { static void mergeCellVertically(XWPFTable table, int col, int fromRow, int toRow) { for(int rowIndex = fromRow; rowIndex <= toRow; rowIndex++){ XWPFTableCell cell = table.getRow(rowIndex).getCell(col); CTVMerge vmerge = CTVMerge.Factory.newInstance(); if(rowIndex == fromRow){ // The first merged cell is set with RESTART merge value vmerge.setVal(STMerge.RESTART); } else { // Cells which join (merge) the first one, are set with CONTINUE vmerge.setVal(STMerge.CONTINUE); // and the content should be removed for (int i = cell.getParagraphs().size(); i > 0; i--) { cell.removeParagraph(0); } cell.addParagraph(); } // Try getting the TcPr. Not simply setting an new one every time. CTTcPr tcPr = cell.getCTTc().getTcPr(); if (tcPr != null) { tcPr.setVMerge(vmerge); } else { // only set an new TcPr if there is not one already tcPr = CTTcPr.Factory.newInstance(); tcPr.setVMerge(vmerge); cell.getCTTc().setTcPr(tcPr); } } } static void mergeCellHorizontally(XWPFTable table, int row, int fromCol, int toCol) { for(int colIndex = fromCol; colIndex <= toCol; colIndex++){ XWPFTableCell cell = table.getRow(row).getCell(colIndex); CTHMerge hmerge = CTHMerge.Factory.newInstance(); if(colIndex == fromCol){ // The first merged cell is set with RESTART merge value hmerge.setVal(STMerge.RESTART); } else { // Cells which join (merge) the first one, are set with CONTINUE hmerge.setVal(STMerge.CONTINUE); // and the content should be removed for (int i = cell.getParagraphs().size(); i > 0; i--) { cell.removeParagraph(0); } cell.addParagraph(); } // Try getting the TcPr. Not simply setting an new one every time. CTTcPr tcPr = cell.getCTTc().getTcPr(); if (tcPr != null) { tcPr.setHMerge(hmerge); } else { // only set an new TcPr if there is not one already tcPr = CTTcPr.Factory.newInstance(); tcPr.setHMerge(hmerge); cell.getCTTc().setTcPr(tcPr); } } } public static void main(String[] args) throws Exception { XWPFDocument document= new XWPFDocument(); XWPFParagraph paragraph = document.createParagraph(); XWPFRun run=paragraph.createRun(); run.setText("The table:"); //create table XWPFTable table = document.createTable(3,5); for (int row = 0; row < 3; row++) { for (int col = 0; col < 5; col++) { table.getRow(row).getCell(col).setText("row " + row + ", col " + col); } } //create CTTblGrid for this table with widths of the 5 columns. //necessary for Libreoffice/Openoffice to accept the column widths. //values are in unit twentieths of a point (1/1440 of an inch) //first column = 1 inches width table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(1*1440)); //other columns (2 in this case) also each 1 inches width for (int col = 1 ; col < 5; col++) { table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1*1440)); } //create and set column widths for all columns in all rows //most examples don't set the type of the CTTblWidth but this //is necessary for working in all office versions for (int col = 0; col < 5; col++) { CTTblWidth tblWidth = CTTblWidth.Factory.newInstance(); tblWidth.setW(BigInteger.valueOf(1*1440)); tblWidth.setType(STTblWidth.DXA); for (int row = 0; row < 3; row++) { CTTcPr tcPr = table.getRow(row).getCell(col).getCTTc().getTcPr(); if (tcPr != null) { tcPr.setTcW(tblWidth); } else { tcPr = CTTcPr.Factory.newInstance(); tcPr.setTcW(tblWidth); table.getRow(row).getCell(col).getCTTc().setTcPr(tcPr); } } } //using the merge methods mergeCellVertically(table, 0, 0, 1); mergeCellHorizontally(table, 1, 2, 3); mergeCellHorizontally(table, 2, 1, 4); paragraph = document.createParagraph(); FileOutputStream out = new FileOutputStream("create_table.docx"); document.write(out); System.out.println("create_table.docx written successully"); } } 

编辑Mar,2018年11月:

设置水平合并有两种方法。 第一种是使用CTHMerge ,它类似于使用CTHMerge的垂直合并,并且它不明确需要表格。 第二种是使用网格范围属性。 此方法需要一个表格,并且必须删除与第一个合并的单元格。

Microsoft Word支持所有方法。

Libreoffice Writer支持CTHMerge但由于正确呈现表格,因此必须设置表格。

WPS Writer仅支持设置网格范围。

所以这应该是最兼容的解决方案:

 import java.io.File; import java.io.FileOutputStream; import java.math.BigInteger; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTcPr; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTTblWidth; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblWidth; import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTVMerge; import org.openxmlformats.schemas.wordprocessingml.x2006.main.STMerge; public class CreateWordTableMerge { static void mergeCellVertically(XWPFTable table, int col, int fromRow, int toRow) { for(int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) { XWPFTableCell cell = table.getRow(rowIndex).getCell(col); CTVMerge vmerge = CTVMerge.Factory.newInstance(); if(rowIndex == fromRow){ // The first merged cell is set with RESTART merge value vmerge.setVal(STMerge.RESTART); } else { // Cells which join (merge) the first one, are set with CONTINUE vmerge.setVal(STMerge.CONTINUE); // and the content should be removed for (int i = cell.getParagraphs().size(); i > 0; i--) { cell.removeParagraph(0); } cell.addParagraph(); } // Try getting the TcPr. Not simply setting an new one every time. CTTcPr tcPr = cell.getCTTc().getTcPr(); if (tcPr == null) tcPr = cell.getCTTc().addNewTcPr(); tcPr.setVMerge(vmerge); } } //merging horizontally by setting grid span instead of using CTHMerge static void mergeCellHorizontally(XWPFTable table, int row, int fromCol, int toCol) { XWPFTableCell cell = table.getRow(row).getCell(fromCol); // Try getting the TcPr. Not simply setting an new one every time. CTTcPr tcPr = cell.getCTTc().getTcPr(); if (tcPr == null) cell.getCTTc().addNewTcPr(); // The first merged cell has grid span property set if (tcPr.isSetGridSpan()) { tcPr.getGridSpan().setVal(BigInteger.valueOf(toCol-fromCol+1)); } else { tcPr.addNewGridSpan().setVal(BigInteger.valueOf(toCol-fromCol+1)); } // Cells which join (merge) the first one, must be removed for(int colIndex = toCol; colIndex > fromCol; colIndex--) { table.getRow(row).getCtRow().removeTc(colIndex); } } public static void main(String[] args) throws Exception { XWPFDocument document= new XWPFDocument(); XWPFParagraph paragraph = document.createParagraph(); XWPFRun run=paragraph.createRun(); run.setText("The table:"); //create table XWPFTable table = document.createTable(3,5); for (int row = 0; row < 3; row++) { for (int col = 0; col < 5; col++) { table.getRow(row).getCell(col).setText("row " + row + ", col " + col); } } //create CTTblGrid for this table with widths of the 5 columns. //necessary for Libreoffice/Openoffice to accept the column widths. //values are in unit twentieths of a point (1/1440 of an inch) //first column = 1 inches width table.getCTTbl().addNewTblGrid().addNewGridCol().setW(BigInteger.valueOf(1*1440)); //other columns (2 in this case) also each 1 inches width for (int col = 1 ; col < 5; col++) { table.getCTTbl().getTblGrid().addNewGridCol().setW(BigInteger.valueOf(1*1440)); } //create and set column widths for all columns in all rows //most examples don't set the type of the CTTblWidth but this //is necessary for working in all office versions for (int col = 0; col < 5; col++) { CTTblWidth tblWidth = CTTblWidth.Factory.newInstance(); tblWidth.setW(BigInteger.valueOf(1*1440)); tblWidth.setType(STTblWidth.DXA); for (int row = 0; row < 3; row++) { CTTcPr tcPr = table.getRow(row).getCell(col).getCTTc().getTcPr(); if (tcPr != null) { tcPr.setTcW(tblWidth); } else { tcPr = CTTcPr.Factory.newInstance(); tcPr.setTcW(tblWidth); table.getRow(row).getCell(col).getCTTc().setTcPr(tcPr); } } } //using the merge methods mergeCellVertically(table, 0, 0, 1); mergeCellHorizontally(table, 1, 2, 3); mergeCellHorizontally(table, 2, 1, 4); paragraph = document.createParagraph(); FileOutputStream out = new FileOutputStream("create_table.docx"); document.write(out); System.out.println("create_table.docx written successully"); } } 

Axel Richter的答案非常完整。 但如果您不使用CTTcPr和其他XML密钥,并且与POI API混合使用,则会出现问题。

你必须使用

  // Cells which join (merge) the first one, must be removed int sizeOfTc = currentRow.getCtRow().sizeOfTcArray(); for(int colIndex = toCol; colIndex > fromCol; colIndex--) { if (colIndex < sizeOfTc) currentRow.getCtRow().removeTc(colIndex); currentRow.removeCell(colIndex); } 

因为Apache POI上有一个错误。 removeCell()方法不会从行中删除Tc。 如果您使用removeTc(),它不会从内部POI列表中删除该单元格。 你必须使用两者。