xml - XSLT1.0 检查是否存在其祖先没有特定属性的后代,但如果有,则其值必须位于 RTF 变量中

标签 xml xslt xpath

我在 XSL 中指定了一个 xsl:variable ($features-list),其中包含来自外部 XML 文件的树片段。

<xsl:variable name="features-list" select="document('features-list.xml', /)" />

此文件包含“feature”元素列表,其中每个元素的值指定一个功能名称。在我尝试转换的 XML 中(它实际上是一个 RNG 模式),某些元素具有方便地命名为“if-feature”的属性,该属性指定此类元素(或者更确切地说整个子树)的副本仅应出现在转换后的文件中。如果这样的属性不存在,或者该属性出现但与外部文件中的特征元素之一具有相同的值,则为文档。这可能意味着结果文档中可能会省略整个子树,因为该属性是从祖先“继承”的。

我已经成功地使用此变量通过检查来触发或省略某些模板

<xsl:when test="not(@if-feature) or @if-feature and $features-list//*[.=current()/@if-feature]">
</xsl:when>

在任何模板中。但这仅在将功能列表中的条目与模板当前正在处理的元素进行比较时才有效。我现在需要的是这样的:

<xsl:apply-templates select="descendant::foo[ancestor-or-self::*[not(@if-feature) or $features-list//*[.=current()/@if-feature]]]"/>

其中 current() 指的是祖先或自身元素之一。我实际上正在尝试基于这样的条件触发模板:仅处理其祖先(及其本身)的当前节点的 foo 后代 - 如果它们具有 if-feature 属性 - 它的值必须与特征元素之一匹配$feature-list 中的值。

我可以仅使用 XPath 表达这样的条件吗?如何?

XSLT 解决方案在这里更合适吗?这可以识别违规元素,但由于 XSLT 的限制,对我帮助不大。

<xsl:for-each select="descendant::foo">
    <xsl:for-each select="ancestor-or-self::*">
      <xsl:choose>
        <xsl:when test="@if-feature and not($features-list//*[.=current()/@if-feature])">
          <!-- we have a hit, break and do not proceed - but wait, this is XSLT, not Java -->
        </xsl:when>
      </xsl:choose>
    </xsl:for-each>
 </xsl:for-each>

在这里尽力学习XSLT 1.0,所以请不要提供2.0的解决方案。

我想要完成的是从指定基于特征的子树的现有 RNG 模式中提取有效的 RNG 模式。我实际上已经这样做了,但它不适用于 ONE 很少发生的微小情况,现在这让我发疯。穿过火墙。还有砖头。

编辑:我的情况说明不清楚,所以我更正了。

最佳答案

<xsl:apply-templates select="
  .//foo[not(
    ancestor-or-self::*[
      @if-feature and not( @if-feature = $features-list//text() )
    ]
  )]
"/>

XPath =运算符比较节点集中的每个节点并产生 true如果其中一个节点满足比较。所以,只需比较 @if-feature到一组节点。

一般说明。

  • XSLT 以声明方式选择正确的节点进行处理和模板匹配为基础。它在这方面非常擅长。命令式编程方法并不好,所以尝试停止思考 Java。
  • 尝试删除<xsl:for-each> 。大多数时候,它弊大于利。使用<xsl:apply-templates><xsl:template>相反。
  • 优先选择正确的节点而不是选择所有节点 - 除非您想处理所有节点。
  • 一旦选择节点,就无法停止循环。但你可以决定它的主体是否被执行。

例如,按字母顺序排列第一个 @if-feature :

<xsl:for-each select="descendant::foo">
  <xsl:sort select="@if-feature" data-type="text" />
  <xsl:if test="position() = 1">
    <!-- ... -->
  </xsl:if>
</xsl:for-each>

这与断点并不完全相同,但具有相同的效果。

关于xml - XSLT1.0 检查是否存在其祖先没有特定属性的后代,但如果有,则其值必须位于 RTF 变量中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9988988/

相关文章:

xslt - 在 xslt 2.0 中使用时区将纪元转换为日期和时间

java - getTextContent() 和 item(0) 在 Java DOM API 中返回什么?

php - 有异常(exception)的 htmlentities

xml - 如何有条件地转换 XML 节点,而不忽略此条件之外的实例?

java - xslt 扩展函数返回字符串

xslt - 如何确定 XSLT 所花费的时间?

xml - 列出persistence.xml 中的所有持久化单元

c# - 无法计算出 XPath 计数表达式结果。 C# xml Web 服务

java - 这相当于在 XML 配置文件中使用 @Autowire 注释 Autowiring 接口(interface)?

xmlstarlet:通过位置号选择元素