docx4j基本操作

最近需要用docx4j来对docx进行一些操作,用到的技术是docx4j,这个技术在国内其实用的不是很多,看了一些博主的文章,有些感悟,做了一些总结,如果有疑问或错误之处欢迎交流。

创建包:

WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();  

保存包:

wordMLPackage.save(new java.io.File("C://xxx.docx")); 

得到主段落,并且输出/带样式输出:

MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); 
wordMLPackage.getMainDocumentPart().addParagraphOfText("Hello Word!");  
wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Title", "Hello Word!");  wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Subtitle"," a subtitle!"); 

创建表格并添加内容:

ObjectFactory factory=Context.getWmlObjectFactory();  
Tbl table = factory.createTbl();  
Tr tableRow = factory.createTr();  
Tc tableCell = factory.createTc();  
tableCell.getContent().add(wordMLPackage.getMainDocumentPart().createParagraphOfText("Field 1"));  
tableRow.getContent().add(tableCell);  
table.getContent().add(tableRow);  
wordMLPackage.getMainDocumentPart().addObject(table);  

先创建一个工厂,(需要导入的包是org.docx4j.wml,导错的的话下面全错)创建表格,在创建行和单元格(tableCell),在单元格里添加你想要的内容,因为返回值是Object,只能通过这种方式传入数据,最后层层退回去,用add添加,最后在主段落添加。

编辑表格样式:

table.setTblPr(new TblPr());  
CTBorder border = new CTBorder();  
border.setColor("auto");  
border.setSz(new BigInteger("4")); 
TblBorders borders = new TblBorders();  
borders.setBottom(border);  
borders.setLeft(border);  
borders.setInsideV(border);  
table.getTblPr().setTblBorders(borders);  

先创建table样式对象,在用CTBorder对象规定样式规范,用TblBorders对象将样式规范应用进去。

创建 段落/运行块/运行块属性/文本 对象:

ObjectFactory factory=Context.getWmlObjectFactory();  
P paragraph = factory.createP();  
Text text = factory.createText();  
text.setValue(content);  
R run = factory.createR();  
run.getContent().add(text);  
paragraph.getContent().add(run);  
RPr runProperties = factory.createRPr(); 
run.setRPr(runProperties);  
tableCell.getContent().add(paragraph);  

P是一个段落,Text是文本的值对象,R是一个运行块,负责便于将多个属性相同的Text对象统一操作,RPr是运行块的属性,可以对R对象进行操作。简单的说几个对象之间的关系可以这么理解:Tc tableCell > P paragraph > R run > Text text。其中,run.setRPr(RPr runProperties)可以设置块中属性。个人认为用开始的方法输入内容,在某种程度上是和上述代码做了一样的工作,效果相同。 
加粗字体和调整字体大小:

HpsMeasure size = new HpsMeasure();  
size.setVal(new BigInteger("40"));  
runProperties.setSz(size);  
runProperties.setSzCs(size);  
BooleanDefaultTrue b = new BooleanDefaultTrue();  
b.setVal(true);  
runProperties.setB(b);  

思路是先创建各自的对象,设置对象的值为自己想要的情况,再用RPr的对象来set相应的属性。其中注意setVal中的值最后会被现实一半,所以只有字体20大小。

纵向合并单元格:

Tc tableCell = factory.createTc();  
TcPr tableCellProperties = new TcPr();  
VMerge merge = new VMerge();  
merge.setVal("restart");  
tableCellProperties.setVMerge(merge);  
tableCell.setTcPr(tableCellProperties);  
tableCell.getContent().add(wordMLPackage.getMainDocumentPart().createParagraphOfText(content));  
row.getContent().add(tableCell);

先创建单元格属性,再创建VMerge对象,如果设置merge则为向上合并,如果将merge属性设为restart则重新开始新的单元格。

设置单元格宽度:

TcPr tableCellProperties = new TcPr();
TblWidth tableWidth = new TblWidth();
tableWidth.setW(BigInteger.valueOf("50"));
tableCellProperties.setTcW(tableWidth);
tableCell.setTcPr(tableCellProperties);

先创建单元格属性对象,创建Tblwidth对象并且设置宽度,用单元格属性对象通过方法调用Tblwidth对象。

添加图片:

File file = new File("c:\\a.jpg");
BinaryPartAbstractImage imagePart = BinaryPartAbstractImage.createImagePart(wordMLPackage, file);
int docPrId = 1;
int cNvPrId = 2;
Inline inline = imagePart.createImageInline("Filename hint","Alternative text", docPrId, cNvPrId, false);
ObjectFactory factory = new ObjectFactory();
P paragraph = factory.createP();
R run = factory.createR();
paragraph.getContent().add(run);
Drawing drawing = factory.createDrawing();
run.getContent().add(drawing);
drawing.getAnchorOrInline().add(inline);
wordMLPackage.getMainDocumentPart().addObject(paragraph);

打开文件,通过imagePart将图片读进去,现在图片被转换成二进制,为了能在文件中内联中显示出图片,调用函数将图片存在inline中。之后paragraph,run,drawing,用drawing读inline,方法同上。

加载读入docx文件:

WordprocessingMLPackage template = WordprocessingMLPackage.load(new File("c:\\a.docx"));

获取文档中所有内容(方法):

private static List<Object> getAllElementFromObject(Object obj, Class<?> toSearch) {  
    List<Object> result = new ArrayList<Object>();  
if (obj instanceof JAXBElement) 
obj = ((JAXBElement<?>) obj).getValue();  
    if (obj.getClass().equals(toSearch))  
        result.add(obj);  
    else if (obj instanceof ContentAccessor) {  
        List<?> children = ((ContentAccessor) obj).getContent();  
        for (Object child : children) {  
            result.addAll(getAllElementFromObject(child, toSearch));  
        }  
    }  
    return result;  
}  

通过对类型的判断,将obj的内容分类读到List中,最后将内容按照列表的顺序贮存,如果obj是JAXB的一个实例就将他转型获取值,如果是和第二个参数的类型相同就添加,如果是ContentAccessor的一个对象,就将对象中的内容存到另外的一个列表中,再次调用自己将全部元素添加到原来的List中,返回一个List。

posted @ 2017-11-14 18:20  chenxiangxiang  阅读(9198)  评论(0编辑  收藏  举报