zoukankan      html  css  js  c++  java
  • POI解析word文件,并为特定规则的key替换值

    转载: https://www.aliyun.com/jiaocheng/778166.html

    模板替换内容key是: ${enforcername1}

    
    

    package com.jsy.test.pdf;

    
    

    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;

    
    

    import org.apache.poi.POIXMLDocument;
    import org.apache.poi.openxml4j.opc.OPCPackage;
    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.XWPFTable;
    import org.apache.poi.xwpf.usermodel.XWPFTableCell;
    import org.apache.poi.xwpf.usermodel.XWPFTableRow;

    
    

    public class WordReplace {

    
    

    /*
    * 在Word文档中段落的最小的操作单位是XWPFRun,正常的一个段落,会被分割成多个小的XWPFRun,这些XWPFRun组合在一起就是一个完整的段落。
    *
    *
    * 通常我们在Word文档中做的标记${mark_1},在文档中会被分割成多个XWPFRun,所以我们没法使用一个XWPFRun来进行标记文本替换。在这里,
    * 我们想到一个方法,就是使用类似于找到字符串中子串下标的方法,找到段落XWPFRun中子Run下标,记录起始和终止下标,在终止下标后insertNewRun
    * (int pos),然后再从终止下标往前xwpfParagraph.removeRun(i);到起始下标。
    *
    *
    * 这个方法可以以整个段落位单位进行标记文本替换。然后遍历文档中所有的段落进行替换。 全部代码如下:
    */

    
    

    /**
    * 替换所有段落中的标记
    *
    * @param xwpfParagraphList
    * @param params
    */
    public static void replaceInAllParagraphs(List<XWPFParagraph> xwpfParagraphList, Map<String, String> params) {
    for (XWPFParagraph paragraph : xwpfParagraphList) {
    if (paragraph.getText() == null || paragraph.getText().equals(""))
    continue;
    for (String key : params.keySet()) {
    if (paragraph.getText().contains(key)) {
    System.err.println("旧值: "+key);
    replaceInParagraph(paragraph, key, params.get(key));
    }
    }
    }
    }

    
    

    /**
    * 替换段落中的字符串
    *
    * @param xwpfParagraph
    * @param oldString
    * @param newString
    */
    public static void replaceInParagraph(XWPFParagraph xwpfParagraph, String oldString, String newString) {
    Map<String, Integer> pos_map = findSubRunPosInParagraph(xwpfParagraph, oldString);
    System.err.println(pos_map.toString());
    if (pos_map != null) {
    System.out.println("start_pos:" + pos_map.get("start_pos"));
    System.out.println("end_pos:" + pos_map.get("end_pos"));
    List<XWPFRun> runs = xwpfParagraph.getRuns();
    XWPFRun modelRun = runs.get(pos_map.get("end_pos"));
    XWPFRun xwpfRun = xwpfParagraph.insertNewRun(pos_map.get("end_pos") + 1);
    System.err.println(newString);
    xwpfRun.setText(newString);

    System.out.println("字体大小:" + modelRun.getFontSize());
    if (modelRun.getFontSize() != -1)
    xwpfRun.setFontSize(modelRun.getFontSize());// 默认值是五号字体,但五号字体getFontSize()时,返回-1
    xwpfRun.setFontFamily(modelRun.getFontFamily());
    for (int i = pos_map.get("end_pos"); i >= pos_map.get("start_pos"); i--) {
    System.out.println("remove run pos in :" + i);
    xwpfParagraph.removeRun(i);
    }
    }
    }

    
    

    /**
    * 找到段落中子串的起始XWPFRun下标和终止XWPFRun的下标
    *
    * @param xwpfParagraph
    * @param substring
    * @return
    */
    public static Map<String, Integer> findSubRunPosInParagraph(XWPFParagraph xwpfParagraph, String substring) {
    List<XWPFRun> runs = xwpfParagraph.getRuns();
    int start_pos = 0;
    int end_pos = 0;
    String subtemp = "";
    for (int i = 0; i < runs.size(); i++) {
    subtemp = "";
    start_pos = i;
    for (int j = i; j < runs.size(); j++) {
    if (runs.get(j).getText(runs.get(j).getTextPosition()) == null)
    continue;
    subtemp += runs.get(j).getText(runs.get(j).getTextPosition());
    if (subtemp.equals(substring)) {
    end_pos = j;
    Map<String, Integer> map = new HashMap<>();
    map.put("start_pos", start_pos);
    map.put("end_pos", end_pos);
    return map;
    }
    }
    }
    return null;
    }

    
    

    // 对表格中标记文本的替换
    // 有些标记做在表格单元格中,每个单元格中的内容都是一个普通的段落,所以,我们只需遍历出所有的单元格,然后遍历出每个单元格中的所有段落,再调用以上方法进行标记文本替换即可。代码如下

    
    

    /**
    * 替换所有的表格
    *
    * @param xwpfTableList
    * @param params
    */
    public static void replaceInTables(List<XWPFTable> xwpfTableList, Map<String, String> params) {
    for (XWPFTable table : xwpfTableList) {
    replaceInTable(table, params);
    }
    }

    
    

    /**
    * 替换一个表格中的所有行
    *
    * @param xwpfTable
    * @param params
    */
    public static void replaceInTable(XWPFTable xwpfTable, Map<String, String> params) {
    List<XWPFTableRow> rows = xwpfTable.getRows();
    replaceInRows(rows, params);
    }

    
    

    /**
    * 替换表格中的一行
    *
    * @param rows
    * @param params
    */
    public static void replaceInRows(List<XWPFTableRow> rows, Map<String, String> params) {
    for (int i = 0; i < rows.size(); i++) {
    XWPFTableRow row = rows.get(i);
    replaceInCells(row.getTableCells(), params);
    }
    }

    
    

    /**
    * 替换一行中所有的单元格
    *
    * @param xwpfTableCellList
    * @param params
    */
    public static void replaceInCells(List<XWPFTableCell> xwpfTableCellList, Map<String, String> params) {
    for (XWPFTableCell cell : xwpfTableCellList) {
    replaceInCell(cell, params);
    }
    }

    
    

    /**
    * 替换表格中每一行中的每一个单元格中的所有段落
    *
    * @param cell
    * @param params
    */
    public static void replaceInCell(XWPFTableCell cell, Map<String, String> params) {
    List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
    replaceInAllParagraphs(cellParagraphs, params);
    }

    
    

    // 调用方法测试
    public static void main(String[] args) throws IOException, Exception {
    // TODO Auto-generated method stub
    String filepathString = "C:\Users\Administrator\Desktop\现场笔录.docx";
    String destpathString = "C:\Users\Administrator\Desktop\现场笔录_new.docx";
    Map<String, String> map = new HashMap<String, String>();
    map.put("${enforcername1}", "小白鼠");
    map.put("${enforcername2}", "喵喵喵");
    map.put("${drivername}", "卡特琳娜");
    map.put("${driverphone}", "15112345678");

    
    

    OPCPackage pack = POIXMLDocument.openPackage(filepathString);
    XWPFDocument document = new XWPFDocument(pack);
    /**
    * 对段落中的标记进行替换
    */
    List<XWPFParagraph> parasList = document.getParagraphs();
    replaceInAllParagraphs(parasList, map);
    /**
    * 对表格中的标记进行替换
    */
    List<XWPFTable> tables = document.getTables();
    replaceInTables(tables, map);
    FileOutputStream outStream = null;
    try {
    outStream = new FileOutputStream(destpathString);
    document.write(outStream);
    outStream.flush();
    outStream.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }

    
    

    }

    
    
    
     

    个人感觉有点慢,15KB的文件需要750ms,希望如果有大佬有好的方案可以评论区告诉我!因为我这个还要转PDF然后立即预览的,所以尽量缩减时间.

    我现在的方法网页预览需要5164毫秒.

  • 相关阅读:
    计算机体系结构的铁律(iron law)
    PHP 画图——使用jpgraph画图
    理解Paxos Made Practical
    【bzoj1015】【JSOI2008】【星球大战】【并查集+离线】
    Spark调研笔记第3篇
    hduoj2094产生冠军
    使用HD/IDE层的ioctl接口获取磁盘容量get_hdd_max_sector
    给GridView设置行高
    tomcat的一些简单配置
    【JavaScript】--JavaScript总结一览无余
  • 原文地址:https://www.cnblogs.com/yxgmagic/p/9851367.html
Copyright © 2011-2022 走看看