zoukankan      html  css  js  c++  java
  • 用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

    如果实在找不到的话加我 

    下面贴上主要代码我是按照上面博客借鉴的稍微根据我的需求改了改

      1 import java.io.FileInputStream;
      2 import java.io.FileOutputStream;
      3 import java.io.IOException;
      4 import java.io.InputStream;
      5 import java.io.OutputStream;
      6 import java.math.BigInteger;
      7 import java.util.HashMap;
      8 import java.util.List;
      9 import java.util.Map;
     10 
     11 import org.apache.poi.xwpf.usermodel.XWPFDocument;
     12 import org.apache.poi.xwpf.usermodel.XWPFParagraph;
     13 import org.apache.poi.xwpf.usermodel.XWPFRun;
     14 import org.apache.poi.xwpf.usermodel.XWPFStyle;
     15 import org.apache.poi.xwpf.usermodel.XWPFStyles;
     16 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDecimalNumber;
     17 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTOnOff;
     18 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPPr;
     19 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTString;
     20 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTStyle;
     21 import org.openxmlformats.schemas.wordprocessingml.x2006.main.STStyleType;
     22 
     23 
     24 public class test {
     25 private static Map<String,Map<String,Object>> orderMap =new HashMap<String, Map<String,Object>>();
     26 
     27     public void init(String targetPath,String sourcePath){
     28         InputStream is = null;
     29         XWPFDocument doc=null;
     30         OutputStream out=null;
     31         try {
     32             XWPFDocument createDoc = new XWPFDocument();
     33 
     34             is = new FileInputStream(sourcePath);
     35             doc = new XWPFDocument(is);
     36             //获取段落
     37             List<XWPFParagraph> paras=doc.getParagraphs();
     38 
     39             for (XWPFParagraph para : paras){
     40  //             System.out.println(para.getCTP());//得到xml格式
     41               System.out.println(para.getStyleID());//段落级别
     42               System.out.println(para.getParagraphText());//段落内容
     43 
     44                 String titleLvl = getTitleLvl(doc,para);//获取段落级别
     45                 if("a5".equals(titleLvl)||"HTML".equals(titleLvl)||"".equals(titleLvl)||null==titleLvl){
     46                     titleLvl = "8";
     47                 }
     48               System.out.println(titleLvl+"-----");//0,1,2
     49                 if(!"8".equals(titleLvl)){
     50                     System.out.println(titleLvl+"===="+para.getParagraphText());
     51                 }
     52 
     53 
     54                 XWPFParagraph ctPara = createDoc.createParagraph();
     55                 //一个XWPFRun代表具有相同属性的一个区域。
     56                 XWPFRun ctRun = ctPara.createRun();
     57                 String ctText = para.getParagraphText();
     58                 ctRun.setFontFamily("宋体");//字体
     59                 ctRun.setFontSize(12);
     60 
     61                 if(null!=titleLvl&&!"".equals(titleLvl)&&!"8".equals(titleLvl)){
     62                     addCustomHeadingStyle(createDoc,titleLvl,Integer.parseInt(titleLvl));
     63                     String orderCode = getOrderCode(titleLvl);//获取编号
     64                     ctText = orderCode+" "+ctText;
     65                     ctRun.setBold(true);//标题加粗
     66                     ctRun.setFontSize(14);
     67 
     68                     ctPara.setStyle(titleLvl);
     69 
     70                 }else{//正文
     71                     ctPara.setIndentationFirstLine(567);//首行缩进:567==1厘米
     72 //                  ctRun.setTextPosition(6);//设置行间距
     73                 }
     74 
     75                 ctRun.setText(ctText);//内容
     76             }
     77             out=new FileOutputStream(targetPath);
     78             createDoc.write(out);
     79         } catch (Exception e) {
     80             e.printStackTrace();
     81         } finally{
     82             try {
     83                 if(null!=out){
     84                     out.close();
     85                 } 
     86                 if(null!=is){
     87                     is.close();
     88                 }
     89             }catch (IOException e) {
     90                 e.printStackTrace();
     91             }
     92         }
     93     }
     94 
     95     /**
     96      * Word中的大纲级别,可以通过getPPr().getOutlineLvl()直接提取,但需要注意,Word中段落级别,通过如下三种方式定义: 
     97      *  1、直接对段落进行定义; 
     98      *  2、对段落的样式进行定义; 
     99      *  3、对段落样式的基础样式进行定义。 
    100      *  因此,在通过“getPPr().getOutlineLvl()”提取时,需要依次在如上三处读取。
    101      * @param doc
    102      * @param para
    103      * @return
    104      */
    105     private static String getTitleLvl(XWPFDocument doc, XWPFParagraph para) {
    106         String titleLvl = "";
    107         try {
    108             //判断该段落是否设置了大纲级别
    109             if (para.getCTP().getPPr().getOutlineLvl() != null) {
    110                 // System.out.println("getCTP()");
    111 //              System.out.println(para.getParagraphText());
    112 //              System.out.println(para.getCTP().getPPr().getOutlineLvl().getVal());
    113 
    114                 return String.valueOf(para.getCTP().getPPr().getOutlineLvl().getVal());
    115             }
    116         } catch (Exception e) {
    117 
    118         }
    119 
    120         try {
    121             //判断该段落的样式是否设置了大纲级别
    122             if (doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl() != null) {
    123 
    124                 // System.out.println("getStyle");
    125 //              System.out.println(para.getParagraphText());
    126 //              System.out.println(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
    127 
    128                 return String.valueOf(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getPPr().getOutlineLvl().getVal());
    129             }
    130         } catch (Exception e) {
    131 
    132         }
    133 
    134         try {
    135             //判断该段落的样式的基础样式是否设置了大纲级别
    136             if (doc.getStyles().getStyle(doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal())
    137                     .getCTStyle().getPPr().getOutlineLvl() != null) {
    138                 // System.out.println("getBasedOn");
    139 //              System.out.println(para.getParagraphText());
    140                 String styleName = doc.getStyles().getStyle(para.getStyle()).getCTStyle().getBasedOn().getVal();
    141 //              System.out.println(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
    142 
    143                 return String.valueOf(doc.getStyles().getStyle(styleName).getCTStyle().getPPr().getOutlineLvl().getVal());
    144             }
    145         } catch (Exception e) {
    146 
    147         }
    148 
    149         try {
    150             if(para.getStyleID()!=null){
    151                 return para.getStyleID();
    152             }
    153         } catch (Exception e) {
    154 
    155         }
    156 
    157         return titleLvl;
    158     }
    159 
    160     /**
    161      * 增加自定义标题样式。这里用的是stackoverflow的源码
    162      * 
    163      * @param docxDocument 目标文档
    164      * @param strStyleId 样式名称
    165      * @param headingLevel 样式级别
    166      */
    167     private static void addCustomHeadingStyle(XWPFDocument docxDocument, String strStyleId, int headingLevel) {
    168 
    169         strStyleId = String.valueOf(Integer.parseInt(strStyleId)+1);
    170         CTStyle ctStyle = CTStyle.Factory.newInstance();
    171         ctStyle.setStyleId(strStyleId);
    172 
    173         CTString styleName = CTString.Factory.newInstance();
    174         styleName.setVal(strStyleId);
    175         ctStyle.setName(styleName);
    176 
    177         CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
    178         indentNumber.setVal(BigInteger.valueOf(headingLevel));
    179 
    180         // lower number > style is more prominent in the formats bar
    181         ctStyle.setUiPriority(indentNumber);
    182 
    183         CTOnOff onoffnull = CTOnOff.Factory.newInstance();
    184         ctStyle.setUnhideWhenUsed(onoffnull);
    185 
    186         // style shows up in the formats bar
    187         ctStyle.setQFormat(onoffnull);
    188 
    189         // style defines a heading of the given level
    190         CTPPr ppr = CTPPr.Factory.newInstance();
    191         ppr.setOutlineLvl(indentNumber);
    192         ctStyle.setPPr(ppr);
    193 
    194         XWPFStyle style = new XWPFStyle(ctStyle);
    195 
    196         // is a null op if already defined
    197         XWPFStyles styles = docxDocument.createStyles();
    198 
    199         style.setType(STStyleType.PARAGRAPH);
    200         styles.addStyle(style);
    201 
    202     }
    203     /**
    204      * 获取标题编号
    205      * @param titleLvl
    206      * @return
    207      */
    208     private static String getOrderCode(String titleLvl) {
    209         String order = "";
    210 
    211         if("0".equals(titleLvl)||Integer.parseInt(titleLvl)==8){//文档标题||正文
    212             return "";
    213         }else if(Integer.parseInt(titleLvl)>0&&Integer.parseInt(titleLvl)<8){//段落标题
    214 
    215             //设置最高级别标题
    216             Map<String,Object> maxTitleMap = orderMap.get("maxTitleLvlMap");
    217             if(null==maxTitleMap){//没有,表示第一次进来
    218                 //最高级别标题赋值
    219                 maxTitleMap = new HashMap<String, Object>();
    220                 maxTitleMap.put("lvl", titleLvl);
    221                 orderMap.put("maxTitleLvlMap", maxTitleMap);
    222             }else{
    223                 String maxTitleLvl = maxTitleMap.get("lvl")+"";//最上层标题级别(0,1,2,3)
    224                 if(Integer.parseInt(titleLvl)<Integer.parseInt(maxTitleLvl)){//当前标题级别更高
    225                     maxTitleMap.put("lvl", titleLvl);//设置最高级别标题
    226                     orderMap.put("maxTitleLvlMap", maxTitleMap);
    227                 }
    228             }
    229 
    230             //查父节点标题
    231             int parentTitleLvl = Integer.parseInt(titleLvl)-1;//父节点标题级别
    232             Map<String,Object> cMap = orderMap.get(titleLvl);//当前节点信息
    233             Map<String,Object> pMap = orderMap.get(parentTitleLvl+"");//父节点信息
    234 
    235             if(0==parentTitleLvl){//父节点为文档标题,表明当前节点为1级标题
    236                 int count= 0;
    237                 //最上层标题,没有父节点信息
    238                 if(null==cMap){//没有当前节点信息
    239                     cMap = new HashMap<String, Object>();
    240                 }else{
    241                     count = Integer.parseInt(String.valueOf(cMap.get("cCount")));//当前序个数
    242                 }
    243                 count++;
    244                 order = count+"";
    245                 cMap.put("cOrder", order);//当前序
    246                 cMap.put("cCount", count);//当前序个数
    247                 orderMap.put(titleLvl, cMap);
    248 
    249             }else{//父节点为非文档标题
    250                 int count= 0;
    251                 //如果没有相邻的父节点信息,当前标题级别自动升级
    252                 if(null==pMap){
    253                     return getOrderCode(String.valueOf(parentTitleLvl));
    254                 }else{
    255                     String pOrder = String.valueOf(pMap.get("cOrder"));//父节点序
    256                     if(null==cMap){//没有当前节点信息
    257                         cMap = new HashMap<String, Object>();
    258                     }else{
    259                         count = Integer.parseInt(String.valueOf(cMap.get("cCount")));//当前序个数
    260                     }
    261                     count++;
    262                     order = pOrder+"."+count;//当前序编号
    263                     cMap.put("cOrder", order);//当前序
    264                     cMap.put("cCount", count);//当前序个数
    265                     orderMap.put(titleLvl, cMap);
    266                 }
    267             }
    268 
    269             //字节点标题计数清零
    270             int childTitleLvl = Integer.parseInt(titleLvl)+1;//子节点标题级别
    271             Map<String,Object> cdMap = orderMap.get(childTitleLvl+"");//
    272             if(null!=cdMap){
    273                 cdMap.put("cCount", 0);//子节点序个数
    274                 orderMap.get(childTitleLvl+"").put("cCount", 0);
    275             }
    276         }
    277         return order;
    278     }
    279 
    280     public static void main(String[] args) {
    281         InputStream is = null;
    282         XWPFDocument doc=null;
    283         OutputStream out=null;
    284         String[] title= new String [276];
    285         String[] concent= new String [276];
    286         String[] type= new String [276];
    287         int i=0;
    288         try {
    289             XWPFDocument createDoc = new XWPFDocument();
    290 
    291             is = new FileInputStream("E:/doc/a.docx");
    292             doc = new XWPFDocument(is);
    293             //获取段落
    294             List<XWPFParagraph> paras=doc.getParagraphs();
    295 
    296             for (XWPFParagraph para : paras){
    297               //System.out.println(para.getCTP());//得到xml格式
    298               //System.out.println(para.getStyleID());//段落级别
    299              // System.out.println(para.getParagraphText());//段落内容
    300               String titleLvl = getTitleLvl(doc,para);//获取段落级别
    301               if("a5".equals(titleLvl)||"HTML".equals(titleLvl)||"".equals(titleLvl)||null==titleLvl){
    302                   titleLvl = "8";
    303               }
    304             //System.out.println(titleLvl+"-----");//0,1,2
    305              if(!"8".equals(titleLvl)){
    306                 //System.out.println(titleLvl+"===="+para.getParagraphText());
    307                 
    308                 if("3".equals(titleLvl)) {
    309                     
    310                     if(concent[i]!=null)
    311                     concent[i]=concent[i]+para.getParagraphText();
    312                     else
    313                     concent[i]=para.getParagraphText();
    314                     //System.out.println(concent[i]);
    315                 }
    316                 if("2".equals(titleLvl)) {
    317                     i++;
    318                     title[i]=para.getParagraphText();
    319                     type[i]=type[i-1];
    320                     //System.out.println(title[i]);
    321                 }
    322                 if("1".equals(titleLvl)) {
    323                     i++;
    324                     type[i]=para.getParagraphText();     
    325                     //System.out.println(title[i]);
    326                 }
    327             }
    328             
    329 
    330             }
    331             for(int j=2;j<title.length;j++) {
    332                 if(title[j]!=null) {
    333                     String sql = "INSERT INTO shuju (title,concent,type)VALUES ('"+title[j]+"','"+concent[j]+"','"+type[j]+"')";
    334                     DBUtil jdbc=new DBUtil();
    335                     int result=jdbc.executeUpdate(sql);
    336                     jdbc.close();
    337                     //System.out.println(type[j]);
    338                 //System.out.println(title[j]);
    339                 //System.out.println(concent[j]);
    340                 }
    341             }
    342         } catch (Exception e) {
    343             e.printStackTrace();
    344         } finally{
    345             try {
    346                 if(null!=out){
    347                     out.close();
    348                 } 
    349                 if(null!=is){
    350                     is.close();
    351                 }
    352             }catch (IOException e) {
    353                 e.printStackTrace();
    354             }
    355         }
    356     }
    357 }

    ps:331到341是导入到数据库的需要新建数据库工具类

    你自己弄就OK

    如果是单纯的读取的话用下面的代码,因为上面比较繁琐我都不太理解,下面的代码比较简单易懂,当然功能相对也少,只能读取所有内容不能识别标题

    借鉴的哪一篇博客因为时间太长了,我忘了,抱歉

      1 package com.poi.test;
      2  
      3 import java.io.File;
      4 import java.io.FileInputStream;
      5 import java.io.InputStream;
      6  
      7 import org.apache.poi.POIXMLDocument;
      8 import org.apache.poi.POIXMLTextExtractor;
      9 import org.apache.poi.hwpf.extractor.WordExtractor;
     10 import org.apache.poi.openxml4j.opc.OPCPackage;
     11 import org.apache.poi.xwpf.extractor.XWPFWordExtractor;
     12  
     13 public class testPoi {
     14     /**
     15      * 读取word文件内容
     16      * 
     17      * @param path
     18      * @return buffer
     19      */
     20  
     21     public String readWord(String path) {
     22         String buffer = "";
     23         try {
     24             if (path.endsWith(".doc")) {
     25                 InputStream is = new FileInputStream(new File(path));
     26                 WordExtractor ex = new WordExtractor(is);
     27                 buffer = ex.getText();
     28                 ex.close();
     29             } else if (path.endsWith("docx")) {
     30                 OPCPackage opcPackage = POIXMLDocument.openPackage(path);
     31                 POIXMLTextExtractor extractor = new XWPFWordExtractor(opcPackage);
     32                 buffer = extractor.getText();
     33                 extractor.close();
     34             } else {
     35                 System.out.println("此文件不是word文件!");
     36             }
     37  
     38         } catch (Exception e) {
     39             e.printStackTrace();
     40         }
     41  
     42         return buffer;
     43     }
     44  
     45     public static void main(String[] args) {
     46         // TODO Auto-generated method stub
     47         testPoi tp = new testPoi();
     48         String content = tp.readWord("自己的路径.doc");
     49         //String arr[]=content.split("\d+");
     50         //String arr[]=content.split("第"+"\w"+"章");
     51         String arr[]=content.split("\r\n");
     52         /*String[] a=arr[13].split("\d+");
     53         String[] b=a[1].split("\s+");
     54         System.out.println(b[1]);*/
     55         String[] reci = new String [276];;
     56         for(int i=12,j=0;i<290;i++,j++) {
     57             arr[i]=arr[i]+"1";
     58             if(!arr[i].equals("1")) {
     59             
     60             if(i<27) {//判断页面数是否为单数
     61                 String[] a=arr[i].split("\d+|\s+");
     62             if(arr[i]!="\s+") {//判断该元素是否为连续空格
     63                 if(a.length==2) {//判断该元素是否为标题即分割成2个段
     64                     reci[j]=a[1];
     65                 System.out.println(a[1]);
     66                 }
     67                 else if(a.length==1) {
     68                     reci[j]=a[1];
     69                 System.out.println(arr[i]);
     70                 }
     71                 else//否则该元素是平常元素可以分割成3个段
     72                     {
     73                     reci[j]=a[2];
     74                     System.out.println(a[2]);
     75                     }
     76                 }
     77         }
     78             else {
     79                 String[] a=arr[i].split("\d{2,3}|\s+|\t");
     80                     if(arr[i]!="\s+") {//判断该元素是否为连续空格
     81                         if(a.length==2) {
     82                             reci[j]=a[1];
     83                             System.out.println(a[1]);
     84                         }
     85                         else if(a.length==1) {
     86                             reci[j]=a[1];
     87                             System.out.println(arr[i]+i);
     88                         }
     89                         else if(a.length==4) {
     90                             reci[j]=a[1];
     91                             System.out.println(a[1]);
     92                         }
     93                         else
     94                             {reci[j]=a[2];
     95                             System.out.println(a[2]);
     96                             }
     97                     }
     98             }
     99         }
    100     }
    101         String fengefu=reci[0];
    102         for(int i=1;i<276;i++) {
    103             if(reci[i]!=null)
    104         fengefu=fengefu+"|"+reci[i];
    105 
    106         }
    107         System.out.println(reci[275]);
    108         System.out.println(fengefu);
    109         String arr2[]=content.split(fengefu);
    110         for(int i=0;i<200;i++)
    111             System.out.println(arr2[i]);
    112     }
    113 }

    还有下面这一种方法,与上面相似

     1 package com.xxx.util;
     2  
     3 import java.io.File;
     4 import java.io.FileInputStream;
     5 import java.io.IOException;
     6  
     7 import org.apache.poi.hwpf.extractor.WordExtractor;
     8  
     9 public class DocUtil {
    10     /**
    11      * 读取doc文件内容
    12      * 
    13      * @param file
    14      *            想要读取的文件对象
    15      * @return 返回文件内容
    16      * @throws IOException
    17      */
    18     public static String doc2String(FileInputStream fs) throws IOException {
    19         StringBuilder result = new StringBuilder();
    20         WordExtractor re = new WordExtractor(fs);
    21         result.append(re.getText());
    22         re.close();
    23         return result.toString();
    24     }
    25  
    26     public static String doc2String(File file) throws IOException {
    27         return doc2String(new FileInputStream(file));
    28     }
    29  
    30     public static void main(String[] args) {
    31         File file = new File("自己的路径.doc");
    32         try {
    33             System.out.println(doc2String(file));
    34         } catch (IOException e) {
    35             e.printStackTrace();
    36         }
    37     }
    38 }

    结果截图因为一部分原因就不贴出来了

    当然对于poi我还是比较陌生,希望大牛们批评指正

    文学使思想充满血与肉,他比科学和哲学更能给予思想以巨大的明确性和说明性。
  • 相关阅读:
    HDU 2594 Simpsons’ Hidden Talents(辛普森一家的潜在天赋)
    HUD 2203 亲和串
    POJ 3461 Oulipo(乌力波)
    FJNU 1154 Fat Brother And His Love(胖哥与女神)
    Polygon Triangles
    Double it(水题模拟+逆向思维)
    Sphenic numbers(素数筛)
    Desktop(模拟)2016-2017 ACM Central Region of Russia Quarterfinal Programming Contest
    Weather Station(基础DP)2016-2017 ACM Central Region of Russia Quarterfinal Programming Contest
    找零钱(经典DP)
  • 原文地址:https://www.cnblogs.com/zpsblog/p/10568267.html
Copyright © 2011-2022 走看看