Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
487 views
in Technique[技术] by (71.8m points)

java - Creating a Table of Contents for a XWPFDocument with page numbers' indication

I am actually generating a Word Document with Apache POI, and I need to automatically create a Table of Contents (TOC) that references the paragraphs, with their page's indication.

This is the code I am using (I omit preconditions and internal methods' body):

XWPFDocument doc = new XWPFDocument(OPCPackage.openOrCreate(new File(document)));

String strStyleId = "Index Style";
addCustomHeadingStyle(doc, strStyleId, 1);

XWPFParagraph documentControlHeading = doc.createParagraph();
changeText(documentControlHeading, "First try");
documentControlHeading.setAlignment(ParagraphAlignment.LEFT);
documentControlHeading.setPageBreak(true);
documentControlHeading.setStyle(strStyleId);

XWPFParagraph documentControlHeading1 = doc.createParagraph();
changeText(documentControlHeading1, "Second try");
documentControlHeading1.setAlignment(ParagraphAlignment.LEFT);
documentControlHeading1.setPageBreak(true);
documentControlHeading1.setStyle(strStyleId);

doc.createTOC();

When I open the resulting document, I am getting this result (see blue squares):

enter image description here

In the left part, I can see the generated TOC. So far, so good. In the document's body, however, I can just see a static text "Table of Contents", with no indications at all (neither paragraphs nor pages). I cannot even interact with it.

If I'd click on the menu entry "Table of Contents" (red square on the upper-left corner), the "real" Table of Content that I want is being generated (follow the arrow, of course...).

My question is: how can I achieve the second result (red TOC) from code?

Thank you so much.

Side note: I even tried putting doc.enforceUpdateFields(); after doc.createTOC();, but every reference of the TOC disappears, this way.

@Sucy, I add the methods that you requested. Don't know if you can find them useful, though:

/*
 * Adds a custom style with the given indentation level at the given document.
 */
private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {

    CTStyle ctStyle = CTStyle.Factory.newInstance();
    ctStyle.setStyleId(strStyleId);

    CTString styleName = CTString.Factory.newInstance();
    styleName.setVal(strStyleId);
    ctStyle.setName(styleName);

    CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
    indentNumber.setVal(BigInteger.valueOf(headingLevel));

    // lower number > style is more prominent in the formats bar
    ctStyle.setUiPriority(indentNumber);

    CTOnOff onoffnull = CTOnOff.Factory.newInstance();
    ctStyle.setUnhideWhenUsed(onoffnull);

    // style shows up in the formats bar
    ctStyle.setQFormat(onoffnull);

    // style defines a heading of the given level
    CTPPr ppr = CTPPr.Factory.newInstance();
    ppr.setOutlineLvl(indentNumber);
    ctStyle.setPPr(ppr);

    XWPFStyle style = new XWPFStyle(ctStyle);

    // is a null op if already defined
    XWPFStyles styles = docxDocument.createStyles();

    style.setType(STStyleType.PARAGRAPH);
    styles.addStyle(style);

}

/*
 * Changes the text of a given paragraph.
 */
public static void changeText(XWPFParagraph p, String newText) {
    if (p != null) {
        List<XWPFRun> runs = p.getRuns();
        for (int i = runs.size() - 1; i >= 0; i--) {
            p.removeRun(i);
        }

        if (runs.size() == 0) {
            p.createRun();
        }

        XWPFRun run = runs.get(0);
        run.setText(newText, 0);
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The XWPF classes as you have seen are a work in progress, with no real overarching architecture. That will change over time as we work on it, but in the mean time you can try to add a simple TOC field to a paragraph in this way.

XWPFParagraph p;
...
// get or create your paragraph
....
CTP ctP = p.getCTP();
CTSimpleField toc = ctP.addNewFldSimple();
toc.setInstr("TOC \h");
toc.setDirty(STOnOff.TRUE);

This will create a Table of contents with hyperlinks to the pages, it should be recalculated when Word opens it, and the table of contents will be based on predefined HeaderX styles.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...