You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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实体(比如把<转成&lt;),反而会让<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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 18:15:36