Apache POI:如何在Word文档中的编号列表上重新开始编号? [英] Apache POI: How do you restart numbering on a numbered list in word document?

查看:1468
本文介绍了Apache POI:如何在Word文档中的编号列表上重新开始编号?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Apache POI XWPF库在Word docx文件中生成报告.

I'm trying to use Apache POI XWPF library to produce a report in a Word docx file.

我的方法是使用现有的Word文档作为样式模板.在模板中,我定义了一种名为"SRINumberList"的样式.

My approach is to use an existing Word Document as a Styles template. Within the template I defined a style named "SRINumberList".

因此,要加载模板并删除页眉或页脚中不存在的所有内容,

So to load the template and remove everything that's not in the Header or Footer:

protected void createDocFromTemplate() {
    try {
        document = new XWPFDocument(this.getClass().getResourceAsStream(styleTemplate));


        int pos = document.getBodyElements().size()-1;

        while (pos >= 0) {
            IBodyElement element = document.getBodyElements().get(pos);
            if (!EnumSet.of(BodyType.HEADER, BodyType.FOOTER).contains(element.getPartType())) {
                boolean success = document.removeBodyElement(pos);
                logger.log(Level.INFO, "Removed body element "+pos+": "+success);
            }
            pos--;
        }

    } catch (IOException e) {
        logger.log(Level.WARNING, "Not able to load style template", e);
        document = new XWPFDocument();
    }

}

现在我的文档中有几个不同的部分,其中包含一个编号列表.每个都应该从1开始重新编号.这是我这样做的典型方式:

Now within my document there are several different sections that contain a numbered lists. Each should be restart numbering from 1. This is the typical way I'm doing this:

if (itemStem.getItems().size() > 0) {
        p = document.createParagraph();
        p.setStyle(ParaStyle.StemAndItemTitle.styleId);
        final BigInteger bulletNum = newBulletNumber();

        run = p.createRun();
        run.setText("Sub Items");

        itemStem.getItems().stream().forEach(item -> {
            XWPFParagraph p2 = document.createParagraph();
            p2.setStyle(ParaStyle.NumberList.styleId);

            XWPFRun run2 = p2.createRun();
            run2.setText(item.getSubItemText());
        });
        p = document.createParagraph();
        p.createRun();
}

因此,这正确地应用了包含数字格式的样式,但是只有一个序列(对于文档中退出的许多列表项,只有1个序列).例如:

So this correctly applies the Style that contains the number format, but there is only a single sequence (1 ... to however many list items exit in the doc). For example:

Heading 1
1. item a
2. item b
3. item c

Heading 2
4. item a
5. item d
6. item g

但是我想要的是:

Heading 1
1. item a
2. item b
3. item c

Heading 2
1. item a
2. item d
3. item g

因此,基本上,我试图弄清楚如何使用我拥有的样式,但是要重新开始为文档中的各个位置编号.有人可以提供此方法的示例吗?

So basically I'm trying to figure out how to use the style I have but restart page numbering a various spots in the document. Can someone provide a sample of how this would work?

推荐答案

keil 的帮助下.我想出了解决方案.我在此处发布了完整的工作示例: https://github.com/jimklo/apache- poi-sample

With some help from keil. I figured out the solution. I've posted a full working sample here: https://github.com/jimklo/apache-poi-sample

诀窍在于,在创建重新启动编号的新Num时,您需要引用文档中定义的Numbering样式的AbstractNum.

The trick is that you need to reference the the AbstractNum of the Numbering style defined in the document when creating a new Num that restarts the numbering.

这里是要点,但是关键是必须确定文档内Style的AbstractNum ID是什么.似乎不幸的是,鉴于这只是一个XML文档,所以无法通过某种方式枚举现有的Num和AbstractNum.如果有的话,我很想知道这样做的方法.

Here are the highlights, however the key was having to determine what the AbstractNum ID is for the Style inside the document. It's seems unfortunate, that given this is just an XML doc, that there isn't some way to enumerate the existing Num's and AbstractNum's. If there is, I'd love to know the way to do that.

/**
 * first discover all the numbering styles defined in the template.
 * a bit brute force since I can't find a way to just enumerate all the
 * abstractNum's inside the numbering.xml
 */
protected void initNumberingStyles() {
    numbering = document.getNumbering();

    BigInteger curIdx = BigInteger.ONE;
    XWPFAbstractNum abstractNum;

    while ((abstractNum = numbering.getAbstractNum(curIdx)) != null) {
        if (abstractNum != null) {
            CTString pStyle = abstractNum.getCTAbstractNum().getLvlArray(0).getPStyle();
            if (pStyle != null) {
                numberStyles.put(pStyle.getVal(), abstractNum);
            }
        }
        curIdx = curIdx.add(BigInteger.ONE);
    }

}

现在我们有了从Style到AbstractNum的映射,我们可以创建一个新的Num,它通过LvlOverride和StartOverride重新启动.

Now that we have a mapping from the Style to the AbstractNum, we can create a new Num that restarts via a LvlOverride and StartOverride.

/**
 * This creates a new num based upon the specified numberStyle
 * @param numberStyle
 * @return
 */
private XWPFNum restartNumbering(String numberStyle) {
    XWPFAbstractNum abstractNum = numberStyles.get(numberStyle);
    BigInteger numId = numbering.addNum(abstractNum.getAbstractNum().getAbstractNumId());
    XWPFNum num = numbering.getNum(numId);
    CTNumLvl lvlOverride = num.getCTNum().addNewLvlOverride();
    lvlOverride.setIlvl(BigInteger.ZERO);
    CTDecimalNumber number = lvlOverride.addNewStartOverride();
    number.setVal(BigInteger.ONE);
    return num;
}

现在您可以将NumID应用于要创建的列表.

And now you can just apply that NumID to the list you're creating.

/**
 * This creates a five item list with a simple heading, using the specified style..
 * @param index
 * @param styleName
 */
protected void createStyledNumberList(int index, String styleName) {
    XWPFParagraph p = document.createParagraph();
    XWPFRun run = p.createRun();
    run.setText(String.format("List %d: - %s", index, styleName));

    // restart numbering
    XWPFNum num = restartNumbering(styleName);

    for (int i=1; i<=5; i++) {
        XWPFParagraph p2 = document.createParagraph();

        // set the style for this paragraph
        p2.setStyle(styleName);

        // set numbering for paragraph
        p2.setNumID(num.getCTNum().getNumId());
        CTNumPr numProp = p2.getCTP().getPPr().getNumPr();
        numProp.addNewIlvl().setVal(BigInteger.ZERO);

        // set the text
        XWPFRun run2 = p2.createRun();
        run2.setText(String.format("Item #%d using '%s' style.", i, styleName));
    }

    // some whitespace
    p = document.createParagraph();
    p.createRun();

}

同样,总的来说,如果没有 keil 提供的指针,我将无法弄清楚.

Again, overall I wouldn't have figured this out without the pointer that keil provided.

这篇关于Apache POI:如何在Word文档中的编号列表上重新开始编号?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆