首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用POI v5在Word中创建嵌套的项目列表

使用POI v5在Word中创建嵌套的项目列表
EN

Stack Overflow用户
提问于 2022-01-04 17:27:48
回答 1查看 347关注 0票数 0

我在Java中工作,使用以下Maven依赖项(以及其他依赖项):

代码语言:javascript
复制
  <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
  <dependencies>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
        <version>5.0.0</version>
    </dependency>
  </dependencies>

下面的课是从另一篇这样的文章中收集到的:

代码语言:javascript
复制
import java.io.FileOutputStream;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;

import org.apache.poi.xwpf.usermodel.XWPFAbstractNum;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFNumbering;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTLvl;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STNumberFormat;

public class CreateSimpleWordBulletList
{

  public static void main(String[] args) throws Exception
  {

    CTAbstractNum cTAbstractNum = CTAbstractNum.Factory.newInstance();
    
    // Next we set the AbstractNumId. This requires care.
    // Since we are in a new document we can start numbering from 0.
    // But if we have an existing document, we must determine the next free
    // number first.
    cTAbstractNum.setAbstractNumId(BigInteger.valueOf(0));

    // Bullet list
    CTLvl cTLvl = cTAbstractNum.addNewLvl();
    cTLvl.addNewNumFmt().setVal(STNumberFormat.BULLET);
    cTLvl.addNewLvlText().setVal("•");

    XWPFAbstractNum abstractNum = new XWPFAbstractNum(cTAbstractNum);
    XWPFDocument document = new XWPFDocument();
    XWPFNumbering numbering = document.createNumbering();

    BigInteger abstractNumID = numbering.addAbstractNum(abstractNum);
    BigInteger numID = numbering.addNum(abstractNumID);

    XWPFParagraph paragraph = document.createParagraph();

    XWPFRun run = paragraph.createRun();
    run.setText("A list having defined gap between bullet point and text:");

    ArrayList<String> documentList = new ArrayList<String>(Arrays.asList(new String[] { "One", "Two", "Three" }));
    for (String string : documentList)
    {
      paragraph = document.createParagraph();
      paragraph.setNumID(numID);
      // set indents in Twips (twentieth of an inch point, 1440 Twips = 1 inch
      paragraph.setIndentFromLeft(1440 / 4); // indent from left 360 Twips = 1/4
                                             // inch
      paragraph.setIndentationHanging(1440 / 4); // indentation hanging 360
                                                 // Twips = 1/4 inch
                                                 // so bullet point hangs 1/4
                                                 // inch before the text at
                                                 // indentation 0
      run = paragraph.createRun();
      run.setText(string);
    }

    paragraph = document.createParagraph();

    FileOutputStream out = new FileOutputStream("CreateWordSimplestBulletList.docx");
    document.write(out);
    out.close();
    document.close();

  }
}

这会像我想要的那样创建一个弹出列表;我希望缩进它,但这是次要的。

我需要对其进行的真正修改是再添加两个级别的列表,以便在Word文档中得到类似于以下内容的结果:

代码语言:javascript
复制
* One
    - AAA
        o aaa
        o bbb
        o ccc
    - BBB
        o xyz
        o abc
* Two
    - AAA
        o mmm
        o nnn
    - ZZZ
        o bbb
        o nnn

等。

我希望没有必要有人为此为我编写代码,但我不理解也没有找到任何关于CTAbstractNumCTLvlXWPF*类的文档。如果有足够的文档,那么有人就可以指出这一点。

我从这里的其他评论中了解到,CTAbstractNum.setAbstractNumId()中的值集标识了整个编号级别的文档,因此它应该应用于最外层的所有项目,而在概念上,另一个这样的ID将应用于每个项目中相同级别的所有项目(例如,上图中的'aaa‘、'bbb’、'ccc‘字符串。我猜会创建不同的I并应用于每个这样的内部列表。但是,当我对API的概念模型一无所知时,我讨厌猜测这一点。试错编程是如此的无聊。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-05 11:13:35

我已经为如何创建字号提供了多个答案。也适用于如何创建多级编号。例如:Apache多行子弹点是工作的,但不是多个副翼?我如何添加列表在poi字,序号或其他符号的列表符号?

但是当你也在要求文件的时候,我会试图对此做出更多的解释。

现代Word文档(*.docx)正在使用Office Open XML文件格式。该格式最初由Ecma (作为ECMA-376)和ISO和IEC (作为ISO/IEC 29500)在以后的版本标准化。它是一个包含XML和特殊目录结构中的其他文件的ZIP归档文件。因此,您可以轻松地解压缩*.docx文件并查看其内部结构。

基于这些标准,apacheorg.openxmlformats.schemas类中开发了XML。直到apache poi版本4,这些类都是在ooxml-模式中提供的。从apache poi版本5上看,它们都在poi-ooxml-满中。还有一个poi-ooxml-lite版本。但是这只包含那些被高级apache poi类使用的bean。因此,当涉及到更特殊的用例时,它缺乏一些bean。

不幸的是,没有公共的org.openxmlformats.schemas类文档。但是,当然我们可以下载这些源代码,并从这些源中执行javadoc,以便至少具有API文档。

XWPFapache poi对Microsoft使用的Office部分的高级实现。它使用org.openxmlformats.schemas bean来实现更方便的方法。它在https://poi.apache.org/Apache POI - Javadocs快速指南中有文档。但是XWPF至今还没有包含Microsoft的所有可能性和特性。因此,对于一些特殊的用例,需要了解XML和org.openxmlformats.schemas bean的使用情况。

因为*.docx只是一个ZIP存档,所以最方便的方法是使用Microsoft创建一个简单的*.docx文件,然后解压缩*.docx以获得创建的*.docx。然后尝试使用XWPForg.openxmlformats.schemas bean重新创建XML。

当谈到编号时,人们会发现在/word/numbering.xml ZIP归档文件中有一个*.docx,它包含用于编号定义的XML。每个定义都包含一个包含该定义的abstractNum,即使对于多个缩进级别的编号和链接到该abstractNumnum也是如此。num有一个numId,它在/word/document.xml中用于标记枚举中包含的段落。这些段落还可能有一个ilv (缩进级别),它显示了它们在枚举中的深度。

XWPF不完全提供在编号中创建abstractNum的所有功能。它提供XWPFAbstractNum,它有一个接受org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum的构造函数。因此,需要使用低级别bean创建CTAbstractNum。最简单的方法是根据String提供的XML创建它。XML可以通过创建一个简单的*.docx文件,其中包含使用Microsoft本身的编号,然后解压缩*.docx ZIP存档。

如果一个人能够读取XML,那么这个XML将是自我解释。这些元素有很好的名称。我们需要知道的是,缩进和悬挂的测量单位是twips (二十英寸点)。而且,用于符号点的符号一次来自附加的Windows字体符号和/或Wingdings。然后,还需要在XML中设置这些字体。这些值是ASCII值,它使用这些特殊字体的特殊符号。

下面的完整示例说明了这一点。它创建显示的枚举,一次作为项目列表,一次作为编号列表。

代码语言:javascript
复制
import java.io.FileOutputStream;

import org.apache.poi.xwpf.usermodel.*;

import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTAbstractNum;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTNumbering;

import java.math.BigInteger;

import java.util.Map; 
import java.util.TreeMap; 

public class CreateWordMultilevelLists {

 static String cTAbstractNumBulletXML = 
  "<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=\"bullet\"/><w:lvlText w:val=\"\uF0B7\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"720\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Symbol\" w:hAnsi=\"Symbol\" w:hint=\"default\"/></w:rPr></w:lvl>"
+ "<w:lvl w:ilvl=\"1\" w:tentative=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:lvlText w:val=\"\u2013\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"1440\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Courier New\" w:hAnsi=\"Courier New\" w:cs=\"Courier New\" w:hint=\"default\"/></w:rPr></w:lvl>"
+ "<w:lvl w:ilvl=\"2\" w:tentative=\"1\"><w:start w:val=\"1\"/><w:numFmt w:val=\"bullet\"/><w:lvlText w:val=\"\u26Ac\"/><w:lvlJc w:val=\"left\"/><w:pPr><w:ind w:left=\"2160\" w:hanging=\"360\"/></w:pPr><w:rPr><w:rFonts w:ascii=\"Courier New\" w:hAnsi=\"Courier New\" w:hint=\"default\"/></w:rPr></w:lvl>"
+ "</w:abstractNum>";   

 static String cTAbstractNumDecimalXML = 
  "<w:abstractNum xmlns:w=\"http://schemas.openxmlformats.org/wordprocessingml/2006/main\" w:abstractNumId=\"1\">"
+ "<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=\"720\" 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=\"1440\" 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=\"2160\" w:hanging=\"360\"/></w:pPr></w:lvl>"
+ "</w:abstractNum>";

 static BigInteger createNumbering(XWPFDocument document, String abstractNumXML) throws Exception {
  CTNumbering cTNumbering = CTNumbering.Factory.parse(abstractNumXML);
  CTAbstractNum cTAbstractNum = cTNumbering.getAbstractNumArray(0);
  XWPFAbstractNum abstractNum = new XWPFAbstractNum(cTAbstractNum);
  XWPFNumbering numbering = document.createNumbering();
  BigInteger abstractNumID = numbering.addAbstractNum(abstractNum);
  BigInteger numID = numbering.addNum(abstractNumID);
  return numID;
 }
 
 static void setIndentLevel(XWPFParagraph paragraph, BigInteger level) {
  if (paragraph.getCTP().isSetPPr()) {
   if (paragraph.getCTP().getPPr().isSetNumPr()) {
    if (paragraph.getCTP().getPPr().getNumPr().isSetIlvl()) {
     paragraph.getCTP().getPPr().getNumPr().getIlvl().setVal(level);
    } else {
     paragraph.getCTP().getPPr().getNumPr().addNewIlvl().setVal(level);
    }
   }
  }
 }
 
 static BigInteger getIndentLevelFromNumberingString(String numberingString) {
  String[] levels = numberingString.split("\\.");
  int level = levels.length -1;
  return BigInteger.valueOf(level);
 }
 
 static void insertListContent(XWPFDocument document, TreeMap<String, String> listContent, BigInteger numID) {
  for (Map.Entry<String, String> entry : listContent.entrySet()) {
   String key = entry.getKey();
   String value = entry.getValue();
   XWPFParagraph paragraph = document.createParagraph();
   paragraph.setNumID(numID);
   setIndentLevel(paragraph, getIndentLevelFromNumberingString(key));
   XWPFRun run = paragraph.createRun();
   run.setText(value); 
   if (!entry.equals(listContent.lastEntry())) paragraph.setSpacingAfter(0);
  } 
 }

 public static void main(String[] args) throws Exception {
     
  TreeMap<String, String> listContent = new TreeMap<String, String>();
  listContent.put("1", "One");
  listContent.put("1.1", "AAA");
  listContent.put("1.1.1", "aaa");
  listContent.put("1.1.2", "bbb");
  listContent.put("1.1.3", "ccc");
  listContent.put("1.2", "BBB");
  listContent.put("1.2.1", "xyz");
  listContent.put("1.2.2", "abc");
  listContent.put("2", "Two");
  listContent.put("2.1", "AAA");
  listContent.put("2.1.1", "mmm");
  listContent.put("2.1.2", "nnn");
  listContent.put("2.2", "ZZZ");
  listContent.put("2.2.1", "bbb");
  listContent.put("2.2.2", "nnn");
  
  XWPFDocument document = new XWPFDocument();
  
  BigInteger numIDBulletList = createNumbering(document, cTAbstractNumBulletXML);
  BigInteger numIDDecimalList = createNumbering(document, cTAbstractNumDecimalXML);
  
  XWPFParagraph paragraph = document.createParagraph();
  XWPFRun run=paragraph.createRun();  
  run.setText("The bullet list:");
  
  insertListContent(document, listContent, numIDBulletList);
  
  paragraph = document.createParagraph();
  run=paragraph.createRun();  
  run.setText("Paragraph after the list.");
  
  paragraph = document.createParagraph();
  run=paragraph.createRun();  
  run.setText("The decimal list:");
  
  insertListContent(document, listContent, numIDDecimalList);
  
  paragraph = document.createParagraph();
  run=paragraph.createRun();  
  run.setText("Paragraph after the list.");

  FileOutputStream out = new FileOutputStream("./CreateWordMultilevelLists.docx");    
  document.write(out);
  out.close();
  document.close();

 }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70582769

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档