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

如何用Saxon 11.4与Saxon9api从Java向XSLT传递对象列表或DOMSource

用Saxon 9API向XSLT传递DOMSource/对象列表并循环处理

一、传递DOMSource并处理(更适合XSLT生成场景)

如果你的输入是已包含子节点的节点列表,直接传递DOMSource是最直接的方式,无需复杂扩展:

Java端代码

import net.sf.saxon.Processor;
import net.sf.saxon.s9api.*;
import org.w3c.dom.NodeList;
import java.io.File;

public class SaxonDomPassing {
    public static void main(String[] args) throws Exception {
        Processor processor = new Processor(false);
        XsltCompiler compiler = processor.newXsltCompiler();
        XsltExecutable executable = compiler.compile(new StreamSource(new File("input-transformer.xsl")));
        XsltTransformer transformer = executable.load();

        // 假设你已经获取到目标NodeList
        NodeList nodeList = ...;
        // 用Saxon的DocumentBuilder包装DOM节点(避免类型兼容问题)
        DocumentBuilder db = processor.newDocumentBuilder();
        // 如果NodeList没有根节点,先创建一个临时根包裹
        org.w3c.dom.Document doc = nodeList.item(0).getOwnerDocument();
        org.w3c.dom.Element wrapper = doc.createElement("wrapper");
        for (int i = 0; i < nodeList.getLength(); i++) {
            wrapper.appendChild(doc.importNode(nodeList.item(i), true));
        }
        XdmNode inputNodes = db.build(new DOMSource(wrapper));

        // 设置参数,传递节点序列
        transformer.setParameter(new QName("input-nodes"), inputNodes);

        // 设置输出(生成的目标XSLT)
        Serializer serializer = processor.newSerializer(new File("output.xsl"));
        transformer.setDestination(serializer);
        transformer.transform();
    }
}

XSLT端(input-transformer.xsl)

直接接收节点序列并循环处理,生成目标XSLT:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- 声明参数为节点序列 -->
  <xsl:param name="input-nodes" as="node()*"/>

  <xsl:template match="/">
    <!-- 生成目标XSLT的根结构 -->
    <xsl:stylesheet version="2.0">
      <!-- 循环处理传入的节点 -->
      <xsl:for-each select="$input-nodes//your-target-node">
        <!-- 动态生成XSLT模板 -->
        <xsl:template match="{@match-path}">
          <xsl:copy-of select="your-child-node"/>
        </xsl:template>
      </xsl:for-each>
    </xsl:stylesheet>
  </xsl:template>
</xsl:stylesheet>

二、传递Java对象列表并处理

如果必须传递Java对象列表,分两种实现方式:

方式1:直接传递List并调用Java方法

无需自定义扩展函数,利用Saxon原生的Java扩展支持:

Java端代码

List<YourJavaClass> objList = new ArrayList<>();
objList.add(new YourJavaClass("match-path-1", "content-1"));
objList.add(new YourJavaClass("match-path-2", "content-2"));

// 直接将List作为参数传递
transformer.setParameter(new QName("object-list"), objList);

XSLT端代码

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:java="http://saxon.sf.net/java-type"
                exclude-result-prefixes="java">
  <xsl:param name="object-list" as="java:java.util.List"/>

  <xsl:template match="/">
    <xsl:stylesheet version="2.0">
      <!-- 遍历List中的对象 -->
      <xsl:for-each select="java:iterator($object-list)">
        <xsl:variable name="current-obj" select="."/>
        <!-- 调用Java对象的getter方法 -->
        <xsl:template match="{java:getMatchPath($current-obj)}">
          <xsl:value-of select="java:getContent($current-obj)"/>
        </xsl:template>
      </xsl:for-each>
    </xsl:stylesheet>
  </xsl:template>
</xsl:stylesheet>

注意:你的YourJavaClass需要提供public的getter方法(如getMatchPath()、getContent()),Saxon会通过反射调用。

方式2:实现ExtensionFunction(解决你之前的实现问题)

如果需要更灵活的控制,自定义扩展函数是更规范的方式:

1. 实现ExtensionFunction接口

import net.sf.saxon.lib.ExtensionFunction;
import net.sf.saxon.om.*;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.JavaObjectValue;
import javax.xml.namespace.QName;
import java.util.List;

public class ObjectListExtension implements ExtensionFunction {
    private final List<YourJavaClass> objList;

    public ObjectListExtension(List<YourJavaClass> objList) {
        this.objList = objList;
    }

    @Override
    public QName getFunctionQName() {
        // 自定义函数的命名空间和名称
        return new QName("http://your-custom-ns.com/ext", "get-object-list");
    }

    @Override
    public SequenceType[] getArgumentTypes() {
        return new SequenceType[0]; // 该函数无输入参数
    }

    @Override
    public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) {
        // 返回值为YourJavaClass类型的序列
        return SequenceType.makeSequenceType(
                ItemType.makeJavaItemType(YourJavaClass.class),
                OccurrenceIndicator.ZERO_OR_MORE
        );
    }

    @Override
    public Sequence call(XPathContext context, Sequence[] arguments) throws XPathException {
        // 将Java List转换为Saxon的Sequence
        List<Item> items = new ArrayList<>();
        for (YourJavaClass obj : objList) {
            items.add(new JavaObjectValue<>(obj));
        }
        return new SequenceExtent<>(items);
    }
}

2. Java端注册扩展函数

Processor processor = new Processor(false);
// 注册自定义扩展函数
ExtensionFunctionList extFuncList = new ExtensionFunctionList();
extFuncList.add(new ObjectListExtension(objList));
processor.getUnderlyingConfiguration().setExtensionFunctionList(extFuncList);

// 后续编译、加载transformer的步骤和之前一致

3. XSLT端调用扩展函数

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:ext="http://your-custom-ns.com/ext"
                exclude-result-prefixes="ext">
  <xsl:template match="/">
    <xsl:stylesheet version="2.0">
      <!-- 调用自定义扩展函数,遍历返回的对象序列 -->
      <xsl:for-each select="ext:get-object-list()">
        <xsl:variable name="obj" select="."/>
        <xsl:template match="{ext:getMatchPath($obj)}">
          <xsl:value-of select="ext:getContent($obj)"/>
        </xsl:template>
      </xsl:for-each>
    </xsl:stylesheet>
  </xsl:template>
</xsl:stylesheet>

关键注意事项

  • 确保使用的Saxon版本(HE/PE/EE)支持对应功能:ExtensionFunction在HE版本中即可使用,部分高级扩展在PE/EE中提供。
  • 传递DOM时,优先使用Saxon的DocumentBuilder处理,避免跨DOM实现的类型兼容问题。
  • 循环节点/对象序列时,XSLT的xsl:for-each直接支持遍历,无需额外转换。

内容的提问来源于stack exchange,提问作者Iheb RIAHI

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 12:52:49