原文標題:Creating Word documents with Docx4j
原文鏈接:http://blog.iprofs.nl/2012/09/06/creating-word-documents-with-docx4j/
原文作者:lvdpal
發表時間:2012年9月6日
注:第一次翻譯博客;由於個人水平不高,而且英語僅有四級水平,所以錯誤很多,請大家見諒!!!只是國內關於docx4j的博客極少,感覺這篇入門博客挺不錯,勉強翻譯過來,希望對大家有所幫助。
一段時間之前,我為一個想要在word和excel中作報表的客戶提供服務。我以前的項目中生成過PDF文件和CSV文件,但從來沒有處理過docx和xlsx文件。這些天了解到MS Office是基於XML的。我不禁想知道是否有一些庫來幫助我生成這些文件。經過一番在線搜索,結果表明確實有:Docx4j。我開始去試用這個新庫看它能做些什么。
在官方網站上你可以了解到docx4j可以讀取、更新、創建docx、xlsx和pptx文檔。我只需要生成文檔,所以我沒有嘗試讀取和更新文檔,但原理是一樣的。Docx4j已經自帶了不少示例程序,但我發現其中的一些例子同時展示了多樣東西或者沒有完全展示我需要了解的。所以有不少東西我不得不自己解決。幸運的是docx4j嚴格遵循Office Open XML標准,所以還不算太難。總而言這,我對這個庫所提供的功能非常滿意。
在這個博客中我會展示一些我試用docx4j生成docx文檔時創建的例子:
一些提示
在真正示例開始之前有幾處提示。首先,在使用docx創建文檔的時候,看看你使用word軟件創建文檔時生成的xml。當你使用一個ZIP壓縮工具(例如7zip)打開一個docx文件時會找到這些XML文件。看一下都是些什么樣的文件以及它們包含了哪些信息。通常情況下,如果你想得到什么東西,可以通過查看Word軟件自己生成了什么而從中得到很多幫助。
其次,去看一下 the Office Open Specification。
現在讓我們來看一些代碼。
用一些文本創建文檔
最簡單的例子就是創建一個新word文檔並向其中添加一些文本內容。
運行下面代碼:
- WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
- wordMLPackage.getMainDocumentPart().addParagraphOfText("Hello Word!");
- wordMLPackage.save(new java.io.File("src/main/files/HelloWord1.docx"));
結果生成一個如下所示的文件:
這里發生的就是一個word文檔由一個帶有文檔部件的包組成。Docx4j提供一個創建包的工具方法(第1行);然后你可以從這個包中獲取主文檔部件並向其中添加一個文本段落(第2行);最后將這個包保存(第3行)。就這么簡單,當然,如果你想做不僅僅是向文檔中添加一些文本內容,那么你需要做更多的工作。
添加帶樣式的文本
然而即使添加帶樣式的文本也並不需要做過多的工作,不是向文檔添加一個普通的文本段落,而是只需要添加一個帶樣式的段落。
- WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage();
- wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Title", "Hello Word!");
- wordMLPackage.getMainDocumentPart().addStyledParagraphOfText("Subtitle","This is a subtitle!");
- wordMLPackage.save(new java.io.File("src/main/files/HelloWord2.docx"));
添加表格
當我們想添加一個表格時,情況開始變得復雜一些。直到現在我們的代碼都如此簡單以至於不需要拆分到多個方法中,所以我僅僅只展示了代碼中相關的數行。但這個示例我們需要第二個方法,所以我會展示整個類。
- public class AddingATable {
- private static WordprocessingMLPackage wordMLPackage;
- private static ObjectFactory factory;
- public static void main (String[] args) throws Docx4JException {
- wordMLPackage = WordprocessingMLPackage.createPackage();
- factory = Context.getWmlObjectFactory();
- Tbl table = factory.createTbl();
- Tr tableRow = factory.createTr();
- addTableCell(tableRow, "Field 1");
- addTableCell(tableRow, "Field 2");
- table.getContent().add(tableRow);
- wordMLPackage.getMainDocumentPart().addObject(table);
- wordMLPackage.save(new java.io.File("src/main/files/HelloWord4.docx"));
- }
- private static void addTableCell(Tr tableRow, String content) {
- Tc tableCell = factory.createTc();
- tableCell.getContent().add(
- wordMLPackage.getMainDocumentPart().createParagraphOfText(content));
- tableRow.getContent().add(tableCell);
- }
- }
我們再一次創建了word包,只是這一次我們將其保存為一個屬性,從而我們可以在第二個方法中訪問它。然后我們同樣創建了一個對象工廠(ObjectFactory),這是一個幫助我們創建本例中所需要的具體對象的工具類,例如表格、表格行及表格列等具體對象。
然后我們創建了表格,創建了行並且在行中添加了兩個單元格。最后我們將行添加到表格中,將表格添加到主文檔部件並且將包保存。
給表格添加邊框
現在我們擁有了一個表格,讓我們給它添加一些邊框。這需要深入研究一下表格的結構。
- public class TableWithBorders {
- private static WordprocessingMLPackage wordMLPackage;
- private static ObjectFactory factory;
- public static void main (String[] args) throws Docx4JException {
- wordMLPackage = WordprocessingMLPackage.createPackage();
- factory = Context.getWmlObjectFactory();
- Tbl table = createTableWithContent();
- addBorders(table);
- wordMLPackage.getMainDocumentPart().addObject(table);
- wordMLPackage.save(new java.io.File(
- "src/main/files/HelloWord5.docx") );
- }
- private static void addBorders(Tbl table) {
- table.setTblPr(new TblPr());
- CTBorder border = new CTBorder();
- border.setColor("auto");
- tborder.setSz(new BigInteger("4"));
- border.setSpace(new BigInteger("0"));
- border.setVal(STBorder.SINGLE);
- TblBorders borders = new TblBorders();
- borders.setBottom(border);
- borders.setLeft(border);
- borders.setRight(border);
- borders.setTop(border);
- borders.setInsideH(border);
- borders.setInsideV(border);
- table.getTblPr().setTblBorders(borders);
- }
- private static Tbl createTableWithContent() {
- Tbl table = factory.createTbl();
- Tr tableRow = factory.createTr();
- addTableCell(tableRow, "Field 1");
- addTableCell(tableRow, "Field 2");
- table.getContent().add(tableRow);
- return table;
- }
- private static void addTableCell(Tr tableRow, String content) {
- Tc tableCell = factory.createTc();
- tableCell.getContent().add(
- wordMLPackage.getMainDocumentPart().
- createParagraphOfText(content));
- tableRow.getContent().add(tableCell);
- }
- }
首先我們創建了一個默認顏色(黑色)、粗細尺寸為4、間距為0的單線邊框的邊框組件(Border component),然后邊框被應用到表格的四周以及表格內部水平和垂直的邊框。隨后我們將邊框應用到表格;所有其它的代碼與前面的示例一樣。
給表格添加樣式
接下來的問題--給表格添加樣式讓我忙活了一陣子,我們的客戶想要在表格中使用粗體文本並且需要多種大小的字體。
這個示例程序有點復雜,注釋和代碼交織在一起。
- public class TableWithStyledContent {
- private static WordprocessingMLPackage wordMLPackage;
- private static ObjectFactory factory;
- /**
- * 跟前面的做的一樣, 我們再一次創建了一個表格, 並添加了三個單元格, 其中有兩個
- * 單元帶有樣式. 在新方法中我們傳進表格行, 單元格內容, 是否為粗體及字體大小作
- * 為參數. 你需要注意, 因為the Office Open specification規范定義這個屬性是半個
- * 點(half-point)大小, 因此字體大小需要是你想在Word中顯示大小的兩倍,
- */
- public static void main (String[] args) throws Docx4JException {
- wordMLPackage = WordprocessingMLPackage.createPackage();
- factory = Context.getWmlObjectFactory();
- Tbl table = factory.createTbl();
- Tr tableRow = factory.createTr();
- addRegularTableCell(tableRow, "Normal text");
- addStyledTableCell(tableRow, "Bold text", true, null);
- addStyledTableCell(tableRow, "Bold large text", true, "40");
- table.getContent().add(tableRow);
- addBorders(table);
- wordMLPackage.getMainDocumentPart().addObject(table);
- wordMLPackage.save(new java.io.File("src/main/files/HelloWord6.docx") );
- }
- /**
- * 本方法創建單元格, 添加樣式后添加到表格行中
- */
- private static void addStyledTableCell(Tr tableRow, String content,
- boolean bold, String fontSize) {
- Tc tableCell = factory.createTc();
- addStyling(tableCell, content, bold, fontSize);
- tableRow.getContent().add(tableCell);
- }
- /**
- * 這里我們添加實際的樣式信息, 首先創建一個段落, 然后創建以單元格內容作為值的文本對象;
- * 第三步, 創建一個被稱為運行塊的對象, 它是一塊或多塊擁有共同屬性的文本的容器, 並將文本對象添加
- * 到其中. 隨后我們將運行塊R添加到段落內容中.
- * 直到現在我們所做的還沒有添加任何樣式, 為了達到目標, 我們創建運行塊屬性對象並給它添加各種樣式.
- * 這些運行塊的屬性隨后被添加到運行塊. 最后段落被添加到表格的單元格中.
- */
- private static void addStyling(Tc tableCell, String content, boolean bold, String fontSize) {
- 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();
- if (bold) {
- addBoldStyle(runProperties);
- }
- if (fontSize != null && !fontSize.isEmpty()) {
- setFontSize(runProperties, fontSize);
- }
- run.setRPr(runProperties);
- tableCell.getContent().add(paragraph);
- }
- /**
- * 本方法為可運行塊添加字體大小信息. 首先創建一個"半點"尺碼對象, 然后設置fontSize
- * 參數作為該對象的值, 最后我們分別設置sz和szCs的字體大小.
- * Finally we'll set the non-complex and complex script font sizes, sz and szCs respectively.
- */
- private static void setFontSize(RPr runProperties, String fontSize) {
- HpsMeasure size = new HpsMeasure();
- size.setVal(new BigInteger(fontSize));
- runProperties.setSz(size);
- runProperties.setSzCs(size);
- }
- /**
- * 本方法給可運行塊屬性添加粗體屬性. BooleanDefaultTrue是設置b屬性的Docx4j對象, 嚴格
- * 來說我們不需要將值設置為true, 因為這是它的默認值.
- */
- private static void addBoldStyle(RPr runProperties) {
- BooleanDefaultTrue b = new BooleanDefaultTrue();
- b.setVal(true);
- runProperties.setB(b);
- }
- /**
- * 本方法像前面例子中一樣再一次創建了普通的單元格
- */
- private static void addRegularTableCell(Tr tableRow, String content) {
- Tc tableCell = factory.createTc();
- tableCell.getContent().add(
- wordMLPackage.getMainDocumentPart().createParagraphOfText(
- content));
- tableRow.getContent().add(tableCell);
- }
- /**
- * 本方法給表格添加邊框
- */
- private static void addBorders(Tbl table) {
- table.setTblPr(new TblPr());
- CTBorder border = new CTBorder();
- border.setColor("auto");
- border.setSz(new BigInteger("4"));
- border.setSpace(new BigInteger("0"));
- border.setVal(STBorder.SINGLE);
- TblBorders borders = new TblBorders();
- borders.setBottom(border);
- borders.setLeft(border);
- borders.setRight(border);
- borders.setTop(border);
- borders.setInsideH(border);
- borders.setInsideV(border);
- table.getTblPr().setTblBorders(borders);
- }
- }
縱向合並單元格
有時你想要一個三列的表格,其中第一列將多行組合在一起。
- package com.zyh.sample.docx4j;
- public class TableWithMergedCells {
- private static WordprocessingMLPackage wordMLPackage;
- private static ObjectFactory factory;
- /**
- * 創建一個帶邊框的表格並添加四個帶內容的行, 然后將表格添加到文檔並保存
- */
- public static void main (String[] args) throws Docx4JException {
- wordMLPackage = WordprocessingMLPackage.createPackage();
- factory = Context.getWmlObjectFactory();
- Tbl table = factory.createTbl();
- addBorders(table);
- addTableRowWithMergedCells("Heading 1", "Heading 1.1",
- "Field 1", table);
- addTableRowWithMergedCells(null, "Heading 1.2", "Field 2", table);
- addTableRowWithMergedCells("Heading 2", "Heading 2.1",
- "Field 3", table);
- addTableRowWithMergedCells(null, "Heading 2.2", "Field 4", table);
- wordMLPackage.getMainDocumentPart().addObject(table);
- wordMLPackage.save(new java.io.File(
- "src/main/files/HelloWord9.docx") );
- }
- /**
- * 本方法創建一行, 並向其中添加合並列, 然后添加再兩個普通的單元格. 隨后將該行添加到表格
- */
- private static void addTableRowWithMergedCells(String mergedContent,
- String field1Content, String field2Content, Tbl table) {
- Tr tableRow1 = factory.createTr();
- addMergedColumn(tableRow1, mergedContent);
- addTableCell(tableRow1, field1Content);
- addTableCell(tableRow1, field2Content);
- table.getContent().add(tableRow1);
- }
- /**
- * 本方法添加一個合並了其它行單元格的列單元格. 如果傳進來的內容是null, 傳空字符串和一個為null的合並值.
- */
- private static void addMergedColumn(Tr row, String content) {
- if (content == null) {
- addMergedCell(row, "", null);
- } else {
- addMergedCell(row, content, "restart");
- }
- }
- /**
- * 我們創建一個單元格和單元格屬性對象.
- * 也創建了一個縱向合並對象. 如果合並值不為null, 將它設置到合並對象中. 然后將該對象添加到
- * 單元格屬性並將屬性添加到單元格中. 最后設置單元格內容並將單元格添加到行中.
- *
- * 如果合並值為'restart', 表明要開始一個新行. 如果為null, 繼續按前面的行處理, 也就是合並單元格.
- */
- private static void addMergedCell(Tr row, String content, String vMergeVal) {
- Tc tableCell = factory.createTc();
- TcPr tableCellProperties = new TcPr();
- VMerge merge = new VMerge();
- if(vMergeVal != null){
- merge.setVal(vMergeVal);
- }
- tableCellProperties.setVMerge(merge);
- tableCell.setTcPr(tableCellProperties);
- if(content != null) {
- tableCell.getContent().add(
- wordMLPackage.getMainDocumentPart().
- createParagraphOfText(content));
- }
- row.getContent().add(tableCell);
- }
- /**
- * 本方法為給定的行添加一個單元格, 並以給定的段落作為內容
- */
- private static void addTableCell(Tr tr, String content) {
- Tc tc1 = factory.createTc();
- tc1.getContent().add(
- wordMLPackage.getMainDocumentPart().createParagraphOfText(content));
- tr.getContent().add(tc1);
- }
- /**
- * 本方法為表格添加邊框
- */
- private static void addBorders(Tbl table) {
- table.setTblPr(new TblPr());
- CTBorder border = new CTBorder();
- border.setColor("auto");
- border.setSz(new BigInteger("4"));
- border.setSpace(new BigInteger("0"));
- border.setVal(STBorder.SINGLE);
- TblBorders borders = new TblBorders();
- borders.setBottom(border);
- borders.setLeft(border);
- borders.setRight(border);
- borders.setTop(border);
- borders.setInsideH(border);
- borders.setInsideV(border);
- table.getTblPr().setTblBorders(borders);
- }
- }
為表格設置列寬
作為本博客的最后一個示例, 我會展示怎樣為表格設置列寬。
- public class SettingColumnWidthForTable {
- private static WordprocessingMLPackage wordMLPackage;
- private static ObjectFactory factory;
- /**
- * 創建一個帶邊框的表格並添加一行. 然后添加兩個帶內容的單元格並給定寬度.
- */
- public static void main (String[] args) throws Docx4JException {
- wordMLPackage = WordprocessingMLPackage.createPackage();
- factory = Context.getWmlObjectFactory();
- Tbl table = factory.createTbl();
- addBorders(table);
- Tr tr = factory.createTr();
- addTableCellWithWidth(tr, "Field 1", 2500);
- addTableCellWithWidth(tr, "Field 2", 0);
- table.getContent().add(tr);
- wordMLPackage.getMainDocumentPart().addObject(table);
- wordMLPackage.save(new java.io.File(
- "src/main/files/HelloWord13.docx") );
- }
- /**
- * 本方法創建一個單元格並將給定的內容添加進去.
- * 如果給定的寬度大於0, 將這個寬度設置到單元格.
- * 最后, 將單元格添加到行中.
- */
- private static void addTableCellWithWidth(Tr row, String content, int width){
- Tc tableCell = factory.createTc();
- tableCell.getContent().add(
- wordMLPackage.getMainDocumentPart().createParagraphOfText(
- content));
- if (width > 0) {
- setCellWidth(tableCell, width);
- }
- row.getContent().add(tableCell);
- }
- /**
- * 本方法創建一個單元格屬性集對象和一個表格寬度對象. 將給定的寬度設置到寬度對象然后將其添加到
- * 屬性集對象. 最后將屬性集對象設置到單元格中.
- */
- private static void setCellWidth(Tc tableCell, int width) {
- TcPr tableCellProperties = new TcPr();
- TblWidth tableWidth = new TblWidth();
- tableWidth.setW(BigInteger.valueOf(width));
- tableCellProperties.setTcW(tableWidth);
- tableCell.setTcPr(tableCellProperties);
- }
- /**
- * 本方法為表格添加邊框
- */
- private static void addBorders(Tbl table) {
- table.setTblPr(new TblPr());
- CTBorder border = new CTBorder();
- border.setColor("auto");
- border.setSz(new BigInteger("4"));
- border.setSpace(new BigInteger("0"));
- border.setVal(STBorder.SINGLE);
- TblBorders borders = new TblBorders();
- borders.setBottom(border);
- borders.setLeft(border);
- borders.setRight(border);
- borders.setTop(border);
- borders.setInsideH(border);
- borders.setInsideV(border);
- table.getTblPr().setTblBorders(borders);
- }
- }
總結
在這篇文章中,我展示了如何創建一個文檔、如何為其應用樣式以及添加帶樣式的表格。以后的文章我會展示更多的關於docx文檔的示例(比如添加目錄、添加圖片、添加頁眉和頁腳等)以及一些關於xlsx文檔的示例。