Sucy
Sucy

Reputation: 498

How can I add List in poi word, ordered number or other symbol for list symbol?

everyone! first, I want to add list in my poi word(XWPF), second, I want to using black cube as the list symbol like picture as below. third, what I should to do if ordered number instead of the black cube symbol. Could someone give me some advice? Thanks so lot!

enter image description here

Upvotes: 0

Views: 4343

Answers (1)

Axel Richter
Axel Richter

Reputation: 61852

Since for new adding a new AbstractNum in XWPFNumbering, XWPFAbstractNum is needed and this is not able to create without using underlaying low level objects until now, at least org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum is needed.

There are methods in CTAbstractNum for creating the single sub objects therein. But the resulting code would be very small part code and so much many code lines would be necessary. So the best way in my opinion is parsing XML for creating the AbstractNum. To get this XML one can create a simple Worddocument having numbering and then unzip the *.docx file and have a look at /word/numbering.xml. There you will find something like:

<w:numbering>
 <w:abstractNum w:abstractNumId="0">
  <w:multiLevelType w:val="hybridMultilevel"/>
  <w:lvl w:ilvl="0">
   <w:start w:val="1"/><w:numFmt w:val="decimal"/><w:lvlText w:val="%1"/><w:lvlJc w:val="left"/>
   <w:pPr>
    <w:ind w:hanging="360" w:left="720"/>
   </w:pPr>
  </w:lvl>
  <w:lvl w:ilvl="1" w:tentative="1">
   <w:start w:val="1"/><w:numFmt w:val="decimal"/><w:lvlText w:val="%1.%2"/><w:lvlJc w:val="left"/>
   <w:pPr>
    <w:ind w:hanging="360" w:left="1440"/>
   </w:pPr>
  </w:lvl>
  <w:lvl w:ilvl="2" w:tentative="1">
   <w:start w:val="1"/><w:numFmt w:val="decimal"/><w:lvlText w:val="%1.%2.%3"/><w:lvlJc w:val="left"/>
   <w:pPr>
    <w:ind w:hanging="360" w:left="2160"/>
   </w:pPr>
  </w:lvl>
 </w:abstractNum>
...
</w:numbering>

for a 3 level decimal numbering for example.

This XML is self explained in my opinion. There is a lvl definition for each numbering level having definitions for it's appearance and indention.

For a bullet numbering the XMLwill be similar but the glyphs for the bullet characters used will be additional defined using Font definition. The "black cube" for example is a glyph from font Wingdings.

...
<w:lvl w:ilvl="0">
 <w:start w:val="1"/><w:numFmt w:val="bullet"/><w:lvlText w:val=" "/><w:lvlJc w:val="left"/>
 <w:pPr>
  <w:ind w:hanging="360" w:left="720"/>
 </w:pPr>
 <w:rPr>
  <w:rFonts w:ascii="Wingdings" w:hAnsi="Wingdings" w:hint="default"/>
 </w:rPr>
</w:lvl>
...

The space in w:val=" " is the default font glyph representation for the unicode code point F06E. This is used because the ASCII code point 6E is showing the glyph "black cube" in Wingdings but the glyph n in normal fonts. That couls lead to irritations if the font Wingdings is not available. Thats why unicode F06E is used instaed of ASCII 6E.

Knowing this we can code:

import java.io.File;
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.CTNumbering;

import java.math.BigInteger;

public class CreateWordBulletOrDecimalList {

 static String cTAbstractNumBulletXML = 
  "<w:abstractNum xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" w:abstractNumId=\"0\">"
+ "<w:multiLevelType w:val=\"hybridMultilevel\"/>"
+ "<w:lvl w:ilvl=\"0\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:lvlText w:val=\"\uF06E\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"720\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Wingdings\" w:hAnsi=\"Wingdings\" w:hint=\"default\"/></w:rPr></w:lvl>"
+ "<w:lvl w:ilvl=\"1\" w:tentative=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:lvlText w:val=\"\u2013\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"1440\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Courier New\" w:hAnsi=\"Courier New\" w:cs=\"Courier New\" w:hint=\"default\"/></w:rPr></w:lvl>"
+ "<w:lvl w:ilvl=\"2\" w:tentative=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:lvlText w:val=\"\u26Ac\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"2160\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Courier New\" w:hAnsi=\"Courier New\" w:hint=\"default\"/></w:rPr></w:lvl>"
+ "</w:abstractNum>";

 static String cTAbstractNumDecimalXML = 
  "<w:abstractNum xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" w:abstractNumId=\"0\">"
+ "<w:multiLevelType w:val=\"hybridMultilevel\"/>"
+ "<w:lvl w:ilvl=\"0\"><w:start w:val=\"1\"/><w:numFmt w:val=\"decimal\"/><w:lvlText w:val=\"%1\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"720\" w:hanging=\"360\"/></w:pPr></w:lvl>"
+ "<w:lvl w:ilvl=\"1\" w:tentative=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"decimal\"/><w:lvlText w:val=\"%1.%2\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"1440\" w:hanging=\"360\"/></w:pPr></w:lvl>"
+ "<w:lvl w:ilvl=\"2\" w:tentative=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"decimal\"/><w:lvlText w:val=\"%1.%2.%3\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"2160\" w:hanging=\"360\"/></w:pPr></w:lvl>"
+ "</w:abstractNum>";

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

  XWPFDocument document = new XWPFDocument();

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

  CTNumbering cTNumbering = CTNumbering.Factory.parse(cTAbstractNumBulletXML);
  //CTNumbering cTNumbering = CTNumbering.Factory.parse(cTAbstractNumDecimalXML);

  CTAbstractNum cTAbstractNum = cTNumbering.getAbstractNumArray(0);

  XWPFAbstractNum abstractNum = new XWPFAbstractNum(cTAbstractNum);

  XWPFNumbering numbering = document.createNumbering();

  BigInteger abstractNumID = numbering.addAbstractNum(abstractNum);

  BigInteger numID = numbering.addNum(abstractNumID);

  for (int i = 0; i < 5; i++) {
   paragraph = document.createParagraph();
   paragraph.setNumID(numID);
   run = paragraph.createRun();
   run.setText("List item " + (i+1)); 
   if (i < 4) paragraph.setSpacingAfter(0);
   if (i == 0) {
    for (int j = 0; j < 2; j++) {
     paragraph = document.createParagraph();
     paragraph.setNumID(numID);
     paragraph.getCTP().getPPr().getNumPr().addNewIlvl().setVal(BigInteger.valueOf(1));
     run = paragraph.createRun();
     run.setText("Sub list item " + (i+1) + " " + (char)(97+j));
     paragraph.setSpacingAfter(0);
    }
   }
   if (i == 1 || i == 3) {
    paragraph = document.createParagraph();
    paragraph.setNumID(numID);
    paragraph.getCTP().getPPr().getNumPr().addNewIlvl().setVal(BigInteger.valueOf(1));
    run = paragraph.createRun();
    run.setText("Sub list item " + (i+1) + " a");
    paragraph.setSpacingAfter(0); 
   }
  }

  paragraph = document.createParagraph();
  run=paragraph.createRun();  
  run.setText("Paragraph after the list.");

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

  System.out.println("CreateWordBulletOrDecimalList written successully");
 }
}

Code for using both kind of lists in one document:

import java.io.File;
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.CTNumbering;

import java.math.BigInteger;

public class CreateWordBulletAndDecimalList {

 static String cTAbstractNumBulletXML = 
  "<w:abstractNum xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" w:abstractNumId=\"0\">"
+ "<w:multiLevelType w:val=\"hybridMultilevel\"/>"
+ "<w:lvl w:ilvl=\"0\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:lvlText w:val=\"\uF06E\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"720\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Wingdings\" w:hAnsi=\"Wingdings\" w:hint=\"default\"/></w:rPr></w:lvl>"
+ "<w:lvl w:ilvl=\"1\" w:tentative=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:lvlText w:val=\"\u2013\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"1440\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Courier New\" w:hAnsi=\"Courier New\" w:cs=\"Courier New\" w:hint=\"default\"/></w:rPr></w:lvl>"
+ "<w:lvl w:ilvl=\"2\" w:tentative=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:lvlText w:val=\"\u26Ac\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"2160\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Courier New\" w:hAnsi=\"Courier New\" w:hint=\"default\"/></w:rPr></w:lvl>"
+ "</w:abstractNum>";

 static String cTAbstractNumDecimalXML = 
  "<w:abstractNum xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" w:abstractNumId=\"1\">"
+ "<w:multiLevelType w:val=\"hybridMultilevel\"/>"
+ "<w:lvl w:ilvl=\"0\"><w:start w:val=\"1\"/><w:numFmt w:val=\"decimal\"/><w:lvlText w:val=\"%1\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"720\" w:hanging=\"360\"/></w:pPr></w:lvl>"
+ "<w:lvl w:ilvl=\"1\" w:tentative=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"decimal\"/><w:lvlText w:val=\"%1.%2\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"1440\" w:hanging=\"360\"/></w:pPr></w:lvl>"
+ "<w:lvl w:ilvl=\"2\" w:tentative=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"decimal\"/><w:lvlText w:val=\"%1.%2.%3\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"2160\" w:hanging=\"360\"/></w:pPr></w:lvl>"
+ "</w:abstractNum>";

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

  XWPFDocument document = new XWPFDocument();

  CTNumbering cTNumbering = CTNumbering.Factory.parse(cTAbstractNumBulletXML);
  CTAbstractNum cTAbstractNum = cTNumbering.getAbstractNumArray(0);
  XWPFAbstractNum abstractNum1 = new XWPFAbstractNum(cTAbstractNum);


  cTNumbering = CTNumbering.Factory.parse(cTAbstractNumDecimalXML);
  cTAbstractNum = cTNumbering.getAbstractNumArray(0);
  XWPFAbstractNum abstractNum2 = new XWPFAbstractNum(cTAbstractNum);

  XWPFNumbering numbering = document.createNumbering();

  BigInteger abstractNumID1 = numbering.addAbstractNum(abstractNum1);
  BigInteger numID1 = numbering.addNum(abstractNumID1);

  BigInteger abstractNumID2 = numbering.addAbstractNum(abstractNum2);
  BigInteger numID2 = numbering.addNum(abstractNumID2);

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

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

  for (int i = 0; i < 5; i++) {
   paragraph = document.createParagraph();
   paragraph.setNumID(numID1);
   run = paragraph.createRun();
   run.setText("List item " + (i+1)); 
   if (i < 4) paragraph.setSpacingAfter(0);
   if (i == 0) {
    for (int j = 0; j < 2; j++) {
     paragraph = document.createParagraph();
     paragraph.setNumID(numID1);
     paragraph.getCTP().getPPr().getNumPr().addNewIlvl().setVal(BigInteger.valueOf(1));
     run = paragraph.createRun();
     run.setText("Sub list item " + (i+1) + " " + (char)(97+j));
     paragraph.setSpacingAfter(0);
    }
   }
   if (i == 1 || i == 3) {
    paragraph = document.createParagraph();
    paragraph.setNumID(numID1);
    paragraph.getCTP().getPPr().getNumPr().addNewIlvl().setVal(BigInteger.valueOf(1));
    run = paragraph.createRun();
    run.setText("Sub list item " + (i+1) + " a");
    paragraph.setSpacingAfter(0); 
   }
  }

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

  for (int i = 0; i < 5; i++) {
   paragraph = document.createParagraph();
   paragraph.setNumID(numID2);
   run = paragraph.createRun();
   run.setText("List item " + (i+1)); 
   if (i < 4) paragraph.setSpacingAfter(0);
   if (i == 0) {
    for (int j = 0; j < 2; j++) {
     paragraph = document.createParagraph();
     paragraph.setNumID(numID2);
     paragraph.getCTP().getPPr().getNumPr().addNewIlvl().setVal(BigInteger.valueOf(1));
     run = paragraph.createRun();
     run.setText("Sub list item " + (i+1) + " " + (char)(97+j));
     paragraph.setSpacingAfter(0);
    }
   }
   if (i == 1 || i == 3) {
    paragraph = document.createParagraph();
    paragraph.setNumID(numID2);
    paragraph.getCTP().getPPr().getNumPr().addNewIlvl().setVal(BigInteger.valueOf(1));
    run = paragraph.createRun();
    run.setText("Sub list item " + (i+1) + " a");
    paragraph.setSpacingAfter(0); 
   }
  }

  paragraph = document.createParagraph();
  paragraph = document.createParagraph();
  run=paragraph.createRun();  
  run.setText("Paragraph after the lists.");

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

  System.out.println("CreateWordBulletAndDecimalList written successully");
 }
}

Upvotes: 6

Related Questions