2016-10-24 7 views
0

Я пытаюсь использовать библиотеку Apache POI XWPF для создания отчета в файле docx Word.Apache POI: Как перезапустить нумерацию в нумерованном списке в текстовом документе?

Мой подход заключается в использовании существующего Word Document в качестве шаблона стилей. В шаблоне я определил стиль с именем «SRINumberList».

Так, чтобы загрузить шаблон и удалить все, что это не в колонтитул:

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. Это типичный способ я это делаю:

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 ... однако, как много элементов списка выходят в документе). Например:

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 

Поэтому в основном я пытаюсь выяснить, как использовать этот стиль у меня есть, но перезагружать Нумерация страниц различных мест в документе. Может ли кто-нибудь предоставить образец того, как это будет работать?

ответ

0

С некоторой помощью от keil. Я понял решение. Я разместил здесь полный рабочий образец: https://github.com/jimklo/apache-poi-sample

Фокус в том, что вам нужно ссылаться на стиль AbstractNum нумерации, определенный в документе, при создании нового Num, который перезапускает нумерацию.

Вот основные моменты, однако ключ должен был определить, что представляет собой идентификатор AbstractNum для стиля внутри документа. Кажется, это печально, что, поскольку это всего лишь XML-документ, нет никакого способа перечислить существующие Num и AbstractNum. Если есть, я хотел бы узнать, как это сделать.

/** 
* 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); 
    } 

} 

Теперь, когда мы имеем отображение от стиля к AbstractNum, мы можем создать новый Num, который перезапускает через LvlOverride и 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; 
} 

И теперь вы можете просто применить этот номер к списку, который вы создаете.

/** 
* 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.

0

Единственный способ, которым я нашел, - переопределить уровень в CTNum. Другой способ может заключаться в создании множества новых абстрактных нумераций/стилей, но при открытии документа это будет стоить очень много элементов стиля.

ArrayList<String> list = new ArrayList<String>(); 
list.add("SubItem 1"); 
list.add("SubItem 2"); 
list.add("SubItem 3"); 

XWPFNumbering numbering = document.getNumbering(); 
XWPFAbstractNum numAbstract = numbering.getAbstractNum(BigInteger.ONE); 

for (Integer nx = 1; nx < 3; nx++) { 
    XWPFParagraph p = document.createParagraph(); 
    XWPFRun run = p.createRun(); 
    run.setText("Items " + nx.toString()); 
    //leveloverride (start the new numbering) 
    BigInteger numId = numbering.addNum(numAbstract.getAbstractNum().getAbstractNumId()); 
    XWPFNum num = numbering.getNum(numId); 
    CTNumLvl lvloverride = num.getCTNum().addNewLvlOverride(); 
    lvloverride.setIlvl(BigInteger.ZERO); 
    CTDecimalNumber number = lvloverride.addNewStartOverride(); 
    number.setVal(BigInteger.ONE); 

    for (String item : list) { 
     XWPFParagraph p2 = document.createParagraph(); 
     p2.setNumID(num.getCTNum().getNumId()); 
     CTNumPr numProp = p2.getCTP().getPPr().getNumPr(); 
     numProp.addNewIlvl().setVal(BigInteger.ZERO); 

     XWPFRun run2 = p2.createRun(); 
     run2.setText(item); 
    } 
} 
+0

это близко ... он, конечно, перезапускает числа, но не перезапускает только любой список. то есть, если у меня есть альфа-список, я бы хотел, чтобы он перезапустился на «a». – Jim