【问题标题】:How do I create a bulleted list in docx with Apache Poi 5?如何使用 Apache Poi 5 在 docx 中创建项目符号列表?
【发布时间】:2021-08-07 00:15:37
【问题描述】:

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

问题

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

  • 他们编译得很好并创建了一个列表
  • 但生成的.docx 文件包含编号列表而不是项目符号列表。

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();

    }
}

再现

我测试的上述程序使用 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>

我认为错误在某处。

【问题讨论】:

  • 无法复制。我复制/粘贴了您的代码,然后使用apache poi 5.0.0 编译和运行。结果CreateWordSimplestBulletList4.docx 显示Microsoft Word 365Libreoffice Writer Version: 6.4.7.2Google Docs 中的项目符号列表。
  • @AxelRichter 奇怪,我只是仔细检查了计算机上的代码。所以问题一定出在我的依赖或其他东西上。你有你使用的 maven/ant/eclipse/other 构建文件,所以我可以重现你的构建吗?或者只是您使用的所有罐子的列表。
  • 我怀疑这可能是依赖不匹配的结果。然后就会抛出异常。您确定您正在查看正确的文件/tmp/CreateWordSimplestBulletList4.docx?如果您以ZIP 存档打开它,您在/word/numbering.xml 中看到了什么?
  • @AxelRichter 查看 numbers.xml 和 document.xml 的更新
  • 这正是我得到的,它对我有用。疯狂的猜测:你的文字处理应用程序在未设置时不会默认缩进级别为 0 吗?尝试明确设置:cTLvl.setIlvl(BigInteger.valueOf(0)); // set indent level 0.

标签: java apache-poi


【解决方案1】:

在我关于在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("•");
...

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-27
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多