我的编程空间,编程开发者的网络收藏夹
学习永远不晚

完美解决docx4j变量替换的问题

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

完美解决docx4j变量替换的问题

docx4j变量替换的问题

最近工作上需要自己完成word文档变量替换的问题

把里面的变量给替换成数据库里的值,但是由于在word文档渲染成xml的时候,会通过某些原因把字段放在不同层次的xml标签

上面是docx4j文档说的原因,大概是字体格式不同(我的问题是用了粗体 ${ 和 正常中文是不同格式的),拼写语法问题,编辑顺序。

在StackOverflow 找了很久解决方案,Variableprepare.prepare方法确实测试后能解决部分替换问题,但还是不能满足我的需求。

阅读源码后重新清扫了一下字符串。

测试代码

  public static void main(String[] args) throws Exception {
        File file = new File("C:\\Users\\scoli\\Desktop\\t.docx");
        WordprocessingMLPackage doc = WordprocessingMLPackage.load(new FileInputStream(file));
        Docx4jUtils.cleanDocumentPart(doc.getMainDocumentPart());
        Map map = new HashMap();
        map.put("订单编号", "1");
        OutputStream outputStream = new FileOutputStream(new File("C:\\Users\\scoli\\Desktop\\test1.docx"));
        MainDocumentPart mainDocumentPart = doc.getMainDocumentPart();
        if (!map.isEmpty()) {
            // 替换文本内容
            mainDocumentPart.variableReplace(map);
        }
        // 输出word文件
        doc.save(outputStream);
        outputStream.flush();
    }

docx4j版本

 <!--docx4j支持 start-->
        <dependency>
            <groupId>org.docx4j</groupId>
            <artifactId>docx4j</artifactId>
            <version>3.3.6</version>
            <exclusions>
                <exclusion>
                    <groupId>org.slf4j</groupId>
                    <artifactId>slf4j-log4j12</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.docx4j</groupId>
            <artifactId>docx4j-export-fo</artifactId>
            <version>3.3.6</version>
        </dependency>
        <!--docx4j支持 end-->

下面是工具类

package zwy.saas.common.util;  
import org.docx4j.XmlUtils;
import org.docx4j.jaxb.Context;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart;
import org.docx4j.wml.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.Map;
import java.util.regex.Pattern;
 

public final class Docx4jUtils {
 
    private static final Logger logger = LoggerFactory.getLogger(Docx4jUtils.class);
 
    
    public static void downloadDocUseDoc4j(InputStream inputStream, Map<String, String> map,
                                          HttpServletResponse response, String fileName) {
 
        try {
            // 设置响应头
            fileName = URLEncoder.encode(fileName, "UTF-8");
            response.setContentType("application/octet-stream;charset=UTF-8");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-Disposition", "attachment; filename=" + fileName + ".docx");
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
 
            OutputStream outs  = response.getOutputStream();
            Docx4jUtils.replaceDocUseDoc4j(inputStream,map,outs);
 
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }
 
    
    public static void replaceDocUseDoc4j(InputStream inputStream, Map<String, String> map,
                                          OutputStream outputStream) {
        try {
            WordprocessingMLPackage doc = WordprocessingMLPackage.load(inputStream);
            MainDocumentPart mainDocumentPart = doc.getMainDocumentPart();
            if (null != map && !map.isEmpty()) {
                // 将${}里的内容结构层次替换为一层
                Docx4jUtils .cleanDocumentPart(mainDocumentPart);
                // 替换文本内容
                mainDocumentPart.variableReplace(map);
            }
 
            // 输出word文件
            doc.save(outputStream);
            outputStream.flush();
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }
 
 
    
    public static boolean cleanDocumentPart(MainDocumentPart documentPart) throws Exception {
        if (documentPart == null) {
            return false;
        }
        Document document = documentPart.getContents();
        String wmlTemplate =
                XmlUtils.marshaltoString(document, true, false, Context.jc);
        document = (Document) XmlUtils.unwrap(DocxVariableClearUtils.doCleanDocumentPart(wmlTemplate, Context.jc));
        documentPart.setContents(document);
        return true;
    }
 
    
    private static class DocxVariableClearUtils {
 
 
        
        private static final Pattern XML_PATTERN = Pattern.compile("<[^>]*>");
 
        private DocxVariableClearUtils() {
        }
 
        
        private static final char PREFIX = '$';
 
        
        private static final char LEFT_BRACE = '{';
 
        
        private static final char RIGHT_BRACE = '}';
 
        
        private static final int NONE_START = -1;
 
        
        private static final int NONE_START_INDEX = -1;
 
        
        private static final int PREFIX_STATUS = 1;
 
        
        private static final int LEFT_BRACE_STATUS = 2;
 
        
        private static final int RIGHT_BRACE_STATUS = 3;
 
 
        
        private static Object doCleanDocumentPart(String wmlTemplate, JAXBContext jc) throws JAXBException {
            // 进入变量块位置
            int curStatus = NONE_START;
            // 开始位置
            int keyStartIndex = NONE_START_INDEX;
            // 当前位置
            int curIndex = 0;
            char[] textCharacters = wmlTemplate.toCharArray();
            StringBuilder documentBuilder = new StringBuilder(textCharacters.length);
            documentBuilder.append(textCharacters);
            // 新文档
            StringBuilder newDocumentBuilder = new StringBuilder(textCharacters.length);
            // 最后一次写位置
            int lastWriteIndex = 0;
            for (char c : textCharacters) {
                switch (c) {
                    case PREFIX:
                        // TODO 不管其何状态直接修改指针,这也意味着变量名称里面不能有PREFIX
                        keyStartIndex = curIndex;
                        curStatus = PREFIX_STATUS;
                        break;
                    case LEFT_BRACE:
                        if (curStatus == PREFIX_STATUS) {
                            curStatus = LEFT_BRACE_STATUS;
                        }
                        break;
                    case RIGHT_BRACE:
                        if (curStatus == LEFT_BRACE_STATUS) {
                            // 接上之前的字符
                            newDocumentBuilder.append(documentBuilder.substring(lastWriteIndex, keyStartIndex));
                            // 结束位置
                            int keyEndIndex = curIndex + 1;
                            // 替换
                            String rawKey = documentBuilder.substring(keyStartIndex, keyEndIndex);
                            // 干掉多余标签
                            String mappingKey = XML_PATTERN.matcher(rawKey).replaceAll("");
                            if (!mappingKey.equals(rawKey)) {
                                char[] rawKeyChars = rawKey.toCharArray();
                                // 保留原格式
                                StringBuilder rawStringBuilder = new StringBuilder(rawKey.length());
                                // 去掉变量引用字符
                                for (char rawChar : rawKeyChars) {
                                    if (rawChar == PREFIX || rawChar == LEFT_BRACE || rawChar == RIGHT_BRACE) {
                                        continue;
                                    }
                                    rawStringBuilder.append(rawChar);
                                }
                                // FIXME 要求变量连在一起
                                String variable = mappingKey.substring(2, mappingKey.length() - 1);
                                int variableStart = rawStringBuilder.indexOf(variable);
                                if (variableStart > 0) {
                                    rawStringBuilder = rawStringBuilder.replace(variableStart, variableStart + variable.length(), mappingKey);
                                }
                                newDocumentBuilder.append(rawStringBuilder.toString());
                            } else {
                                newDocumentBuilder.append(mappingKey);
                            }
                            lastWriteIndex = keyEndIndex;
 
                            curStatus = NONE_START;
                            keyStartIndex = NONE_START_INDEX;
                        }
                    default:
                        break;
                }
                curIndex++;
            }
            // 余部
            if (lastWriteIndex < documentBuilder.length()) {
                newDocumentBuilder.append(documentBuilder.substring(lastWriteIndex));
            }
            return XmlUtils.unmarshalString(newDocumentBuilder.toString(), jc);
        } 
    }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

完美解决docx4j变量替换的问题

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

DedeCMS关键词替换问题较完美解决方法

问题描述 织梦内容关键词替换的时候存在一个错误:如果拥有www.cppcns.com两个关键词,例如“CIT”(www.cithttp://www.cppcns.com.cn/tags/cit.html)和&ldqu
2022-06-12

github访问速度慢的问题完美解决

这篇文章主要为大家介绍了github访问速度慢的问题完美解决方案,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2022-11-13

完美解决gvim的菜单乱码问题

gvim的菜单乱码问题的解决方法:(乱码是由于系统内码不兼容导致,系统内码包括gb2312 gb18030 utf-8 utf-16[unicode]等) 生成文件 ~/.gvimrc 并添加如下语句: set encoding=chine
2022-06-04

NODE.JS跨域问题的完美解决方案

这几天公司同事(前端)写页面的时候一直说拿不到想要的JSON,安卓iOS那边是可以拿到的,但他也是新手也不知道为什么只知道是js跨域问题,然后问我我也不懂前端我开始百度, 有人说是谷歌浏览器跨域要设置一下,然后我就在谷歌浏览器的目标后面加一
2022-06-04

怎么解决Python字符串替换的问题

本篇内容主要讲解“怎么解决Python字符串替换的问题”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么解决Python字符串替换的问题”吧!项目中遇到一个字符串替换的问题。我们知道字符串替换可
2023-06-16

如何解决php正则替换乱码的问题

今天小编给大家分享一下如何解决php正则替换乱码的问题的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、什么是PHP正则表达
2023-07-06

完美解决Jpush[获取sdk版本失败!]的问题

错误日志如下:5-31 12:47:40.088 23896-23896/ E/JIGUANG-JCore: [JCoreGlobal] Get sdk version fail![获取sdk版本失败!]05-31 12:47:40.088
2023-05-31

完美解决QT QGraphicsView提升到QChartView报错的问题

使用QT提供的QChartView来绘制图表,提升QGraphicsView控件继承QChartView后,然后将QGraphicsView提升到我们自己写的类,怎么才能确保提升后编译不报错呢,下面小编给大家带来了QTQGraphicsView提升到QChartView报错解决方案,感兴趣的朋友一起看看吧
2023-05-19

完美解决liunx下dns配置重启失效的问题

有时候能ping同ip地址,却ping不通域名,这就是dns没有配置的缘故。 但是DNS配置文件 /etc/resolv.conf 每次重启就会失效。 打开这个配置文件,发现有注释提示:Dynamic resolv.conf(5) file
2022-06-04

完美解决Spring声明式事务不回滚的问题

疑问,确实像往常一样在service上添加了注解 @Transactional,为什么查询数据库时还是发现有数据不一致的情况,想想肯定是事务没起作用,出现异常的时候数据没有回滚。于是就对相关代码进行了一番测试,结果发现一下踩进了两个坑,确实
2023-05-31

python 采集中文乱码问题的完美解决方法

近几日遇到采集某网页的时候大部分网页OK,少部分网页出现乱码的问题,调试了几日,终于发现了是含有一些非法字符造成的..特此记录 1. 在正常情况下..可以用import chardetthischarset = chardet.detect
2022-06-04

ubuntu 16.04系统完美解决pip不能升级的问题

原来环境:64位ubuntu 16.04 LTS系统,pip版本为8 问题:使用提示命令pip install –upgrade pip也无法解决升级 解决方法:源码安装pip-9.0.1 1 从pip官网下载压缩包pip
2022-06-04

完美解决node.js中使用https请求报CERT_UNTRUSTED的问题

只要调用了没有受信的https就会报错:CERT_UNTRUSTED 简单的解决方法就是设置环境变量回避非授信证书的问题。 只要在请求的代码之前加上如下代码即可: process.env.NODE_TLS_REJECT_UNAUTHORIZ
2022-06-04

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录