Search code examples
javams-wordapache-poi

Apache POI Word insert both table and text at the same level


I want to insert both a table and some text at the same level in a XWPFDocument using Apache POI, meaning that the table will be on the left side and the text on it'r right side, just like in this template:

enter image description here

Using a solution providing a cursor found around, does not seems to make it work. This is the approach commonly used:

XWPFTable table = document.createTable();

XWPFTableRow tableRowOne = table.getRow(0);
tableRowOne.getCell(0).setText("col one");
tableRowOne.addNewTableCell().setText("col two");
tableRowOne.addNewTableCell().setText("col three");

XmlCursor cursor = table.getCTTbl().newCursor();
cursor.toEndToken();

while(cursor.toNextToken() != org.apache.xmlbeans.XmlCursor.TokenType.START);
XWPFParagraph paragraph2 = document.insertNewParagraph(cursor);

XWPFRun run = paragraph2.createRun();
run.setText("Abstract: ");

The result is this:

enter image description here

Do you have any idea there is a way to make it work? Thanks.


Solution

  • The XmlCursor is the wrong way here. An XmlCursor gets used to get or insert XML into a special position of an XML document. But what you need is either a table property (text wrapping) or a page setting (multiple columns on page).

    To get a page spiltted into two columns, see How to add continuous section break to XWPFDocument?. There left side also may contain a table.

    To set table properties, which not are available using XWPFTable one can do the following:

    Create a *.docx document having the setting. See Set or change table properties for how to set table text wrapping.

    Unzip the *.docx file (each Office Open XML file is simply a ZIP archive) and have a look into /word/document.xml. You will find something like

    <w:tbl>
     <w:tblPr>
      <w:tblpPr w:vertAnchor="text"/>
      <w:tblOverlap w:val="never"/>
     ...
     </w:tblPr>
     ...
    </w:tbl>
    

    for table XML.

    That are TableProperties having TablePositionProperties and TableOverlap.

    Now recreate this using org.openxmlformats.schemas.wordprocessingml.x2006.main.* classes.

    Complete example:

    import java.io.FileOutputStream;
    
    import org.apache.poi.xwpf.usermodel.*;
    
    public class CreateWordTableTextWrapping {
        
     public static void main(String[] args) throws Exception {
    
      XWPFDocument document = new XWPFDocument();
    
      XWPFParagraph paragraph = document.createParagraph();
      XWPFRun run = paragraph.createRun();  
      run.setText("Text before table...");
    
      XWPFTable table = document.createTable(1, 3);
      table.setWidth("50%");
      
      //set table text wrapping
      //get table properties, add new table position properties, set vertical anchor Text
      table.getCTTbl().getTblPr().addNewTblpPr().setVertAnchor​(org.openxmlformats.schemas.wordprocessingml.x2006.main.STVAnchor.TEXT);
      //set table position properties Y in TwIPs (TWentieth of an Inch Point) - must be at least 1 for Office 365
      table.getCTTbl().getTblPr().getTblpPr().setTblpY​(1);
      //get table properties, add new table overlap, set value Never
      table.getCTTbl().getTblPr().addNewTblOverlap().setVal(org.openxmlformats.schemas.wordprocessingml.x2006.main.STTblOverlap.NEVER);
    
      paragraph = document.createParagraph();
      run = paragraph.createRun();  
      run.setText("Text after table...");
    
      FileOutputStream out = new FileOutputStream("./CreateWordTableTextWrapping.docx");
      document.write(out);
      out.close();
      document.close();
    
     }
    }