Java / Saxon:以编程方式运行XSL函数

时间:2011-10-17 05:54:10

标签: java xslt saxon

我有一个定义了几个函数的XSL。

我想编写带有XSL函数名称(以及参数列表)的Java代码并运行该函数(当然,将参数绑定到函数的形式参数)。

到目前为止,我唯一的解决方案是使用运行所选功能的主模板动态生成XSL代码。这很尴尬。我正在寻找一种解决方案,让我直接通过Saxon API运行一个函数。

4 个答案:

答案 0 :(得分:1)

XPath Visualizer执行此操作的方式(无论使用何种XSLT处理器)是将主XSL样式表作为XML文档加载,并使用必要的XPath表达式动态修改一个select属性。

像这样

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:import href="yourTrueMainStylesheetModule"/>
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:variable name="vResult" select="."/>

 <xsl:template match="/">
     <xsl:sequence select="$vResult"/>
     </xsl:copy>
 </xsl:template>
</xsl:stylesheet>
  1. 将上述样式表模块加载为XmlDocument。

  2. 问题:SelectNodes("/*/xsl:variable[@name='vResult']/@select")

  3. 使用您的DOM API将所选属性的值修改为所需属性,例如:my:foo(1,2,3)

  4. 使用已加载的(并动态修改的样式表。

  5. 启动转换

    我多年来一直使用XPath Visualizer 2(对于XSLT 2.0 - 未发布)作为FXSL函数的命令行解释器。我可以随意写:

    f:fold(f:mult(), 1, 1 to 4)
    

    并显示正确的结果:

    24
    

    以下是使用XPath Visualizer 2作为FXSL解释器的屏幕截图

    enter image description here

答案 1 :(得分:0)

你可能不能直接,但是你不能让主模板根据你的一个参数调用不同的模板,比如一个大的switch语句。

答案 2 :(得分:0)

有一个API为XQuery(s9api包中的XQueryEvaluator.callFunction())执行此操作,但没有任何可比的XSLT。它可能通过调用正确的低级内部方法序列来实现它,但您可能必须研究源代码才能使其工作。

答案 3 :(得分:0)

XSLT已经具有根据输入文档的内容运行不同指令的功能:模板。我相信如果你已经在运行XSLT,那么乱用Saxon的内部API太麻烦了,只需编译一次这个大型XSLT并重新使用它。

花点时间了解XSLT及其功能性,并使用正确的match表达式将这些函数转换为模板。

我举一个例子。假设我们有两个输入XML:

<myxml>
  <doctype>recipe</doctype>
  <descr>Bread 'n jam sandwich</descr>
  <var>jam</var>
  <var>bread</var>
</myxml>

<myxml>
  <doctype>shoppinglist</doctype>
  <descr>Monday</descr>
  <var>honey</var>
  <var>butter</var>
  <var>loaf of bread</var>
  <var>jam</var>
</myxml>

现在假设我们想要使用正确的格式为这些XML生成HTML。第一个XML应生成带有“Recipe:”的HTML和一系列成分。第二个应该包含一个购物清单。

这是生成两者的XSLT:

<xsl:stylesheet version="2.0"    
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:saxon="http://saxon.sf.net/" 
    exclude-result-prefixes="xs saxon">

<xsl:output method="html" indent="yes"/>

<!-- Generate basic html -->
<xsl:template match="/">
        <html>
            <body><xsl:apply-templates /></body>
        </html>
</xsl:template>

<!-- Only call template doctype element, not for vars -->
<xsl:template match="myxml">
    <xsl:apply-templates select="doctype"/>
</xsl:template>

<xsl:template match="doctype[.='shoppinglist']">
    <h1>Shopping list for <xsl:value-of select="../descr"/></h1>
    <span><b>Stuff to bring:</b></span>
    <ul>
        <xsl:for-each select="../var">
            <li><xsl:value-of select="."/></li>
        </xsl:for-each>
    </ul>
</xsl:template>

<xsl:template match="doctype[.='recipe']">
    <h1>Recipe: <xsl:value-of select="../descr"/></h1>
    <span><b>Ingredients:</b></span>
    <ul>
        <xsl:for-each select="../var">
            <li><xsl:value-of select="."/></li>
        </xsl:for-each>
    </ul>
</xsl:template>

</xsl:stylesheet>

现在查看最后一个模板的match参数。在这种情况下,我根据元素的内容进行选择,但您可以使用您喜欢的任何XPath过滤器表达式(即根据XML参数进行选择)。