【问题标题】:XPath for xml:lang? Testing attribute self axis failsxml:lang 的 XPath?测试属性自轴失败
【发布时间】:2015-03-04 19:36:59
【问题描述】:

上下文是一个 XSLT 身份转换

<xsl:template match="abstract[@xml:lang]">
    <xsl:copy>
       <xsl:apply-templates select="@*[not(self::xml:lang)]|node()"/>
    </xsl:copy>
</xsl:template>

所以,我希望删除属性xml:lang

【问题讨论】:

  • 那又怎样?那时发生了什么?能给个little more context please吗?一个示例输入 XML、一个完整的样式表、输出并解释其中的问题将是一个好的开始。
  • @MathiasMüller,我同意,但答案是如此之快,而且“开放性”对于 3 个优秀且不同的答案很有好处。查看我在 JLRishe 的 cmets,这是对上下文的最佳解释。

标签: xml xslt xpath


【解决方案1】:

您应该已经看到类似以下内容的警告:

警告!自轴永远不会选择任何元素节点时 从属性节点开始

您可以改为测试属性的name()

  <xsl:template match="abstract[@xml:lang]">
    <xsl:copy>
      <xsl:apply-templates select="@*[name() != 'xml:lang']|node()"/>
    </xsl:copy>
  </xsl:template>

这将根据请求有效地从abstract 中删除xml:lang 属性。

【讨论】:

  • OP 会在哪里看到该警告?
  • @JLRishe:SaxonHE9-5-1-2J 针对 OP 的模板发出了该特定警告。
  • 啊。我没有看到任何提到使用 Saxon 的 OP,但也许 OP 过去曾提到过使用它?
  • @JLRishe:对不起,如果我的简洁误导了。仅仅意味着理想情况下 OP 应该看到如下警告(Saxon 提供的消息)。
  • 我明白了。我不知道大多数 XSLT 处理器是否为可能无用的 XPath 提供警告。 .NET 的 XSLT 处理器肯定不会,但仍然感谢您的澄清。
【解决方案2】:

self 轴上永远不会有属性(除非您使用的是 libxslt 处理器...)。
请参阅下面 cmets 中的讨论

你为什么不简单地做:

<xsl:template match="abstract/@xml:lang"/>

要抑制不需要的属性专门


工作演示:http://xsltransform.net/eiZQaFp

【讨论】:

  • 有道理,但这种技术只适用于元素,不适用于属性节点。自己测试...
  • 属性可以在自身轴上。应用于属性的self::node() 会返回属性(但self::* 不会)。
  • @PeterKrauss 我测试我的答案之前我发布它们。我之前发布过此评论,以及一个演示链接,该链接显示我的答案有效。不幸的是,这里有些人认为可以无缘无故地删除我的 cmets。
  • 那是因为node() 等价于child::node(),而不是self::node()
  • 对不起@michael.hor257k,我误会了this other case, for replace attribute value。您的解决方案对于 XSLTv1 (!) 是正确的。当问题实际上只是删除属性时,这是一个有效的解决方案。
【解决方案3】:

这里的问题是self::[QName] 只能引用一个元素,而不是一个属性1

我认为 michael.hor257k 的建议最适合这种特殊情况,并且在这种特殊情况下检查 kjhughes 的答案中的名称应该没问题,因为它与 xml 命名空间有关,这是明确的。

但一般来说,如果你想排除单个属性而不依赖name(),你可以这样做:

<xsl:template match="abstract[@xml:lang]">
    <xsl:copy>
       <xsl:apply-templates select="@*[(. | ../@xml:lang)[2]]|node()"/>
    </xsl:copy>
</xsl:template>

http://xsltransform.net/eiZQaFp/2

这只有在 xml:lang 属性存在时才能正常工作,但您在 match 属性中的模式可确保它确实存在。


  1. 以下是 XPath 规范中的相关文本,解释了为什么会这样:

每个轴都有一个主节点类型。如果一个轴可以包含元素,那么主节点类型是元素;否则,它是轴可以包含的节点的类型。因此,

  • 对于属性轴,主节点类型为属性。
  • 对于命名空间轴,主节点类型是命名空间。
  • 对于其他轴,主节点类型为元素。

当且仅当节点的类型(参见 [5 数据模型])是主要节点类型并且扩展名称等于 QName 指定的扩展名称时,作为 QName 的节点测试为真.例如 child::para 选择上下文节点的 para 元素子项;如果上下文节点没有 para 子节点,它将选择一个空的节点集。 attribute::href 选择上下文节点的 href 属性;如果上下文节点没有 href 属性,它将选择一组空节点。

self::的主节点类型是元素,所以如果后面跟着一个QName(如xml:lang),那么self::xml:lang只能指一个元素,不能指一个属性。

【讨论】:

  • 谢谢,您解释了问题的重点(!)。另一方面,最简单的解决方案和解释是@kjhughes 的:在我看来@*[(. | ../@xml:lang)[2]]|node() 与(更友好的语法)@*[name() != 'xml:lang']|node() 相比有点“加密”。所以你展示了最好的解释(带有良好且相关的w3.org/TR/xpath v1 引用!),kjhughes 是第一个完整的解决方案,michael.hor257k 是最简单的替代方案(对我不好,但对其他读者很好)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-05
  • 2016-10-29
  • 1970-01-01
  • 1970-01-01
  • 2011-05-18
  • 2010-09-16
  • 1970-01-01
相关资源
最近更新 更多