在Word(docx)模板的Freemarker中解析HTML标签的问题
解决Freemarker生成Docx时HTML标签不渲染的问题
我之前也踩过一模一样的坑!Docx本质是XML结构,不是HTML,所以Freemarker默认只会把你的字符串当纯文本输出,<b>这种HTML标签自然会原样显示。你试的那些方法没起效,大多是没摸准Docx和Freemarker结合的核心逻辑,下面给你几个可行的解决方案:
方案1:封装文本段对象(最适合简单加粗需求,双层循环也能用)
你之前用LinkedHashMap的思路方向对,但没处理好双层循环的问题。不如把每个需要格式化的文本片段封装成对象,明确标记是否需要加粗:
Java代码部分
先定义一个简单的文本段类:
public class FormattedText { private String content; private boolean isBold; // 构造器、getter、setter按需补充 public FormattedText(String content, boolean isBold) { this.content = content; this.isBold = isBold; } }
然后把你的字符串拆分成带格式的片段列表,双层循环场景也能适配:
// 处理示例字符串 List<FormattedText> textSegments = new ArrayList<>(); textSegments.add(new FormattedText("This is ", false)); textSegments.add(new FormattedText("example", true)); textSegments.add(new FormattedText(" of string", false)); // 双层循环场景:比如每个列表项都包含带格式的文本段 List<YourListItem> items = new ArrayList<>(); YourListItem item = new YourListItem(); item.setTextSegments(textSegments); items.add(item); // 把数据放入Freemarker模型 model.put("items", items);
Docx模板部分
注意:不要直接在Word里编辑模板!你需要把docx文件解压,找到word/document.xml,在对应的段落位置编写Freemarker逻辑:
<!-- 外层循环示例 --> <#list items as item> <w:p> <#list item.textSegments as seg> <w:r> <!-- 按需添加加粗样式 --> <#if seg.isBold> <w:rPr> <w:b/> </w:rPr> </#if> <w:t>${seg.content}</w:t> </w:r> </#list> </w:p> </#list>
这样不管多少层循环,只要数据结构匹配,就能正确渲染加粗样式。
方案2:用Docx4j转HTML为Docx结构(适合复杂HTML格式)
如果你的字符串里不止有<b>,还有<i>、<ul>之类的复杂HTML标签,直接用Docx4j把HTML转换成Docx原生的XML元素最省心:
Java代码部分
import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.convert.in.xhtml.XHTMLImporterImpl; // 你的带HTML标签的字符串 String htmlContent = "This is <b>example</b> of string"; // 初始化Docx4j的HTML转换器 WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.createPackage(); XHTMLImporterImpl xhtmlImporter = new XHTMLImporterImpl(wordMLPackage); xhtmlImporter.setParagraphFormatting(FormattingOption.CLEAN); // 把HTML转成Docx能识别的内容列表 List<Object> formattedContent = xhtmlImporter.convert(htmlContent, null); // 放入Freemarker模型 model.put("formattedContent", formattedContent);
Docx模板部分
同样要在解压后的document.xml里对应位置循环插入内容:
<#list formattedContent as element> ${element} </#list>
Docx4j会自动把<b>转换成<w:rPr><w:b/></w:rPr>这种Docx原生的加粗结构,完全不用你手动拼接XML。
为什么你之前的方法没起效?
[#escape x as x?html]:这个是把特殊字符转成HTML实体(比如把<转成<),反而会让<b>彻底变成纯文本,完全反了方向。- 替换成
<strong>:和<b>一样,Freemarker不会把HTML标签解析成Docx的XML结构,所以没用。 - 直接包裹
<w:t>、<w:r>:如果是在Word里编辑模板输入这些标签,Word会自动把它们转义成纯文本,必须直接编辑解压后的document.xml文件才行。 - 模板里写JavaScript:Docx模板是XML格式,Freemarker根本不会执行JS,当然没用。
内容的提问来源于stack exchange,提问作者Damian Szarik Paul
相关产品推荐
相关产品推荐

