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

如何基于YAML配置生成XSLT 3.0模板?附Java实现场景

解决方案:从YAML规则生成XSLT 3.0模板及模板调用问题处理

一、先明确规则到XSLT的映射逻辑

首先把YAML里的转换规则对应到标准XSLT模板的写法,这是解决问题的基础:

  • 元素移除:生成空匹配模板,匹配到目标元素时不输出任何内容
    <xsl:template match="要移除的元素名"/>
    
  • 元素重命名:匹配原元素,输出新元素名并继承其子节点/属性
    <xsl:template match="原元素名">
      <新元素名>
        <xsl:apply-templates select="@* | node()"/>
      </新元素名>
    </xsl:template>
    
  • 属性修改:匹配目标属性,输出新属性名和处理后的值
    <xsl:template match="目标元素/@原属性名">
      <xsl:attribute name="新属性名">
        <xsl:value-of select="属性值处理逻辑(比如concat('prefix-', .))"/>
      </xsl:attribute>
    </xsl:template>
    

二、解决模板内调用模板的问题

根据你当前用Saxon s9api+扩展函数的场景,分两种方案处理:

方案1:静态生成完整XSLT文件(推荐)

既然已经用SnakeYAML把YAML解析成Java对象,直接在Java层拼接XSLT代码字符串,生成完整的.xsl文件,再用Saxon编译执行。这种方式完全规避动态模板调用的问题,因为所有模板都是预定义的静态结构。

示例Java代码片段:

// 假设transformations是解析后的YAML转换规则列表
StringBuilder xsltBuilder = new StringBuilder();
xsltBuilder.append("<xsl:stylesheet version='3.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>");
// 添加默认复制模板(保留未匹配的节点)
xsltBuilder.append("<xsl:template match='@* | node()'><xsl:copy><xsl:apply-templates select='@* | node()'/></xsl:copy></xsl:template>");

for (Transformation rule : transformations) {
    switch (rule.getType()) {
        case "remove":
            xsltBuilder.append(String.format("<xsl:template match='%s'/>", rule.getMatch()));
            break;
        case "rename":
            xsltBuilder.append(String.format("<xsl:template match='%s'><%s><xsl:apply-templates select='@* | node()'/></%s></xsl:template>",
                    rule.getMatch(), rule.getNewName(), rule.getNewName()));
            break;
        case "modify-attribute":
            xsltBuilder.append(String.format("<xsl:template match='%s'><xsl:attribute name='%s'><xsl:value-of select='%s'/></xsl:attribute></xsl:template>",
                    rule.getMatch(), rule.getNewAttr(), rule.getNewValue()));
            break;
    }
}
xsltBuilder.append("</xsl:stylesheet>");

// 将xsltBuilder的内容写入文件,再用Saxon编译执行

方案2:运行时动态构建XSLT模板(适配你的s9api场景)

如果必须在运行时动态传递规则而不生成文件,直接用Saxon s9api的API动态创建XSLT模板节点,添加到样式表中,确保所有模板都是静态存在的,避免动态调用问题。

示例Java代码片段:

Processor processor = new Processor(false);
XsltCompiler compiler = processor.newXsltCompiler();

// 基础样式表(包含默认复制模板)
String baseXslt = "<xsl:stylesheet version='3.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>"
        + "<xsl:template match='@* | node()'><xsl:copy><xsl:apply-templates select='@* | node()'/></xsl:copy></xsl:template>"
        + "</xsl:stylesheet>";

XdmNode baseStylesheet = processor.newDocumentBuilder().build(new StringReader(baseXslt));
XsltPackage pack = compiler.compilePackage(baseStylesheet.asSource());

// 遍历转换规则,动态添加模板
for (Transformation rule : transformations) {
    if ("rename".equals(rule.getType())) {
        // 创建rename模板节点
        Element template = processor.getUnderlyingConfiguration().getDocumentBuilder()
                .newElement(new QName("http://www.w3.org/1999/XSL/Transform", "template"));
        template.setAttribute("match", rule.getMatch());
        
        Element newElement = processor.getUnderlyingConfiguration().getDocumentBuilder()
                .newElement(new QName(rule.getNewName()));
        Element applyTemplates = processor.getUnderlyingConfiguration().getDocumentBuilder()
                .newElement(new QName("http://www.w3.org/1999/XSL/Transform", "apply-templates"));
        applyTemplates.setAttribute("select", "@* | node()");
        
        newElement.appendChild(applyTemplates);
        template.appendChild(newElement);
        // 添加到样式表顶层
        pack.getPrincipalStylesheetModule().getContents().add(template);
    } else if ("remove".equals(rule.getType())) {
        // 创建空的remove模板
        Element template = processor.getUnderlyingConfiguration().getDocumentBuilder()
                .newElement(new QName("http://www.w3.org/1999/XSL/Transform", "template"));
        template.setAttribute("match", rule.getMatch());
        pack.getPrincipalStylesheetModule().getContents().add(template);
    }
    // 属性修改规则的动态创建逻辑类似
}

// 生成可执行的XSLT并执行转换
XsltExecutable executable = pack.load();
XsltTransformer transformer = executable.newTransformer();
// 后续设置输入输出、执行转换...

方案3:在XSLT内直接处理规则(无需调用模板)

如果不想动态生成模板,也可以在XSLT模板内通过扩展函数获取规则,用<xsl:choose>分支直接执行转换逻辑,完全避免模板调用:

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:my="自定义扩展函数命名空间">
    <xsl:template match="@* | node()">
        <xsl:variable name="rule" select="my:get-transformation-rule(.)"/>
        <xsl:choose>
            <xsl:when test="$rule/@type = 'rename'">
                <xsl:element name="{$rule/@new-name}">
                    <xsl:apply-templates select="@* | node()"/>
                </xsl:element>
            </xsl:when>
            <xsl:when test="$rule/@type = 'remove'">
                <!-- 不输出内容 -->
            </xsl:when>
            <xsl:when test="$rule/@type = 'modify-attribute'">
                <xsl:copy>
                    <xsl:for-each select="@*">
                        <xsl:choose>
                            <xsl:when test="local-name() = $rule/@match-attr">
                                <xsl:attribute name="{$rule/@new-attr}">
                                    <xsl:value-of select="$rule/@new-value"/>
                                </xsl:attribute>
                            </xsl:when>
                            <xsl:otherwise>
                                <xsl:copy/>
                            </xsl:otherwise>
                        </xsl:choose>
                    </xsl:for-each>
                    <xsl:apply-templates select="node()"/>
                </xsl:copy>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy>
                    <xsl:apply-templates select="@* | node()"/>
                </xsl:copy>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

内容的提问来源于stack exchange,提问作者I. Riahi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 07:27:03