如何用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
相关产品推荐
相关产品推荐

