You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在XSLT中实现动态XPath:saxon:evaluate简化for-each-group遇阻

解决Saxon:evaluate简化XSLT重复代码的问题

刚接触XSLT就想着用动态求值来减少重复代码,这个思路很棒!不过你的尝试里有几个关键问题导致报错,咱们一步步拆解修复:

你当前代码的核心问题

  1. 错误地将节点值当成XPath表达式传递:你用<xsl:value-of>把匹配到的节点内容提取成了字符串,但saxon:evaluate需要的是XPath表达式字符串,不是节点的文本内容。比如$oSel里的$compose//*[contains(@outputclass,$sel)]应该是作为字符串传递,而不是直接计算节点后取文本。
  2. 分组表达式的上下文错误group-by里的表达式是针对每个分组节点的,你之前的$oGroup构造没有考虑到这个上下文,导致求值时找不到正确的节点。

修正后的实现方案

首先确保你的XSLT开头声明了Saxon命名空间:

xmlns:saxon="http://saxon.sf.net/"

然后重新构造XPath表达式字符串,而不是直接计算节点:

<!-- 构造选择节点的XPath表达式字符串 -->
<xsl:variable name="selectExpr">
  <xsl:choose>
    <xsl:when test="starts-with($from,'oclass-')">
      <xsl:text>$compose//*[contains(@outputclass, '</xsl:text>
      <!-- 转义单引号避免X语法错误 -->
      <xsl:value-of select="replace($sel, '&apos;', '&apos;&apos;')"/>
      <xsl:text>')]</xsl:text>
    </xsl:when>
    <xsl:when test="starts-with($from,'node-')">
      <xsl:text>$compose//*[name()='</xsl:text>
      <xsl:value-of select="replace($sel, '&apos;', '&apos;&apos;')"/>
      <xsl:text>']</xsl:text>
    </xsl:when>
    <xsl:otherwise>()</xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<!-- 构造分组依据的XPath表达式字符串 -->
<xsl:variable name="groupExpr">
  <xsl:choose>
    <xsl:when test="ends-with($from,'-attribute')">
      <xsl:text>@*[local-name()='</xsl:text>
      <xsl:value-of select="replace($group, '&apos;', '&apos;&apos;')"/>
      <xsl:text>']</xsl:text>
    </xsl:when>
    <xsl:when test="ends-with($from,'-childnode')">
      <xsl:text>*[name()='</xsl:text>
      <xsl:value-of select="replace($group, '&apos;', '&apos;&apos;')"/>
      <xsl:text>']</xsl:text>
    </xsl:when>
    <xsl:when test="ends-with($from,'-parentnode')">
      <xsl:text>parent::*[name()='</xsl:text>
      <xsl:value-of select="replace($group, '&apos;', '&apos;&apos;')"/>
      <xsl:text>']</xsl:text>
    </xsl:when>
    <xsl:when test="ends-with($from,'-followingnode')">
      <xsl:text>following-sibling::*[name()='</xsl:text>
      <xsl:value-of select="replace($group, '&apos;', '&apos;&apos;')"/>
      <xsl:text>'][1]</xsl:text>
    </xsl:when>
    <xsl:when test="ends-with($from,'-precedingnode')">
      <xsl:text>preceding-sibling::*[name()='</xsl:text>
      <xsl:value-of select="replace($group, '&apos;', '&apos;&apos;')"/>
      <xsl:text>'][1]</xsl:text>
    </xsl:when>
    <xsl:otherwise>()</xsl:otherwise>
  </xsl:choose>
</xsl:variable>

<!-- 使用saxon:evaluate执行动态分组 -->
<xsl:for-each-group select="saxon:evaluate($selectExpr)" group-by="saxon:evaluate($groupExpr)">
  <xsl:sort select="current-grouping-key()"/>
  <element key="{current-grouping-key()}">
    <xsl:if test="number(current-group()[1]) = number(current-group()[1])">
      <xsl:attribute name="max" select="max(current-group())"/>
      <xsl:attribute name="sum" select="sum(current-group())"/>
    </xsl:if>
    <xsl:copy-of select="current-group()[1]"/>
  </element>
</xsl:for-each-group>

额外注意事项

  • 单引号转义:用replace($sel, '&apos;', '&apos;&apos;')处理参数中的单引号,避免XPath表达式语法错误。
  • Saxon版本兼容性:你用的9.1.0.8支持saxon:evaluate,但要确保变量$compose在当前上下文可见(如果是全局变量就没问题)。
  • 空值处理:添加<xsl:otherwise>()</xsl:otherwise>避免无效表达式导致的报错。

这样就能实现你想要的动态选择和分组逻辑,大幅减少重复代码啦!

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

火山引擎 最新活动