如何使用 Apache Poi 5 在 docx 中创建项目符号列表?

How do I create a bulleted list in docx with Apache Poi 5?

我知道对此有很多答案,包括 Whosebug 上的一些答案: Apache POI bullet spacing

问题

我无法让他们使用 Apache Poi 5.0.0:

Java代码

import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STLevelSuffix;
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;
// https://www.titanwolf.org/Network/q/15e5b419-e50e-426c-895d-d4a47d18e714/y
public class CreateWordTableWithBulletList3 {
    public static void main(String[] args) throws Exception {
        ArrayList < String > documentList = new ArrayList < String > (
            Arrays.asList(
                new String[] {
                    "One",
                    "Two",
                    "Three, new test"
                }));

        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.addNewNumFmt().setVal(STNumberFormat.BULLET);
        cTLvl.addNewSuff().setVal(STLevelSuffix.SPACE);
        cTLvl.addNewLvlText().setVal("•");

        XWPFAbstractNum abstractNum = new XWPFAbstractNum(cTAbstractNum);
        XWPFDocument document = new XWPFDocument();
        XWPFNumbering numbering = document.createNumbering();

        BigInteger abstractNumID = numbering.addAbstractNum(abstractNum);
        BigInteger numID = numbering.addNum(abstractNumID);

        XWPFParagraph paragraph = document.createParagraph();
        XWPFRun run = paragraph.createRun();
        run.setText("The list having space between bulltet point and text:");

        for (String string: documentList) {
            paragraph = document.createParagraph();
            paragraph.setNumID(numID);
            // font size for bullet point in half pt
            paragraph.getCTP().getPPr().addNewRPr().addNewSz().setVal(BigInteger.valueOf(48));
            run = paragraph.createRun();
            run.setText(string);
            run.setFontSize(24);
        }

        paragraph = document.createParagraph();

        FileOutputStream out = new FileOutputStream("/tmp/CreateWordSimplestBulletList4.docx");
        document.write(out);
        out.close();
        document.close();

    }
}

复制

以上我测试过的程序生成了一个 numbered 的 Apache Poi 5.0.0 列表。

注意: 虽然我的原始输出未能通过真实 Word (Mac) 的测试,但我目前正在 Libre Office (7.1.5.2) Fedora (Linux) 和 Slack 的 Preview Word 功能。两者都显示一个编号列表。

最后我刚刚创建了一个新项目,其中仅包含 poi5 中的所有 .jar 文件(包括所有依赖项,仅此而已)。那仍然在我的 Libre Office 中显示了一个编号列表。

结果输出

从.docx中提取的numbering.xml

<?xml version="1.0" encoding="UTF-8"?>
<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
   <w:abstractNum w:abstractNumId="0">
      <w:lvl>
         <w:numFmt w:val="bullet" />
         <w:suff w:val="space" />
         <w:lvlText w:val="•" />
      </w:lvl>
   </w:abstractNum>
   <w:num w:numId="1">
      <w:abstractNumId w:val="0" />
   </w:num>
</w:numbering>

这里是 document.xml:

<?xml version="1.0" encoding="UTF-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
   <w:body>
      <w:p>
         <w:r>
            <w:t>The list having space between bulltet point and text:</w:t>
         </w:r>
      </w:p>
      <w:p>
         <w:pPr>
            <w:numPr>
               <w:numId w:val="1" />
            </w:numPr>
            <w:rPr>
               <w:sz w:val="48" />
            </w:rPr>
         </w:pPr>
         <w:r>
            <w:rPr>
               <w:sz w:val="48" />
            </w:rPr>
            <w:t>One</w:t>
         </w:r>
      </w:p>
      <w:p>
         <w:pPr>
            <w:numPr>
               <w:numId w:val="1" />
            </w:numPr>
            <w:rPr>
               <w:sz w:val="48" />
            </w:rPr>
         </w:pPr>
         <w:r>
            <w:rPr>
               <w:sz w:val="48" />
            </w:rPr>
            <w:t>Two</w:t>
         </w:r>
      </w:p>
      <w:p>
         <w:pPr>
            <w:numPr>
               <w:numId w:val="1" />
            </w:numPr>
            <w:rPr>
               <w:sz w:val="48" />
            </w:rPr>
         </w:pPr>
         <w:r>
            <w:rPr>
               <w:sz w:val="48" />
            </w:rPr>
            <w:t>Three, new test. Lite. Still testing.</w:t>
         </w:r>
      </w:p>
      <w:p />
   </w:body>
</w:document>

我认为错误出在某处。

在我关于在 Microsoft Word 中创建编号的示例中,我假设如果未设置缩进级别将默认为 0。我已经使用我拥有的所有文字处理应用程序对其进行了测试,情况确实如此。但是,使用所有可以打开 *.docx 个文件的文字处理应用程序似乎并非如此。因此明确设置缩进级别似乎是最兼容的解决方案。

因此在创建 CTLvl 的代码中使用 cTLvl.setIlvl(BigInteger.valueOf(0)); // set indent level 0:

明确设置缩进级别
...
  //Bullet list
  CTLvl cTLvl = cTAbstractNum.addNewLvl();
  cTLvl.setIlvl(BigInteger.valueOf(0)); // set indent level 0
  cTLvl.addNewNumFmt().setVal(STNumberFormat.BULLET);
  cTLvl.addNewSuff().setVal(STLevelSuffix.SPACE);
  cTLvl.addNewLvlText().setVal("•");
...

我已经相应地更新了所有示例。