Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache POI numbered list

I am using apache-poi to write some data in a MS Word document. I've already spent several hours trying to figure out how to create a numbered list but I haven't achieved any results.

I've gone through this, that and multiple other questions. Taking into account that apache-poi has the worst kind of documentation I've ever seen (basically there's no documentation at all) and their classes and methods have absolutely mad names it's too difficult for me to understand such complex examples.

Q: Could anyone provide a concise code snippet to create such a list in MS Word document:

  1. One
  2. Two
  3. Three

Thank's in advance.

like image 888
Alexander Romanov Avatar asked Jan 03 '23 22:01

Alexander Romanov


1 Answers

First I thought there is an issue with my code linked in your question, since apache poi is highly in development and sometimes code which has worked in earlier versions does not work any more in current versions. But simple copy&paste code leads to working code even in current version 3.16.

So I have removed all the table stuff, since the linked question was about a list in table cells and I got:

import java.io.FileOutputStream;

import org.apache.poi.xwpf.usermodel.*;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLvl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STNumberFormat;

import java.util.ArrayList;
import java.util.Arrays;

import java.math.BigInteger;

public class CreateWordSimplestNumberingList {

 public static void main(String[] args) throws Exception {

  XWPFDocument document = new XWPFDocument();

  XWPFParagraph paragraph = document.createParagraph();
  XWPFRun run=paragraph.createRun();  
  run.setText("The list:");

  ArrayList<String> documentList = new ArrayList<String>(
   Arrays.asList(
    new String[] {
     "One",
     "Two",
     "Three"
    }));

  CTAbstractNum cTAbstractNum = CTAbstractNum.Factory.newInstance();
  //Next we set the AbstractNumId. This requires care. 
  //Since we are in a new document we can start numbering from 0. 
  //But if we have an existing document, we must determine the next free number first.
  cTAbstractNum.setAbstractNumId(BigInteger.valueOf(0));

/* Bullet list
  CTLvl cTLvl = cTAbstractNum.addNewLvl();
  cTLvl.setIlvl(BigInteger.valueOf(0)); // set indent level 0
  cTLvl.addNewNumFmt().setVal(STNumberFormat.BULLET);
  cTLvl.addNewLvlText().setVal("•");
*/

///* Decimal list
  CTLvl cTLvl = cTAbstractNum.addNewLvl();
  cTLvl.setIlvl(BigInteger.valueOf(0)); // set indent level 0
  cTLvl.addNewNumFmt().setVal(STNumberFormat.DECIMAL);
  cTLvl.addNewLvlText().setVal("%1.");
  cTLvl.addNewStart().setVal(BigInteger.valueOf(1));
//*/

  XWPFAbstractNum abstractNum = new XWPFAbstractNum(cTAbstractNum);

  XWPFNumbering numbering = document.createNumbering();

  BigInteger abstractNumID = numbering.addAbstractNum(abstractNum);

  BigInteger numID = numbering.addNum(abstractNumID);

  for (String string : documentList) {
   paragraph = document.createParagraph();
   paragraph.setNumID(numID);
   run=paragraph.createRun(); 
   run.setText(string); 
  }

  paragraph = document.createParagraph();

  FileOutputStream out = new FileOutputStream("CreateWordSimplestNumberingList.docx");
  document.write(out);
  out.close();
  document.close();

 }
}

This results in:

enter image description here

What you need to know is, that a *.docx file is simply a ZIP file containing a directory structure with XMLfiles in it. So what I do if I have the requirement to create a special Word document, is to create the simplest form of that document using Word itself. Then I unzip the *.docx file and find the main story in /word/document.xml. With numberings (lists) I find there:

<w:numId w:val="1"/>

within the paragraphs. This are references to mumIds in /word/numbering.xml. Well have a look at this, I find something like:

<w:numbering>
 <w:abstractNum w:abstractNumId="0">
  <w:lvl>
   <w:start w:val="1"/>
   <w:numFmt w:val="decimal"/>
   <w:lvlText w:val="%1."/>
  </w:lvl>
 </w:abstractNum>
 <w:num w:numId="1">
  <w:abstractNumId w:val="0"/>
 </w:num>
</w:numbering>

A abstractNum having the definition for levels (lvl) of the numbering and a num having the numId and a reference to the abstractNum.

Then you need to know that apache poi XWPF bases on org.openxmlformats.schemas.wordprocessingml.x2006.main.*. So we have XWPFNumbering and XWPFAbstractNum but XWPFAbstractNum can only be created using org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum So how to find documentation about CTAbstractNum. Well Google it and find http://grepcode.com/file/repo1.maven.org/maven2/org.apache.poi/ooxml-schemas/1.1/org/openxmlformats/schemas/wordprocessingml/x2006/main/CTAbstractNum.java

like image 183
Axel Richter Avatar answered Jan 06 '23 10:01

Axel Richter