【问题标题】:Conditionaly assign variable to match path in xslt template有条件地分配变量以匹配 xslt 模板中的路径
【发布时间】:2019-06-18 02:34:45
【问题描述】:

我想在 xslt 模板中动态构建匹配。我使用 xls fo 和 apache fop 和 saxon9he。最好的方式是我想从 java 传递参数,但首先我尝试在 xslt 中设置它。

当我像这样创建变量示例时:

<xsl:variable name="testPath" select="/abc:Files/def:Description" /> 

如果我尝试在应用模板中使用它也可以正常工作:

<xsl:apply-templates select="$testPath/qwe:Test"/>

但我想动态设置 testPath 变量。我尝试使用选择标签:

<xsl:variable name="testPath"> 
    <xsl:choose>
        <xsl:when test="$versionNo = '2'">
             <xsl:value-of select="/abc:Files/def:Description" />   
        </xsl:when>
        <xsl:otherwise>
             <xsl:value-of select="/abc:Files/def:Names" /> 
        </xsl:otherwise>
    </xsl:choose>
</xsl:variable> 

但是这种方法不起作用,当我尝试使用这个变量时:

<xsl:apply-templates select="$testPath/qwe:Test"/>

我收到此错误:

在第 82 行第 21 列评估 ((attr{table-layout=...}, ...)) 时出错 pdf_gen.xsl:SXCH0003:org.apache.fop.fo.ValidationException: “fo:table-body”缺少子元素。所需内容模型: 标记* (table-row+|table-cell+)(见位置 82:21):
文件:/C:/Users/SuperUser/workspace/project/xls-editor/target/classes/pdf/xsl/pdf_gen.xsl:82:21: “fo:table-body”缺少子元素。所需内容模型: marker* (table-row+|table-cell+) (见位置 82:21)

最好的选择是我想将 Java 中的 $testPath 变量作为参数传递,例如:

transformer.setParameter("testPath ", "/abc:Files/def:Description");

并在 xslt 中使用

<xsl:param name="testPath "/>

并在模板中应用:

<xsl:apply-templates select="$testPath/qwe:Test"/>

但我收到以下错误:

类型错误评估 ($testPath) 在 xsl:apply-templates/@select 在第 74 行第 60 列 pdf_gen.xsl: XPTY0019: 所需的项目类型 '/' 的第一个操作数是 node();提供的值
u"/abc:Files/def:Description" 是一个原子值

为什么没有任何解决方案可以实现它?

【问题讨论】:

  • 您使用的是哪种 XSLT 处理器?
  • 我使用 xsl fo 和 apache fop 和 saxon。
  • 第一个错误由 FOP 处理器引发,只是告诉您在 XSLT 代码中构造的 XSL-FO 无效,table-body 没有所需的子级。因此,要获得这方面的帮助,您需要展示最少但完整的相关 sn-ps,以便我们查看您拥有哪些 XML、您想要创建哪个 XSL-FO 以及您当前获得了哪个。第二个错误XPTY0019 建议您使用 XSLT 2 或 3 处理器,确定是 Saxon 9.8 还是 9.9,您可以选择使用静态参数和影子属性,但可能仅使用 s9api。
  • 当我使用内联声明时,第一种方法效果很好:&lt;xsl:variable name="testPath" select="/abc:Files/def:Description" /&gt; 但在选择标签中,即使我在 when 和其他地方输入相同的值,这也不好用。我认为问题是&lt;xsl:value-of&gt; 但我可以用它来代替它。
  • 您使用的是哪个版本的 Saxon 9?那是9.8还是9.9?这些实现了 XSLT 3,您可以在其中执行例如&lt;xsl:param name="testPath" as="xs:string" static="yes"/&gt; 然后是阴影属性 &lt;xsl:apply-templates _select="{$testPath}/qwe:Test"/&gt; 如果确实需要这种方法。另一方面,由于需要在编译之前设置静态参数,我不确定您是否可以使用 JAXP API 设置它们,使用 Saxon 9 的 s9api 可能会更好甚至是必要的。

标签: java pdf xslt conditional variable-assignment


【解决方案1】:

当您使用 Saxon 9 时,您至少使用 XSLT 2 和 XPath 2,我建议在 XPath 中使用例如实现变量选择

<xsl:variable name="testPath" select="if ($versionNo = '2') then /abc:Files/def:Description else /abc:Files/def:Names"/> 

这样你的

<xsl:apply-templates select="$testPath/qwe:Test"/>

应该可以很好地处理先前选择的def:Descriptiondef:Names 元素的qwe:Test 子元素。

当然也可以使用例如

<xsl:apply-templates select="(if ($versionNo = '2') then /abc:Files/def:Description else /abc:Files/def:Names)/qwe:Test"/>

或者做例如

<xsl:apply-templates select="(/abc:Files/def:Description[$versionNo = '2'], /abc:Files/def:Names[$versionNo != '2'])/qwe:Test"/>

【讨论】:

    【解决方案2】:

    我正在处理类似的问题。 在我看来,变量可见性仅在 &lt;xsl:choose&gt; 块内,我建议您制作模板块并以这种方式调用它们:

    <xsl:choose>
        <xsl:when test="$versionNo = '2'" >
            <xsl:call-template name="TemplateOne">
                <xsl:with-param name="testPath" select="'/abc:Files/def:Description'" />
            </xsl:call-template>
        </xsl:when>
        <xsl:otherwise>
            <xsl:call-template name="TemplateTwo">
                <xsl:with-param name="testPath" select="'/abc:Files/def:Names'" />
            </xsl:call-template>
        </xsl:otherwise>
    </xsl:choose>
    

    模板定义为:

    <xsl:template name="TemplateOne">
        <xsl:param name="testPath" />
        ...
        bla bla bla
        remember to use variable in this template as "{$testPath}"
        ...
    </xsl:template>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-18
      • 2012-06-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多