Search code examples
docx4j

Restart numeration in multiple tables with docx4j


I need to create a .docx file using docx4j with many tables based on a template.

Tables must have rows with automatic numeration.

After copying table from template numeration continues in consecutive tables, like this:

table 1

  1. List item
  2. List item

table 2

  1. List item
  2. List item

How can I restart numeration for every table to obtain this:

table 1

  1. List item
  2. List item

table 2

  1. List item
  2. List item

I found that there exists NumberingDefinitionPart.restart() method that could be helpful but how can I apply it on each table?

Could you give example with java code?


Solution

  • For each table after the first, you need to create/add a list level override to the numbering definitions part, then use that in your numPr (ie in your "list item").

    The method you mentioned does this:

    /**
     * For the given list numId, restart the numbering on the specified
     * level at value val.  This is done by creating a new list (ie <w:num>)
     * which uses the existing w:abstractNum.
     * @param numId
     * @param ilvl
     * @param val
     * @return 
     */
    public long restart(long numId, long ilvl, long val) 
        throws InvalidOperationException {
    
        // Find the abstractNumId
    
        // (Ensure maps are initialised)
        if (em == null ) { 
            getEmulator();
        }
        ListNumberingDefinition existingLnd = instanceListDefinitions.get( Long.toString(numId) );
        if (existingLnd==null) {
            throw new InvalidOperationException("List " + numId + " does not exist");
        }
        BigInteger abstractNumIdVal = existingLnd.getNumNode().getAbstractNumId().getVal();
    
        // Generate the new <w:num
        long newNumId = instanceListDefinitions.size() + 1;
    
        org.docx4j.wml.ObjectFactory factory = Context.getWmlObjectFactory();
    
        Num newNum = factory.createNumberingNum();
        newNum.setNumId( BigInteger.valueOf(newNumId) );
        AbstractNumId abstractNumId = factory.createNumberingNumAbstractNumId();
        abstractNumId.setVal(abstractNumIdVal);
        newNum.setAbstractNumId(abstractNumId);
    
        LvlOverride lvlOverride = factory.createNumberingNumLvlOverride();
        lvlOverride.setIlvl(BigInteger.valueOf(ilvl));
        newNum.getLvlOverride().add(lvlOverride);
    
        StartOverride start = factory.createNumberingNumLvlOverrideStartOverride();
        start.setVal(BigInteger.valueOf(val));
        lvlOverride.setStartOverride(start);
    
        // Add it to the jaxb object and our hashmap
        ((Numbering)getJaxbElement()).getNum().add(newNum);
        ListNumberingDefinition listDef 
            = new ListNumberingDefinition(newNum, abstractListDefinitions);
        instanceListDefinitions.put(listDef.getListNumberId(), listDef);        
    
        // Return the new numId
        return newNumId;
    
    }
    

    https://github.com/plutext/docx4j/blob/master/src/samples/docx4j/org/docx4j/samples/NumberingRestart.java is an example of using it.

    In your numPr element in your w:p "list item":

                        <w:pPr>
                            <w:numPr>
                                <w:ilvl w:val="0"/>
                                <w:numId w:val="1"/>
                            </w:numPr>
                        </w:pPr>
    

    set level (ilvl) to the level you used in the method; set numid to the value the method returns.

    As noted in the sample, after the first paragraph using newNumId, it doesn't matter whether subsequent paragraphs use that or the original numId.