如何使用docx4j将docx模板中未赋值的变量设为空字符串?
问题
我在.docx文档中用${<变量名>}格式定义了若干变量,通过docx4j的VariablePrepare.prepare(doc)和document.getMainDocumentPart().variableReplace(placeholders)方法,结合Map数据替换变量。但如果Map中缺少部分变量,替换后的文档会直接显示变量名称,而非空字符串。
现有代码如下:
VariablePrepare.prepare(document); val placeholders = new HashMap<>(PLACEHOLDERS_STATIC); if (data != null) { final HashMap<String, String> dynamicPlaceholders = new HashMap<>() {{ put("firstName", "First name"); put("firstNameVal", data.getFirstName()); put("childTable", "Child"); put("lastName", "Last name"); }}; placeholders.putAll(dynamicPlaceholders); document.getMainDocumentPart().variableReplace(placeholders); }
模板效果:
替换后效果:
我希望未填充的变量显示为空字符串而非变量名,能否通过docx4j实现?手动给大量文档的所有变量设置空值过于耗时。
当前依赖:
<dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j-JAXB-ReferenceImpl</artifactId> <version>11.4.9</version> </dependency>
解决方案
方法1:自动补全缺失变量为空值
先从docx模板中提取所有定义的变量,再将Map中不存在的变量自动设为空字符串,无需手动维护:
- 提取模板中所有
${xxx}格式的变量名; - 遍历变量列表,为Map中缺失的变量添加空值映射;
- 执行默认的变量替换方法。
示例代码:
// 1. 提取模板中的所有变量 List<String> allVariables = extractAllVariables(document); // 2. 补全缺失变量为空值 for (String var : allVariables) { placeholders.putIfAbsent(var, ""); } // 3. 执行替换 document.getMainDocumentPart().variableReplace(placeholders); // 提取变量的工具方法 private List<String> extractAllVariables(WordprocessingMLPackage doc) throws Exception { List<String> variables = new ArrayList<>(); Pattern pattern = Pattern.compile("\\$\\{([^}]+)\\}"); // 遍历文档所有段落 List<P> paragraphs = doc.getMainDocumentPart().getContents().getBody().getP(); for (P p : paragraphs) { String text = XmlUtils.unwrap(p).toString(); Matcher matcher = pattern.matcher(text); while (matcher.find()) { variables.add(matcher.group(1)); } } // 去重后返回 return new ArrayList<>(new HashSet<>(variables)); }
方法2:自定义变量替换逻辑
绕过docx4j默认的variableReplace方法,直接遍历文档文本节点,对未匹配到的变量直接替换为空字符串:
示例代码:
// 自定义变量替换方法 public void replaceVariables(WordprocessingMLPackage doc, Map<String, String> placeholders) throws Exception { VariablePrepare.prepare(doc); Pattern pattern = Pattern.compile("\\$\\{([^}]+)\\}"); // 遍历文档中所有文本节点 List<Object> textNodes = doc.getMainDocumentPart().getJAXBNodesViaXPath("//w:t", false); for (Object node : textNodes) { Text text = (Text) node; String content = text.getValue(); Matcher matcher = pattern.matcher(content); StringBuffer sb = new StringBuffer(); while (matcher.find()) { String varName = matcher.group(1); // 变量不存在则替换为空字符串 String replacement = placeholders.getOrDefault(varName, ""); matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement)); } matcher.appendTail(sb); text.setValue(sb.toString()); } } // 使用自定义方法替换变量 replaceVariables(document, placeholders);
内容的提问来源于stack exchange,提问作者MarekChr
相关产品推荐
相关产品推荐

