Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create table with docx4j

I try to create a new table depending on input data and insert it into an docx-document. Following leads to a corrupted output file:

private Tbl getSampleTable(WordprocessingMLPackage wPMLpackage) {

        ObjectFactory factory = Context.getWmlObjectFactory();
        int writableWidthTwips = wPMLpackage.getDocumentModel().getSections().get(0).getPageDimensions().getWritableWidthTwips();
        List<Map<String, String>> data = getSampleTableData();
        TableDefinition tableDef = getSampleTableDef();
        int cols = tableDef.getColumns().size();
        int cellWidthTwips = new Double(Math.floor((writableWidthTwips / cols))).intValue();

        Tbl table = TblFactory.createTable((data.size() + 1), cols, cellWidthTwips);

        Tr headerRow = (Tr) table.getContent().get(0);

        int f = 0;
        for (Column column : tableDef.getColumns()) {
            Tc column = (Tc) headerRow.getContent().get(f);
            f++;
            Text text = factory.createText();
            text.setValue(column.getName());
            R run = factory.createR();
            run.getContent().add(text);
            column.getContent().add(run);
            headerRow.getContent().add(column);
        }
        int i = 1;

        for (Map<String, String> entry : data) {
            Tr row = (Tr) table.getContent().get(i);
            i++;
            int p = 0;
            for (String key : entry.keySet()) {
                Tc column = (Tc) row.getContent().get(p);
                p++;
                Text tx = factory.createText();
                R run = factory.createR();
                tx.setValue(entry.get(key));
                run.getContent().add(tx);
                column.getContent().add(run);
                row.getContent().add(column);
            }
        }
        return table;
    }

Without inserting the table the docx-document is created how it shall be.

I use the this function by trying to insert this table in an file that I receive as input parameter:

    ByteArrayInputStream bis = new ByteArrayInputStream(file);
    WordprocessingMLPackage wPMLpackage = null;
    wPMLpackage = WordprocessingMLPackage.load(bis);

    // Zip it up
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    SaveToZipFile saver = new SaveToZipFile(wPMLpackage);
    saver.save(baos);
    byte[] template = baos.toByteArray();

    WordprocessingMLPackage target = WordprocessingMLPackage.load(new ByteArrayInputStream(template));
    target.getMainDocumentPart().getContent().clear();

    target.getMainDocumentPart().addObject(getSampleTable(target));
    ByteArrayOutputStream baos2 = new ByteArrayOutputStream();
    SaveToZipFile saver2 = new SaveToZipFile(target);
    saver2.save(baos2);
    return baos2.toByteArray();

Someone has an idea why the generated file can't be interpreted by Microsoft Word? The error message is "The file can't be opened as its contents causes problems". Manipulation of the document works as long as I don't insert this table.

like image 423
user1335772 Avatar asked Nov 13 '13 15:11

user1335772


2 Answers

Inserting the runs in paragraphs leads to the desired result:

 private Tbl getSampleTable(WordprocessingMLPackage wPMLpackage) {

    ObjectFactory factory = Context.getWmlObjectFactory();
    int writableWidthTwips = wPMLpackage.getDocumentModel().getSections()
                                        .get(0).getPageDimensions()
                                        .getWritableWidthTwips();
    List<Map<String, String>> data = getSampleTableData();
    TableDefinition tableDef = getSampleTableDef();
    int cols = tableDef.getColumns().size();
    int cellWidthTwips = new Double(
            Math.floor((writableWidthTwips / cols))
        ).intValue();

    Tbl table = TblFactory.createTable((data.size() + 1), cols, cellWidthTwips);

    Tr headerRow = (Tr) table.getContent().get(0);

    int f = 0;
    for (Column column : tableDef.getColumns()) {
        Tc column = (Tc) headerRow.getContent().get(f);
        P columnPara = (P) column.getContent().get(0);
        f++;
        Text text = factory.createText();
        text.setValue(column.getName());
        R run = factory.createR();
        run.getContent().add(text);
        columnPara.getContent().add(run);
    }
    int i = 1;

    for (Map<String, String> entry : data) {
        Tr row = (Tr) table.getContent().get(i);
        i++;
        int d = 0;
        for (String key : entry.keySet()) {
            Tc column = (Tc) row.getContent().get(d);
            P columnPara = (P) column.getContent().get(0);
            d++;
            Text tx = factory.createText();
            R run = factory.createR();
            tx.setValue(entry.get(key));
            run.getContent().add(tx);
            columnPara.getContent().add(run);
        }
    }
    return table;
}
like image 162
user1335772 Avatar answered Oct 14 '22 22:10

user1335772


In creating a table (or anything else for that matter), one approach worth bearing in mind is to create what you want in Word, then use one of the docx4j code gen tools to generate corresponding Java code.

The code gen tool is available 2 ways:

  • online at http://webapp.docx4java.org/OnlineDemo/PartsList.html
  • or as a Word AddIn, see http://www.docx4java.org/forums/docx4jhelper-addin-f30/

The advantage of the Word AddIn is that you avoid the save-upload cycle.

like image 40
JasonPlutext Avatar answered Oct 14 '22 22:10

JasonPlutext