用java语言通过POI实现word文档的按标题提取
最近有一个项目需要将一个word文档中的数据提取到数据库中。就去网上查了好多资料,最靠谱的就是用poi实现word文档的提取。
喝水不忘挖井人,我查了好多资料就这个最靠谱,我的这篇博客主要是借鉴https://blog.csdn.net/qq_16601953/article/details/82415518
现在讲一下思路:
1.首先我们要用poi将word中的数据提取出来,我把提取的数据存到字符数组中,
2.然后通过sql数据将字符串数组中的数据存到mysql数据库中
当然需要jar包依赖
可能不需要这么多,但是我都导进去了
网上有poi的下载链接http://120.52.51.14/archive.apache.org/dist/poi/release/bin/poi-bin-3.17-20170915.zip
如果实在找不到的话加我
下面贴上主要代码我是按照上面博客借鉴的稍微根据我的需求改了改
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.util.HashMap;
import java.util.List;
import java.util.Map; import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.poi.xwpf.usermodel.XWPFStyle;
import org.apache.poi.xwpf.usermodel.XWPFStyles;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType; public class test {
private static Map<String,Map<String,Object>> orderMap =new HashMap<String, Map<String,Object>>(); public void init(String targetPath,String sourcePath){
InputStream is = null;
XWPFDocument doc=null;
OutputStream out=null;
try {
XWPFDocument createDoc = new XWPFDocument(); is = new FileInputStream(sourcePath);
doc = new XWPFDocument(is);
//获取段落
List<XWPFParagraph> paras=doc.getParagraphs(); for (XWPFParagraph para : paras){
// System.out.println(para.getCTP());//得到xml格式
System.out.println(para.getStyleID());//段落级别
System.out.println(para.getParagraphText());//段落内容 String titleLvl = getTitleLvl(doc,para);//获取段落级别
if("a5".equals(titleLvl)||"HTML".equals(titleLvl)||"".equals(titleLvl)||null==titleLvl){
titleLvl = "";
}
System.out.println(titleLvl+"-----");//0,1,2
if(!"".equals(titleLvl)){
System.out.println(titleLvl+"===="+para.getParagraphText());
} XWPFParagraph ctPara = createDoc.createParagraph();
//一个XWPFRun代表具有相同属性的一个区域。
XWPFRun ctRun = ctPara.createRun();
String ctText = para.getParagraphText();
ctRun.setFontFamily("宋体");//字体
ctRun.setFontSize(); if(null!=titleLvl&&!"".equals(titleLvl)&&!"".equals(titleLvl)){
addCustomHeadingStyle(createDoc,titleLvl,Integer.parseInt(titleLvl));
String orderCode = getOrderCode(titleLvl);//获取编号
ctText = orderCode+" "+ctText;
ctRun.setBold(true);//标题加粗
ctRun.setFontSize(); ctPara.setStyle(titleLvl); }else{//正文
ctPara.setIndentationFirstLine();//首行缩进:567==1厘米
// ctRun.setTextPosition(6);//设置行间距
} ctRun.setText(ctText);//内容
}
out=new FileOutputStream(targetPath);
createDoc.write(out);
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
if(null!=out){
out.close();
}
if(null!=is){
is.close();
}
}catch (IOException e) {
e.printStackTrace();
}
}
} /**
* Word中的大纲级别,可以通过getPPr().getOutlineLvl()直接提取,但需要注意,Word中段落级别,通过如下三种方式定义:
* 1、直接对段落进行定义;
* 2、对段落的样式进行定义;
* 3、对段落样式的基础样式进行定义。
* 因此,在通过“getPPr().getOutlineLvl()”提取时,需要依次在如上三处读取。
* @param doc
* @param para
* @return
*/
private static String getTitleLvl(XWPFDocument doc, XWPFParagraph para) {
String titleLvl = "";
try {
//判断该段落是否设置了大纲级别
if (para.getCTP().getPPr().getOutlineLvl() != null) {
// System.out.println("getCTP()");
// System.out.println(para.getParagraphText());
// System.out.println(para.getCTP().getPPr().getOutlineLvl().getVal()); return String.valueOf(para.getCTP().getPPr().getOutlineLvl().getVal());
}
} catch (Exception e) { } try {
//判断该段落的样式是否设置了大纲级别
if (doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl() != null) { // System.out.println("getStyle");
// System.out.println(para.getParagraphText());
// System.out.println(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal()); return String.valueOf(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
}
} catch (Exception e) { } try {
//判断该段落的样式的基础样式是否设置了大纲级别
if (doc.getStyles().getStyle(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal())
.getCTStyle().getPPr().getOutlineLvl() != null) {
// System.out.println("getBasedOn");
// System.out.println(para.getParagraphText());
String styleName = doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal();
// System.out.println(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal()); return String.valueOf(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
}
} catch (Exception e) { } try {
if(para.getStyleID()!=null){
return para.getStyleID();
}
} catch (Exception e) { } return titleLvl;
} /**
* 增加自定义标题样式。这里用的是stackoverflow的源码
*
* @param docxDocument 目标文档
* @param strStyleId 样式名称
* @param headingLevel 样式级别
*/
private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) { strStyleId = String.valueOf(Integer.parseInt(strStyleId)+);
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); }
/**
* 获取标题编号
* @param titleLvl
* @return
*/
private static String getOrderCode(String titleLvl) {
String order = ""; if("".equals(titleLvl)||Integer.parseInt(titleLvl)==){//文档标题||正文
return "";
}else if(Integer.parseInt(titleLvl)>&&Integer.parseInt(titleLvl)<){//段落标题 //设置最高级别标题
Map<String,Object> maxTitleMap = orderMap.get("maxTitleLvlMap");
if(null==maxTitleMap){//没有,表示第一次进来
//最高级别标题赋值
maxTitleMap = new HashMap<String, Object>();
maxTitleMap.put("lvl", titleLvl);
orderMap.put("maxTitleLvlMap", maxTitleMap);
}else{
String maxTitleLvl = maxTitleMap.get("lvl")+"";//最上层标题级别(0,1,2,3)
if(Integer.parseInt(titleLvl)<Integer.parseInt(maxTitleLvl)){//当前标题级别更高
maxTitleMap.put("lvl", titleLvl);//设置最高级别标题
orderMap.put("maxTitleLvlMap", maxTitleMap);
}
} //查父节点标题
int parentTitleLvl = Integer.parseInt(titleLvl)-;//父节点标题级别
Map<String,Object> cMap = orderMap.get(titleLvl);//当前节点信息
Map<String,Object> pMap = orderMap.get(parentTitleLvl+"");//父节点信息 if(==parentTitleLvl){//父节点为文档标题,表明当前节点为1级标题
int count= ;
//最上层标题,没有父节点信息
if(null==cMap){//没有当前节点信息
cMap = new HashMap<String, Object>();
}else{
count = Integer.parseInt(String.valueOf(cMap.get("cCount")));//当前序个数
}
count++;
order = count+"";
cMap.put("cOrder", order);//当前序
cMap.put("cCount", count);//当前序个数
orderMap.put(titleLvl, cMap); }else{//父节点为非文档标题
int count= ;
//如果没有相邻的父节点信息,当前标题级别自动升级
if(null==pMap){
return getOrderCode(String.valueOf(parentTitleLvl));
}else{
String pOrder = String.valueOf(pMap.get("cOrder"));//父节点序
if(null==cMap){//没有当前节点信息
cMap = new HashMap<String, Object>();
}else{
count = Integer.parseInt(String.valueOf(cMap.get("cCount")));//当前序个数
}
count++;
order = pOrder+"."+count;//当前序编号
cMap.put("cOrder", order);//当前序
cMap.put("cCount", count);//当前序个数
orderMap.put(titleLvl, cMap);
}
} //字节点标题计数清零
int childTitleLvl = Integer.parseInt(titleLvl)+;//子节点标题级别
Map<String,Object> cdMap = orderMap.get(childTitleLvl+"");//
if(null!=cdMap){
cdMap.put("cCount", );//子节点序个数
orderMap.get(childTitleLvl+"").put("cCount", );
}
}
return order;
} public static void main(String[] args) {
InputStream is = null;
XWPFDocument doc=null;
OutputStream out=null;
String[] title= new String [];
String[] concent= new String [];
String[] type= new String [];
int i=;
try {
XWPFDocument createDoc = new XWPFDocument(); is = new FileInputStream("E:/doc/a.docx");
doc = new XWPFDocument(is);
//获取段落
List<XWPFParagraph> paras=doc.getParagraphs(); for (XWPFParagraph para : paras){
//System.out.println(para.getCTP());//得到xml格式
//System.out.println(para.getStyleID());//段落级别
// System.out.println(para.getParagraphText());//段落内容
String titleLvl = getTitleLvl(doc,para);//获取段落级别
if("a5".equals(titleLvl)||"HTML".equals(titleLvl)||"".equals(titleLvl)||null==titleLvl){
titleLvl = "";
}
//System.out.println(titleLvl+"-----");//0,1,2
if(!"".equals(titleLvl)){
//System.out.println(titleLvl+"===="+para.getParagraphText()); if("".equals(titleLvl)) { if(concent[i]!=null)
concent[i]=concent[i]+para.getParagraphText();
else
concent[i]=para.getParagraphText();
//System.out.println(concent[i]);
}
if("".equals(titleLvl)) {
i++;
title[i]=para.getParagraphText();
type[i]=type[i-];
//System.out.println(title[i]);
}
if("".equals(titleLvl)) {
i++;
type[i]=para.getParagraphText();
//System.out.println(title[i]);
}
} }
for(int j=;j<title.length;j++) {
if(title[j]!=null) {
String sql = "INSERT INTO shuju (title,concent,type)VALUES ('"+title[j]+"','"+concent[j]+"','"+type[j]+"')";
DBUtil jdbc=new DBUtil();
int result=jdbc.executeUpdate(sql);
jdbc.close();
//System.out.println(type[j]);
//System.out.println(title[j]);
//System.out.println(concent[j]);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally{
try {
if(null!=out){
out.close();
}
if(null!=is){
is.close();
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
ps:331到341是导入到数据库的需要新建数据库工具类
你自己弄就OK
如果是单纯的读取的话用下面的代码,因为上面比较繁琐我都不太理解,下面的代码比较简单易懂,当然功能相对也少,只能读取所有内容不能识别标题
借鉴的哪一篇博客因为时间太长了,我忘了,抱歉
package com.poi.test; import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream; import org.apache.poi.POIXMLDocument;
import org.apache.poi.POIXMLTextExtractor;
import org.apache.poi.hwpf.extractor.WordExtractor;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.xwpf.extractor.XWPFWordExtractor; public class testPoi {
/**
* 读取word文件内容
*
* @param path
* @return buffer
*/ public String readWord(String path) {
String buffer = "";
try {
if (path.endsWith(".doc")) {
InputStream is = new FileInputStream(new File(path));
WordExtractor ex = new WordExtractor(is);
buffer = ex.getText();
ex.close();
} else if (path.endsWith("docx")) {
OPCPackage opcPackage = POIXMLDocument.openPackage(path);
POIXMLTextExtractor extractor = new XWPFWordExtractor(opcPackage);
buffer = extractor.getText();
extractor.close();
} else {
System.out.println("此文件不是word文件!");
} } catch (Exception e) {
e.printStackTrace();
} return buffer;
} public static void main(String[] args) {
// TODO Auto-generated method stub
testPoi tp = new testPoi();
String content = tp.readWord("自己的路径.doc");
//String arr[]=content.split("\\d+");
//String arr[]=content.split("第"+"\\w"+"章");
String arr[]=content.split("\\r\\n");
/*String[] a=arr[13].split("\\d+");
String[] b=a[1].split("\\s+");
System.out.println(b[1]);*/
String[] reci = new String [];;
for(int i=,j=;i<;i++,j++) {
arr[i]=arr[i]+"";
if(!arr[i].equals("")) { if(i<) {//判断页面数是否为单数
String[] a=arr[i].split("\\d+|\\s+");
if(arr[i]!="\\s+") {//判断该元素是否为连续空格
if(a.length==) {//判断该元素是否为标题即分割成2个段
reci[j]=a[];
System.out.println(a[]);
}
else if(a.length==) {
reci[j]=a[];
System.out.println(arr[i]);
}
else//否则该元素是平常元素可以分割成3个段
{
reci[j]=a[];
System.out.println(a[]);
}
}
}
else {
String[] a=arr[i].split("\\d{2,3}|\\s+|\\t");
if(arr[i]!="\\s+") {//判断该元素是否为连续空格
if(a.length==) {
reci[j]=a[];
System.out.println(a[]);
}
else if(a.length==) {
reci[j]=a[];
System.out.println(arr[i]+i);
}
else if(a.length==) {
reci[j]=a[];
System.out.println(a[]);
}
else
{reci[j]=a[];
System.out.println(a[]);
}
}
}
}
}
String fengefu=reci[];
for(int i=;i<;i++) {
if(reci[i]!=null)
fengefu=fengefu+"|"+reci[i]; }
System.out.println(reci[]);
System.out.println(fengefu);
String arr2[]=content.split(fengefu);
for(int i=;i<;i++)
System.out.println(arr2[i]);
}
}
还有下面这一种方法,与上面相似
package com.xxx.util; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import org.apache.poi.hwpf.extractor.WordExtractor; public class DocUtil {
/**
* 读取doc文件内容
*
* @param file
* 想要读取的文件对象
* @return 返回文件内容
* @throws IOException
*/
public static String doc2String(FileInputStream fs) throws IOException {
StringBuilder result = new StringBuilder();
WordExtractor re = new WordExtractor(fs);
result.append(re.getText());
re.close();
return result.toString();
} public static String doc2String(File file) throws IOException {
return doc2String(new FileInputStream(file));
} public static void main(String[] args) {
File file = new File("自己的路径.doc");
try {
System.out.println(doc2String(file));
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果截图因为一部分原因就不贴出来了
当然对于poi我还是比较陌生,希望大牛们批评指正
用java语言通过POI实现word文档的按标题提取的更多相关文章
- POI生成WORD文档
h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h ...
- POI生成word文档完整案例及讲解
一,网上的API讲解 其实POI的生成Word文档的规则就是先把获取到的数据转成xml格式的数据,然后通过xpath解析表单式的应用取值,判断等等,然后在把取到的值放到word文档中,最后在输出来. ...
- Java jacob调用打印机打印word文档
前面说了Java如何生成复杂的Word文档,今年记录下Java如何调用打印机打印word文档. 起初用的是自带的PrintJob,但是系统提供的打印机制并不成熟完整.网上的代码也是千篇一律,在我的打印 ...
- Poi之Word文档结构介绍
1.poi之word文档结构介绍之正文段落 一个文档包含多个段落,一个段落包含多个Runs,一个Runs包含多个Run,Run是文档的最小单元 获取所有段落:List<XWPFParagraph ...
- Java 用Freemarker完美导出word文档(带图片)
Java 用Freemarker完美导出word文档(带图片) 前言 最近在项目中,因客户要求,将页面内容(如合同协议)导出成word,在网上翻了好多,感觉太乱了,不过最后还是较好解决了这个问题. ...
- POI 生成 word 文档 简单版(包括文字、表格、图片、字体样式设置等)
POI 生成word 文档 一般有两种方法: ① word模板 生成word 文档 : ② 写代码直接生成 word 文档: 我这里演示的是第二种方法,即写代码生成 word文档,不多说废话,直接 ...
- Java POI 解析word文档
实现步骤: 1.poi实现word转html 2.模型化解析html 3.html转Map数组 Map数组(数组的操作处理不做说明) 1.导jar包. 2.代码实现 package com.web.o ...
- java对word文档的操作(提取标题和内容等)-直接操作或poi工具包或freemarker+xml或html转word
1,java自带工具包实现对word的排版和写入 import java.awt.Color; import java.io.FileNotFoundException; import java.io ...
- java 使用poi读取word文档存入数据库
使用的poi jar包需要自己下载 读取的word文档中含有多个图片,所以分为两个部分,一个部分读取各个表格中内容,一个是将所有图片截取出来: /** * 遍历段落内容 * docxReadPath ...
随机推荐
- es elasticsearch-head安装
---恢复内容开始--- 参考 https://www.jianshu.com/p/36d7f97a20cd 1.下载安装git clone git://github.com/mobz/elastic ...
- 项目必备!永无 bug 注释
佛祖保佑 永无bug 代码注释 // // _oo0oo_ // o8888888o // 88" . "88 // (| -_- |) // 0\ = /0 // ___/`-- ...
- Git permission denied(public key) 解决方法
1. 在Linux上: # ssh-keygen ##一定用 id_rsa.pub # cat /root/.ssh/id_rsa.pub 2. copy 整个文件内容到剪切板 3. 打开 ...
- MongDB增删改查
增加 增加一条:db.th.insertOne({}) // 返回 _id 增加多条:db.th.insertMany([{},{},{}]) // 返回 _ids 针对Array增加操作: db.s ...
- C语言面试题分类->位运算
1.不用临时变量交换两个整数. a = a ^ b; b = a ^ b; a = a ^ b; 2.实现一个函数,输入一个整数,输出该数二进制表示中1的个数.例如9的二进制是1001,则输出2. i ...
- wordpress chronus主题 显示文章阅读数
wordpress chronus主题 显示文章阅读数 第一步:将下面的代码拷贝到文件 /wp-content/themes/chronus/inc/template-tags.php 中 funct ...
- maven打包忽略静态资源解决办法,dispatchServlet拦截静态资源请求的解决办法
问题: maven 打包时,有的文件打不进去target 解决: 因为maven打包默认打Java文件.在项目中的pom文件中加build标签 <build> <resources& ...
- netbeans10支持php7.1-7.3
2019年1月16日10:56:49 官方发布时间2018年12月27日 PHP支持 NetBeans 10的所有PHP支持都是由我们的NetBeans提交者 Junichi Yamamoto提供的. ...
- python经常使用的十进制、16进制、字符串、字节串之间的转换(长期更新帖)
进行协议解析时.总是会遇到各种各样的数据转换的问题,从二进制到十进制,从字节串到整数等等 废话不多上.直接上样例 整数之间的进制转换: 10进制转16进制: hex(16) ==> 0x10 ...
- TCP/IP详解--拥塞控制 & 慢开始、拥塞避免、快重传和快恢复。
https://www.cnblogs.com/losbyday/p/5847041.html 膜拜大佬,看完了就会