如何动态生成/修改XSLT参数名以批量传递Java参数?
问题描述
我正尝试借助XSLT模板生成XML,需要生成若干标签相同但内部值不同的元素。现有XSLT样式代码如下:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="NbOfBatches"/> <xsl:param name="wholeTag"/> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/> <xsl:template match="/"> <Document xmlns="urn:something" xmlns:file="someUrn"> <FileAppHdr> <file:NbOfBatches><xsl:value-of select="$NbOfBatches"></xsl:value-of></file:NbOfBatches> <xsl:call-template name="selects"> <xsl:with-param name="i">1</xsl:with-param> <xsl:with-param name="count"><xsl:value-of select="$NbOfBatches"/></xsl:with-param> </xsl:call-template> </FileAppHdr> </Document> </xsl:template> <xsl:template name="selects"> <xsl:param name="i" /> <xsl:param name="count" /> <xsl:if test="$i <= $count"> <xsl:call-template name="credit"> <xsl:with-param name="param0"/> </xsl:call-template> </xsl:if> <xsl:if test="$i <= $count"> <xsl:call-template name="selects"> <xsl:with-param name="i"> <xsl:value-of select="$i + 1"/> </xsl:with-param> <xsl:with-param name="count"> <xsl:value-of select="$count"/> </xsl:with-param> </xsl:call-template> </xsl:if> </xsl:template> <xsl:template name="credit"> <xsl:param name="param0"/> <CreditTransfer> <xsl:value-of select="$param0"/> </CreditTransfer> </xsl:template> </xsl:stylesheet>
目前可通过Saxon或JAXP调用.setParameter()传入NbOfBatches参数控制生成标签数量,但希望能动态生成/修改CreditTransfer中的param0参数名,以便在Java中循环调用.setParameter("param1", value1)、.setParameter("param2", value2)等传递不同参数值。
解决方案
方法1:使用参数集合(推荐,XSLT 2.0+兼容)
如果使用Saxon支持的XSLT 2.0及以上版本,建议直接传递值序列作为单个参数,避免逐个命名param1、param2,代码更简洁易维护:
修改后的XSLT代码
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="NbOfBatches" as="xs:integer"/> <!-- 接收值序列参数 --> <xsl:param name="CreditValues" as="xs:string*"/> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/> <xsl:template match="/"> <Document xmlns="urn:something" xmlns:file="someUrn"> <FileAppHdr> <file:NbOfBatches><xsl:value-of select="$NbOfBatches"/></file:NbOfBatches> <!-- 直接遍历值序列生成元素 --> <xsl:for-each select="$CreditValues[position() le $NbOfBatches]"> <CreditTransfer> <xsl:value-of select="."/> </CreditTransfer> </xsl:for-each> </FileAppHdr> </Document> </xsl:template> </xsl:stylesheet>
Java调用示例
// 假设使用Saxon的Processor Processor processor = new Processor(false); XsltCompiler compiler = processor.newXsltCompiler(); XsltExecutable executable = compiler.compile(new File("your-style.xsl")); XsltTransformer transformer = executable.load(); // 构造值序列 List<String> creditValues = Arrays.asList("value1", "value2", "value3"); // 传递序列参数 transformer.setParameter(new QName("CreditValues"), processor.newArray(creditValues.stream().map(processor::newStringValue).toArray(XdmValue[]::new))); // 执行转换(省略输出逻辑)
方法2:动态查找命名参数(XSLT 1.0兼容,依赖Saxon扩展)
如果必须保留逐个命名param1、param2的方式,可以借助Saxon的扩展函数动态获取参数值:
修改后的XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:saxon="http://saxon.sf.net/" extension-element-prefixes="saxon"> <xsl:param name="NbOfBatches"/> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/> <xsl:template match="/"> <Document xmlns="urn:something" xmlns:file="someUrn"> <FileAppHdr> <file:NbOfBatches><xsl:value-of select="$NbOfBatches"/></file:NbOfBatches> <xsl:call-template name="selects"> <xsl:with-param name="i">1</xsl:with-param> <xsl:with-param name="count" select="$NbOfBatches"/> </xsl:call-template> </FileAppHdr> </Document> </xsl:template> <xsl:template name="selects"> <xsl:param name="i" /> <xsl:param name="count" /> <xsl:if test="$i <= $count"> <!-- 动态构造参数名,比如param1、param2 --> <xsl:variable name="paramName" select="concat('param', $i)"/> <CreditTransfer> <!-- 使用Saxon扩展获取参数值 --> <xsl:value-of select="saxon:evaluate(concat('$', $paramName))"/> </CreditTransfer> <!-- 递归调用 --> <xsl:call-template name="selects"> <xsl:with-param name="i" select="$i + 1"/> <xsl:with-param name="count" select="$count"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet>
Java调用示例
// 使用Saxon的TransformerFactory TransformerFactory factory = new net.sf.saxon.TransformerFactoryImpl(); Transformer transformer = factory.newTransformer(new StreamSource("your-style.xsl")); int nbOfBatches = 3; transformer.setParameter("NbOfBatches", String.valueOf(nbOfBatches)); // 循环设置param1到paramN for (int i = 1; i <= nbOfBatches; i++) { transformer.setParameter("param" + i, "value" + i); } // 执行转换(省略输出逻辑)
方法3:XSLT 1.0节点集参数(兼容旧版处理器)
如果只能用XSLT 1.0且不能用Saxon扩展,可以传递XML节点集作为参数:
Java端构造节点集
// 构造包含所有值的XML片段 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.newDocument(); Element root = doc.createElement("Values"); for (int i = 1; i <= nbOfBatches; i++) { Element value = doc.createElement("Value"); value.setTextContent("value" + i); root.appendChild(value); } // 设置参数,将节点集传入 transformer.setParameter("CreditValues", root);
修改后的XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:param name="NbOfBatches"/> <xsl:param name="CreditValues"/> <xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/> <xsl:template match="/"> <Document xmlns="urn:something" xmlns:file="someUrn"> <FileAppHdr> <file:NbOfBatches><xsl:value-of select="$NbOfBatches"/></file:NbOfBatches> <xsl:for-each select="$CreditValues/Value[position() <= $NbOfBatches]"> <CreditTransfer> <xsl:value-of select="."/> </CreditTransfer> </xsl:for-each> </FileAppHdr> </Document> </xsl:template> </xsl:stylesheet>
内容的提问来源于stack exchange,提问作者Priku
相关产品推荐
相关产品推荐

