如何使用 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:
- 他们可以很好地编译并创建一个列表
- 但生成的
.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();
}
}
复制
以上我测试过的程序生成了一个 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("•");
...
我已经相应地更新了所有示例。
我知道对此有很多答案,包括 Whosebug 上的一些答案: 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();
}
}
复制
以上我测试过的程序生成了一个 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("•");
...
我已经相应地更新了所有示例。