I even cannot get valuable results using XWPFDocument.createTOC()
(fields for page numbers are wrong for example). So I have never used that. What I can say is that XWPFDocument.createTOC()
currently not creates a "Table of Contents" like Word itself will do. So after opening in Word
it will not be recognized as TOC from Word
GUI.
But if the question is only about the styles, then that can be answered. There must be styles named "toc 1", "toc 2", "toc 3", ..., "toc n" present for each heading level. This can be achieved using XML
like:
<w:style w:styleId="TOC1" w:type="paragraph">
<w:name w:val="toc 1"/>
<w:basedOn w:val="Normal"/>
<w:next w:val="Normal"/>
<w:autoRedefine/><w:unhideWhenUsed/>
<w:rPr>
<w:b/><w:bCs/><w:caps/><w:sz w:val="32"/><w:szCs w:val="32"/>
</w:rPr>
</w:style>
The most formatting is done within the rPr
(Run Properties) element and it's children.
Example:
import java.io.File;
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTNumbering;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyles;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTSimpleField;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STOnOff;
import java.math.BigInteger;
public class CreateWordNumberedHeadings {
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="360" 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="720" 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="1440" w:hanging="360"/></w:pPr></w:lvl>"
+ "</w:abstractNum>";
static String cTStyleNormal =
"<w:style xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" w:type="paragraph" w:default="1" w:styleId="Normal">"
+ "<w:name w:val="Normal"/>"
+ "<w:qFormat/>"
+ "</w:style>";
static String cTStyleH1XML =
"<w:style xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" w:type="paragraph" w:styleId="Heading1">"
+ "<w:name w:val="heading 1"/>"
+ "<w:basedOn w:val="Normal"/>"
+ "<w:next w:val="Normal"/>"
+ "<w:unhideWhenUsed/>"
+ "<w:qFormat/>"
+ "<w:rPr><w:b/><w:sz w:val="36"/></w:rPr>"
+ "</w:style>";
static String cTStyleH2XML =
"<w:style xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" w:type="paragraph" w:styleId="Heading2">"
+ "<w:name w:val="heading 2"/>"
+ "<w:basedOn w:val="Normal"/>"
+ "<w:next w:val="Normal"/>"
+ "<w:unhideWhenUsed/>"
+ "<w:qFormat/>"
+ "<w:rPr><w:sz w:val="32"/></w:rPr>"
+ "</w:style>";
static String cTStyleH3XML =
"<w:style xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" w:type="paragraph" w:styleId="Heading3">"
+ "<w:name w:val="heading 3"/>"
+ "<w:basedOn w:val="Normal"/>"
+ "<w:next w:val="Normal"/>"
+ "<w:unhideWhenUsed/>"
+ "<w:qFormat/>"
+ "<w:rPr><w:i/><w:sz w:val="28"/></w:rPr>"
+ "</w:style>";
static String cTStyleTOC1 =
"<w:style xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" w:type="paragraph" w:styleId="TOC1">"
+ "<w:name w:val="toc 1"/>"
+ "<w:basedOn w:val="Normal"/>"
+ "<w:next w:val="Normal"/>"
+ "<w:autoRedefine/><w:unhideWhenUsed/>"
+ "<w:rPr><w:b/><w:bCs/><w:caps/><w:color w:val="C00000"/><w:sz w:val="32"/><w:szCs w:val="32"/></w:rPr>"
+ "</w:style>";
static String cTStyleTOC2 =
"<w:style xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" w:type="paragraph" w:styleId="TOC2">"
+ "<w:name w:val="toc 2"/>"
+ "<w:basedOn w:val="Normal"/>"
+ "<w:next w:val="Normal"/>"
+ "<w:autoRedefine/><w:unhideWhenUsed/>"
+ "<w:rPr><w:i/><w:iCs/><w:sz w:val="28"/><w:szCs w:val="28"/></w:rPr>"
+ "</w:style>";
public static void main(String[] args) throws Exception {
XWPFDocument document = new XWPFDocument();
XWPFNumbering numbering = document.createNumbering();
CTNumbering cTNumbering = CTNumbering.Factory.parse(cTAbstractNumDecimalXML);
CTAbstractNum cTAbstractNum = cTNumbering.getAbstractNumArray(0);
XWPFAbstractNum abstractNum = new XWPFAbstractNum(cTAbstractNum);
BigInteger abstractNumID = numbering.addAbstractNum(abstractNum);
BigInteger numID = numbering.addNum(abstractNumID);
XWPFStyles styles = document.createStyles();
CTStyles cTStyles = CTStyles.Factory.parse(cTStyleNormal);
CTStyle cTStyle = cTStyles.getStyleArray(0);
styles.addStyle(new XWPFStyle(cTStyle));
cTStyles = CTStyles.Factory.parse(cTStyleH1XML);
cTStyle = cTStyles.getStyleArray(0);
styles.addStyle(new XWPFStyle(cTStyle));
cTStyles = CTStyles.Factory.parse(cTStyleH2XML);
cTStyle = cTStyles.getStyleArray(0);
styles.addStyle(new XWPFStyle(cTStyle));
cTStyles = CTStyles.Factory.parse(cTStyleH3XML);
cTStyle = cTStyles.getStyleArray(0);
styles.addStyle(new XWPFStyle(cTStyle));
cTStyles = CTStyles.Factory.parse(cTStyleTOC1);
cTStyle = cTStyles.getStyleArray(0);
styles.addStyle(new XWPFStyle(cTStyle));
cTStyles = CTStyles.Factory.parse(cTStyleTOC2);
cTStyle = cTStyles.getStyleArray(0);
styles.addStyle(new XWPFStyle(cTStyle));
createParagraphs(document, numID,
new String[] {"First Level",
"Second Level",
"First Level",
"Second Level",
"Third Level",
"Second Level",
"Third Level",
"Second Level",
"First Level"}
);
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run=paragraph.createRun();
run.setText("Table of contents:");
paragraph = document.createParagraph();
CTSimpleField toc = paragraph.getCTP().addNewFldSimple();
toc.setInstr("TOC \* MERGEFORMAT");
toc.setDirty(STOnOff.TRUE);
FileOutputStream out = new FileOutputStream("CreateWordNumberedHeadings.docx");
document.write(out);
out.close();
document.close();
}
public static void createParagraphs(XWPFDocument doc, BigInteger numID, String[] content) {
for (String value : content) {
XWPFParagraph para = doc.createParagraph();
para.setVerticalAlignment(TextAlignment.CENTER);
para.setNumID(numID);
para.setStyle("Heading1");
if (value.contains("Second")) {
para.getCTP().getPPr().getNumPr().addNewIlvl().setVal(BigInteger.valueOf(1));
para.setStyle("Heading2");
}
if(value.contains("Third")) {
para.getCTP().getPPr().getNumPr().addNewIlvl().setVal(BigInteger.valueOf(2));
para.setStyle("Heading3");
}
XWPFRun run = para.createRun();
run.setText(value);
para = doc.createParagraph();
run = para.createRun();
run.setText("Lorem ipsum semit dolor ...");
run.addBreak(BreakType.PAGE);
}
}
}
Note: I do not use XWPFDocument.createTOC()
for mentioned reasons. Instead I am inserting a field which must be refreshed while opening the document in Word
. This leads to a confirm dialog while opening which must be answered with Yes
.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…