【发布时间】:2022-01-06 22:18:33
【问题描述】:
【问题讨论】:
标签: apache-poi
【问题讨论】:
标签: apache-poi
由于要在XWPFNumbering 中添加新的AbstractNum,所以需要XWPFAbstractNum,并且直到现在不使用底层底层对象才能创建,至少需要org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum。
CTAbstractNum 中有用于在其中创建单个子对象的方法。但是生成的代码将是非常小的部分代码,并且需要很多代码行。所以我认为最好的方法是解析XML 来创建AbstractNum。要获得这个XML,可以创建一个简单的带有编号的Worddocument,然后解压缩*.docx 文件并查看/word/numbering.xml。在那里你会找到类似的东西:
<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>
以 3 级十进制编号为例。
我认为这个XML 是自我解释的。每个编号级别都有一个lvl 定义,定义了它的外观和缩进。
对于项目符号编号,XML 将类似,但使用的项目符号字符的字形将使用 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>
...
w:val=" " 中的空格是 unicode 代码点 F06E 的默认字体字形表示。这是因为 ASCII 码点 6E 在 Wingdings 中显示字形“黑色立方体”,但在普通字体中显示字形 n。如果字体 Wingdings 不可用,这可能会导致恼火。这就是为什么使用 unicode F06E 而不是 ASCII 6E。
知道了这一点我们就可以编码了:
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");
}
}
在一个文档中使用两种列表的代码:
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");
}
}
【讨论】:
cTAbstractNumBulletXML 或 使用 cTAbstractNumDecimalXML。如果两者都需要,您将需要两个不同的XWPFAbstractNum abstractNum1 和abstractNum2 都添加到XWPFNumbering numbering 导致两个不同的BigInteger abstractNumID1 和abstractNumID2 以及两个不同的BigInteger @987654356 @和numID2。 paragraph.setNumID 中使用的不同 numID 将为段落设置不同类型的编号。
w:abstractNumId="0" 不能同时是 0 和 XML。其中之一必须不同。我现在提供了使用这两种列表的示例代码。