XWPFDocument创建和读取Office Word文档基础篇(一)

时间:2021-11-22 05:44:20
注:有不正确的地方还望大神能够指出,抱拳了 老铁!   参考API:http://poi.apache.org/apidocs/org/apache/poi/xwpf/usermodel/XWPFDocument.html 主要参考文章1:http://www.cnblogs.com/Springmoon-venn/p/5494602.html 主要参考文章2:http://elim.iteye.com/blog/2049110 主要参考文章3:http://doc.okbase.net/oh_Maxy/archive/154764.html     建议大家使用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(); 之后和正文段落一样     注:
  1. 表格的一格相当于一个完整的docx文档,只是没有页眉和页脚。里面可以有表格,使用xwpfTableCell.getTables()获取,and so on
  2. 在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();
}

/**
* 增加自定义标题样式。这里用的是*的源码
*
*
@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);

}