前言: 此文档简单记述在使用docx4j进行编程式生成文档元素的个人心得,故存在理解有误之处,还请指正!
- 该项目是基于docx文档的xml结构,进行标签对象的赋值与取值,因此,当生成部分不常见元素时(比如无序项目编码时),可以参考xml文件中的属性,进行编码实现。
-
比如文档中插入小标题,即文本添加导航功能:
文档内容如下:
-
对应解压文件
document.xml 即文档xml结构内容,styles.xml即为样式文件 -
document.xml内容
val是style中的样式id,那么对用的style.xml文件内容如下:
<w:outlinelvl>标签将样式与导航窗格绑定,它指定了样式的大纲视图层级,val属性的值代表的是层级。
那如何实现为文本增加标题导航?
首先,我们需要定义一个样式:WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); //创建docx4j工厂 ObjectFactory factory = Context.getWmlObjectFactory(); //获得word包中document.xml文件内容 MainDocumentPart main = wordMLPackage.getMainDocumentPart(); //获得styles.xml文件内容 StyleDefinitionsPart sdp = main.getStyleDefinitionsPart(); //创建一个样式标签 Style style = factory.createStyle(); //设置样式标签的type属性 style.setType("paragraph"); //新建name标签 Name name = new Name(); //设置name标签的val属性 name.setVal("test"); //将设置好的name标签设置到样式标签中 style.setName(name); //设置样式标签的id属性 style.setStyleId("test"); //创建段落格式标签 PPr ppr = factory.createPPr(); //创建大纲级别标签 OutlineLvl lvl = new OutlineLvl(); //设置大纲级别标签的val属性为0 lvl.setVal(BigInteger.valueOf(0)); //将设置好的大纲级别标签设置到段落格式标签中 ppr.setOutlineLvl(lvl); //将设置好的段落格式标签设置到样式标签中 style.setPPr(ppr); //将设置好的段落标签加入到styles.xml文件中 sdp.getContents().getStyle().add(style); //将创建的样式,添加到段落中 //获得document.xml文件下body标签内容 Body body = main.getContents().getBody(); //创建段落标签 P p = factory.createP(); //创建段落格式标签 PPr pPr = factory.createPPr(); //创建段落样式标签 PStyle ps = new PStyle(); //设置段落样式标签的val属性值为前面创建的样式id ps.setVal("Heading1"); //将设置好的段落样式标签设置到段落格式标签中 pPr.setPStyle(ps); //将设置好的段落格式标签设置到段落标签中 p.setPPr(pPr); //创建r标签 R run = factory.createR(); //创建t标签 Text t = factory.createText(); //设置t标签内的内容 t.setValue("测试内容"); //将设置好的t标签设置到r标签中 run.getContent().add(t); //将设置好的r标签设置到段落标签中 p.getContent().add(run); //将设置好的段落标签加入body标签中 body.getContent().add(p); //设置word文档要存放的文件 File file = new File("保存路径"); //将设置好的word包保存到指定文件中 wordMLPackage.save(file);
-
测试结果
-
- 如何理解项目中P与R
P是文本顶级标签,在xml中与文本有关结构(比如,项目符号)都需要该标签,因此可以嵌到其他标签中去,但是其它标签很难相互嵌套。它有两个重要的子标签,rPr设置文本属性,比如字体、颜色、下划线等,pPr设置P的样式,比如缩进等。它们的关系可以总结为:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GFOZcpLS-1631796377060)(vx_images/4915000242393.png)]
R是理解为混合数据类型,这里可以作为一段文本对象,接受text和rPR等关于文本一切的属性设置,这样可以在段落中,设置不同样式的文本,最后都装载到P中。 - 如何实现一般的项目符号,这里只举例数字编号和原点符号,其它特殊符号实现尚不得知。
private static void createBulletedItem(MainDocumentPart wordMLPackage,
String info) throws InvalidFormatException, JAXBException {
NumberingDefinitionsPart ndp = new NumberingDefinitionsPart();
wordMLPackage.addTargetPart(ndp);
ndp.unmarshalDefaultNumbering();
//必须加载上述信息
ObjectFactory factory = new org.docx4j.wml.ObjectFactory();
P p = factory.createP();
org.docx4j.wml.Text t1 = factory.createText();
t1.setValue(info);
org.docx4j.wml.R run = factory.createR();
run.getContent().add(t1);
org.docx4j.wml.PPr ppr = factory.createPPr();
p.setPPr(ppr);
// Create and add <w:numPr>
PPrBase.NumPr numPr = factory.createPPrBaseNumPr();
ppr.setNumPr(numPr);
// The <w:ilvl> element
PPrBase.NumPr.Ilvl ilvlElement = factory.createPPrBaseNumPrIlvl();
numPr.setIlvl(ilvlElement);
ilvlElement.setVal(BigInteger.valueOf(0));
// 查阅了相关英文文档,初步认定:0是删除项目编号,1是(数字编号)有序列表,2是无序列表
PPrBase.NumPr.NumId numIdElement = factory.createPPrBaseNumPrNumId();
numPr.setNumId(numIdElement);
numIdElement.setVal(BigInteger.valueOf(2));
p.getContent().add(run);
wordMLPackage.addObject(p);
}
我们之前说过,项目符号也是本文的一种,只是样式改变了,即每一个item即为一个P。
- 因为xml结构获取对象比较繁琐,所以在使用外用轮子需注意,倾向于以下这种,在获得对象之间,先做判断,如果直接生成新的对象,会出现对象相互覆盖的问题。
public static TrPr getTrPr(Tr tr) {
TrPr trPr = tr.getTrPr();
if (trPr == null) {
trPr = new TrPr();
tr.setTrPr(trPr);
}
return trPr;
}
- 实现Tab或者代替文本空格
R.Tab rtab = factory.createRTab();
JAXBElement<org.docx4j.wml.R.Tab> rtabWrapped = factory.createRTab(rtab);
r.getContent().add(rtabWrapped);
- 文档生成大部分元素都可以通过网上查询与项目一的方法解决,这里提供一些参考资料,方便查阅