【问题标题】:Apache POI Table of contents not updatingApache POI 目录未更新
【发布时间】:2016-09-24 01:38:54
【问题描述】:

我正在使用 Apache POI XWPF 组件和 java,将 .xml 文件中的数据提取到 word 文档中。到目前为止一切顺利,但我正在努力创建一个目录。我必须在方法开始时创建一个目录,然后在最后更新它以获取所有新标题。目前我使用 doc.createTOC(),其中 doc 是从 XWPFDocument 创建的变量,在开始时创建表,然后我使用 doc.enforceUpdateFields() 来更新文档末尾的所有内容。但是当我运行程序后打开文档时,目录是空的,但导航面板确实包含我指定的一些标题。

评论建议我包含一些代码。所以我首先从模板创建文档:

XWPFDocument doc = new XWPFDocument(new FileInputStream("D://Template.docx"));

然后我创建一个目录:

doc.createTOC();

然后在整个方法中,我将标题添加到文档中:

XWPFParagraph documentControlHeading = doc.createParagraph();
documentControlHeading.setPageBreak(true);
documentControlHeading.setAlignment(ParagraphAlignment.LEFT);
documentControlHeading.setStyle("Tier1Header");

添加所有标题后,我想更新文档,以便所有新标题都出现在目录中。我使用以下命令进行此购买:

doc.enforceUpdateFields();

【问题讨论】:

  • 给我们一个显示问题的精简版代码,然后也许有人可以提供帮助。
  • 嗨。我在最初的问题中添加了一些代码,希望对您有所帮助。

标签: java ms-word apache-poi tableofcontents


【解决方案1】:

嗯...我正在查看createTOC() 方法代码,它似乎在寻找看起来像Heading # 的样式。所以Tier1Header 不会被发现。尝试先创建文本,然后使用 Heading 1 之类的样式作为标题。然后使用createTOC() 添加目录。它应该在创建 TOC 时找到所有标题。不知道enforceUpdateFields()会不会影响TOC。

【讨论】:

  • 嗨。谢谢你的评论。它可以工作,但目录现在位于文档的末尾。有什么方法可以指定 TOC 的生成位置吗? enforceUpdateFields() 确实适用于 TOC,但它只在导航面板中更新它,而不是在 word 文档本身中。
  • 对不起,这里不知道答案,杂草丛生,没时间去挖源头找。 Word 文档在 POI 中是一种额外的东西。而且我不知道现在是否有任何提交者在做这件事。 HWPF 甚至没有办法做一个 TOC。如果createToc() 方法返回目录会更容易,因此您可以在必要时自己添加行。但它不是自动的。
【解决方案2】:

//您的 docx 模板应包含以下或类似的文本//将被搜索并替换为 WORD TOC。

//${TOC}

public static void main(String[] args) throws IOException, OpenXML4JException {
        XWPFDocument docTemplate = null;
        try {
            File file = new File(PATH_TO_FILE); //"C:\\Reports\\Template.docx";
            FileInputStream fis = new FileInputStream(file);
            docTemplate = new XWPFDocument(fis);
             generateTOC(docTemplate);
            saveDocument(docTemplate);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (docTemplate != null) {
                docTemplate.close();
            }
        }
    }   

private static void saveDocument(XWPFDocument docTemplate) throws FileNotFoundException, IOException {
    FileOutputStream outputFile = null;
    try {
        outputFile = new FileOutputStream(OUTFILENAME);
        docTemplate.write(outputFile);
    } finally {
        if (outputFile != null) {
            outputFile.close();
        }
    }
}


public static void generateTOC(XWPFDocument document) throws InvalidFormatException, FileNotFoundException, IOException {
        String findText = "${TOC}";
        String replaceText = "";
        for (XWPFParagraph p : document.getParagraphs()) {
            for (XWPFRun r : p.getRuns()) {
                int pos = r.getTextPosition();
                String text = r.getText(pos);
                if (text != null && text.contains(findText)) {
                    text = text.replace(findText, replaceText);
                    r.setText(text, 0);
                    addField(p, "TOC \\o \"1-3\" \\h \\z \\u");
                    break;
                }
            }
        }
    }

private static void addField(XWPFParagraph paragraph, String fieldName) {
    CTSimpleField ctSimpleField = paragraph.getCTP().addNewFldSimple();
    // ctSimpleField.setInstr(fieldName + " \\* MERGEFORMAT ");
    ctSimpleField.setInstr(fieldName);
    ctSimpleField.addNewR().addNewT().setStringValue("<<fieldName>>");
}

【讨论】:

  • 更新:在保存方法之前添加以下行:docTemplate.enforceUpdateFields();
【解决方案3】:

这是createTOC()的代码,通过检查XWPFDocument.class得到:

public void createTOC() {
    CTSdtBlock block = getDocument().getBody().addNewSdt();
    TOC toc = new TOC(block);
    for (XWPFParagraph par : this.paragraphs) {
        String parStyle = par.getStyle();
        if ((parStyle != null) && (parStyle.startsWith("Heading"))) try {
            int level = Integer.valueOf(parStyle.substring("Heading".length())).intValue();
            toc.addRow(level, par.getText(), 1, "112723803");
        } catch (NumberFormatException e) {
            e.printStackTrace();
        }
    }
}

如您所见,它将所有样式命名为“HeadingX”的段落添加到目录中,其中 X 是一个数字。但是,不幸的是,这还不够。事实上,该方法在其实现中存在错误/不完整。

传递给addRow() 的页码始终是1,甚至没有计算出来。 因此,最后,您将获得一个目录,其中包含所有段落和尾随点,以提供适当的缩进,但页面将始终等于“1”。


编辑 ...但是,有一个解决方案here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-23
    • 2017-12-13
    • 2015-11-23
    • 1970-01-01
    • 2017-06-20
    相关资源
    最近更新 更多