XWPFDocument创建和读取Office Word文档基础篇(一)
注:有不正确的地方还望大神能够指出,抱拳了 老铁!
建议大家使用office word来创建文档。(wps和word结构有些不一样)
IBodyElement -------------------迭代器(段落和表格)
XWPFComment -------------------评论(个人理解应该是批注)
XWPFSDT
XWPFFooter -------------------页脚
XWPFFootnotes -------------------脚注
XWPFHeader -------------------页眉
XWPFHyperlink -------------------超链接
XWPFNumbering -------------------编号(我也不知是啥...)
XWPFParagraph -------------------段落
XWPFPictureData -------------------图片
XWPFStyles -------------------样式(设置多级标题的时候用)
XWPFTable -------------------表格
1、正文段落
一个文档包含多个段落,一个段落包含多个Runs,一个Runs包含多个Run,Run是文档的最小单元
获取所有段落:List<XWPFParagraph> paragraphs = word.getParagraphs();
获取一个段落中的所有Runs:List<XWPFRun> xwpfRuns = xwpfParagraph.getRuns();
获取一个Runs中的一个Run:XWPFRun run = xwpfRuns.get(index);
XWPFRun--代表具有相同属性的一段文本
2、正文表格
一个文档包含多个表格,一个表格包含多行,一行包含多列(格),每一格的内容相当于一个完整的文档
获取所有表格:List<XWPFTable> xwpfTables = doc.getTables();
获取一个表格中的所有行:List<XWPFTableRow> xwpfTableRows = xwpfTable.getRows();
获取一行中的所有列:List<XWPFTableCell> xwpfTableCells = xwpfTableRow.getTableCells();
获取一格里的内容:List<XWPFParagraph> paragraphs = xwpfTableCell.getParagraphs();
之后和正文段落一样
注:
- 表格的一格相当于一个完整的docx文档,只是没有页眉和页脚。里面可以有表格,使用xwpfTableCell.getTables()获取,and so on
- 在poi文档中段落和表格是完全分开的,如果在两个段落中有一个表格,在poi中是没办法确定表格在段落中间的。(当然除非你本来知道了,这句是废话)。只有文档的格式固定,才能正确的得到文档的结构
个人理解:我不能确定表格所处的位置(第一个段落后面 ,还是第二个段落后面...)
3、页眉:
一个文档可以有多个页眉,页眉里面可以包含段落和表格
获取文档的页眉:List<XWPFHeader> headerList = doc.getHeaderList();
获取页眉里的所有段落:List<XWPFParagraph> paras = header.getParagraphs();
获取页眉里的所有表格:List<XWPFTable> tables = header.getTables();
之后就一样了
4、页脚:
页脚和页眉基本类似,可以获取表示页数的角标
言归正传-------干货:
1、通过XWPFDocument读:段落+表格
a、获取文档的所有段落
InputStream is = new FileInputStream("D:\\table.docx"); XWPFDocument doc = new XWPFDocument(is); List<XWPFParagraph> paras = doc.getParagraphs();
获取段落内容
for (XWPFParagraph para : paras) { //当前段落的属性 //CTPPr pr = para.getCTP().getPPr(); System.out.println(para.getText()); }
b、获取文档中所有的表格
List<XWPFTable> tables = doc.getTables(); List<XWPFTableRow> rows; List<XWPFTableCell> cells; for (XWPFTable table : tables) { //表格属性 CTTblPr pr = table.getCTTbl().getTblPr(); //获取表格对应的行 rows = table.getRows(); for (XWPFTableRow row : rows) { //获取行对应的单元格 cells = row.getTableCells(); for (XWPFTableCell cell : cells) { System.out.println(cell.getText());; } } }
2、XWPFDocument生成word
直接new一个空的XWPFDocument,之后再往这个XWPFDocument里面填充内容,然后再把它写入到对应的输出流中。
新建一个文档
XWPFDocument doc = new XWPFDocument(); //创建一个段落 XWPFParagraph para = doc.createParagraph(); //一个XWPFRun代表具有相同属性的一个区域:一段文本 XWPFRun run = para.createRun(); run.setBold(true); //加粗 run.setText("加粗的内容"); run = para.createRun(); run.setColor("FF0000"); run.setText("红色的字。"); OutputStream os = new FileOutputStream("D:\\simpleWrite.docx"); //把doc输出到输出流 doc.write(os); this.close(os);
新建一个表格
//XWPFDocument doc = new XWPFDocument(); //创建一个5行5列的表格 XWPFTable table = doc.createTable(5, 5); //这里增加的列原本初始化创建的那5行在通过getTableCells()方法获取时获取不到,但通过row新增的就可以。 //table.addNewCol(); //给表格增加一列,变成6列 table.createRow(); //给表格新增一行,变成6行 List<XWPFTableRow> rows = table.getRows(); //表格属性 CTTblPr tablePr = table.getCTTbl().addNewTblPr(); //表格宽度 CTTblWidth width = tablePr.addNewTblW(); width.setW(BigInteger.valueOf(8000)); XWPFTableRow row; List<XWPFTableCell> cells; XWPFTableCell cell; int rowSize = rows.size(); int cellSize; for (int i=0; i<rowSize; i++) { row = rows.get(i); //新增单元格 row.addNewTableCell(); //设置行的高度 row.setHeight(500); //行属性 //CTTrPr rowPr = row.getCtRow().addNewTrPr(); //这种方式是可以获取到新增的cell的。 //List<CTTc> list = row.getCtRow().getTcList(); cells = row.getTableCells(); cellSize = cells.size(); for (int j=0; j<cellSize; j++) { cell = cells.get(j); if ((i+j)%2==0) { //设置单元格的颜色 cell.setColor("ff0000"); //红色 } else { cell.setColor("0000ff"); //蓝色 } //单元格属性 CTTcPr cellPr = cell.getCTTc().addNewTcPr(); cellPr.addNewVAlign().setVal(STVerticalJc.CENTER); if (j == 3) { //设置宽度 cellPr.addNewTcW().setW(BigInteger.valueOf(3000)); } cell.setText(i + ", " + j); } } //文件不存在时会自动创建 OutputStream os = new FileOutputStream("D:\\table.docx"); //写入文件 doc.write(os); this.close(os);
段落内容替换
/** * 替换段落里面的变量 * @param para 要替换的段落 * @param params 参数 */ private void replaceInPara(XWPFParagraph para, Map<String, Object> params) { List<XWPFRun> runs; Matcher matcher; if (this.matcher(para.getParagraphText()).find()) { runs = para.getRuns(); for (int i=0; i<runs.size(); i++) { XWPFRun run = runs.get(i); String runText = run.toString(); matcher = this.matcher(runText); if (matcher.find()) { while ((matcher = this.matcher(runText)).find()) { runText = matcher.replaceFirst(String.valueOf(params.get(matcher.group(1)))); } //直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun,把文本附加在当前文本后面, //所以我们不能直接设值,需要先删除当前run,然后再自己手动插入一个新的run。 para.removeRun(i); para.insertNewRun(i).setText(runText); } } } }
直接调用XWPFRun的setText()方法设置文本时,在底层会重新创建一个XWPFRun,把文本附加在当前文本后面,所以我们不能直接设值,需要先删除当前run,然后再自己手动插入一个新的run。
//抽取 word docx文件中的图片
String path ="D://abc.docx"; File file = new File(path); try { FileInputStream fis = new FileInputStream(file); XWPFDocument document = new XWPFDocument(fis); XWPFWordExtractor xwpfWordExtractor = new XWPFWordExtractor(document); String text = xwpfWordExtractor.getText(); System.out.println(text); List<XWPFPictureData> picList = document.getAllPictures(); for (XWPFPictureData pic : picList) { System.out.println(pic.getPictureType() + file.separator + pic.suggestFileExtension() +file.separator+pic.getFileName()); byte[] bytev = pic.getData(); FileOutputStream fos = new FileOutputStream("D:\\abc\\docxImage\\"+pic.getFileName()); fos.write(bytev); } fis.close(); } catch (IOException e) { e.printStackTrace(); } }
多级标题结构
/** * 自定义样式方式写word,参考statckoverflow的源码 * * @throws IOException */ public static void writeSimpleDocxFile() throws IOException { XWPFDocument docxDocument = new XWPFDocument(); // 老外自定义了一个名字,中文版的最好还是按照word给的标题名来,否则级别上可能会乱 addCustomHeadingStyle(docxDocument, "标题 1", 1); addCustomHeadingStyle(docxDocument, "标题 2", 2); // 标题1 XWPFParagraph paragraph = docxDocument.createParagraph(); XWPFRun run = paragraph.createRun(); run.setText("标题 1"); paragraph.setStyle("标题 1"); // 标题2 XWPFParagraph paragraph2 = docxDocument.createParagraph(); XWPFRun run2 = paragraph2.createRun(); run2.setText("标题 2"); paragraph2.setStyle("标题 2"); // 正文 XWPFParagraph paragraphX = docxDocument.createParagraph(); XWPFRun runX = paragraphX.createRun(); runX.setText("正文");
// word写入到文件 FileOutputStream fos = new FileOutputStream("D:/myDoc2.docx"); docxDocument.write(fos); fos.close(); } /** * 增加自定义标题样式。这里用的是stackoverflow的源码 * * @param docxDocument 目标文档 * @param strStyleId 样式名称 * @param headingLevel 样式级别 */ private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) { CTStyle ctStyle = CTStyle.Factory.newInstance(); ctStyle.setStyleId(strStyleId); CTString styleName = CTString.Factory.newInstance(); styleName.setVal(strStyleId); ctStyle.setName(styleName); CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance(); indentNumber.setVal(BigInteger.valueOf(headingLevel)); // lower number > style is more prominent in the formats bar ctStyle.setUiPriority(indentNumber); CTOnOff onoffnull = CTOnOff.Factory.newInstance(); ctStyle.setUnhideWhenUsed(onoffnull); // style shows up in the formats bar ctStyle.setQFormat(onoffnull); // style defines a heading of the given level CTPPr ppr = CTPPr.Factory.newInstance(); ppr.setOutlineLvl(indentNumber); ctStyle.setPPr(ppr); XWPFStyle style = new XWPFStyle(ctStyle); // is a null op if already defined XWPFStyles styles = docxDocument.createStyles(); style.setType(STStyleType.PARAGRAPH); styles.addStyle(style); }