【问题标题】:XSL 1.0 distinct values from a template来自模板的 XSL 1.0 不同值
【发布时间】:2013-09-03 00:17:34
【问题描述】:

有人可以帮我解决这个问题吗?

这是我的 XML -

<grandparent>
  <parent>
    <child>apple</child>
  </parent>
  <parent>
    <child>apple</child>
    <child>orange</child>
    <child>apple</child>
    <child>apple</child>
    <child>apple</child>
  </parent>
  <parent>
    <child>pear</child>
    <child>apple</child>
    <child>pear</child>
    <child>pear</child>
  </parent>
</granparent>

我有一个模板,我将 parent 传递给它,它会吐出所有子标签,但我希望它只吐出唯一的子值。

我进行了搜索,每个人使用密钥的建议似乎都不起作用,因为它似乎只获得祖父母范围内的唯一值,而不是父母范围内的唯一值。

这就是我所拥有的-

<xsl:template name="uniqueChildren">
  <xsl:param name="parent" />

  <xsl:for-each select="$parent/child">
    <xsl:value-of select="." />
  </xsl:for-each>
</xsl:template>

目前显示 -

apple
apple orange apple apple apple
pear apple pear pear

我尝试按键时的代码 -

<xsl:key name="children" match="child" use="." />

<xsl:template name="uniqueChildren">
  <xsl:param name="parent" />

  <xsl:for-each select="$parent/child[generate-id() = generate-id(key('children', .)[1])]">
    <xsl:value-of select="." />
  </xsl:for-each>
</xsl:template>

当我尝试使用它显示的键时 -

apple
orange
pear

我希望它显示什么 -

apple
apple orange
pear apple

【问题讨论】:

  • “当我尝试使用密钥时” - 你能展示一下你在这种情况下使用的 XSLT 吗?这可能只是稍微调整键定义以考虑父元素的情况。
  • 我已经包含了上面的关键示例,谢谢。
  • 进一步查看,key 是顶级元素,所以在模板中创建 key 也不起作用,似乎破坏了整个页面......

标签: xml xslt xslt-1.0


【解决方案1】:

您非常接近密钥方法,诀窍是您需要将父节点的身份作为分组密钥的一部分:

<xsl:key name="children" match="child" use="concat(generate-id(..), '|', .)" />

<xsl:template name="uniqueChildren">
  <xsl:param name="parent" />

  <xsl:for-each select="$parent/child[generate-id() = generate-id(
           key('children', concat(generate-id($parent), '|', .))[1])]">
    <xsl:value-of select="." />
  </xsl:for-each>
</xsl:template>

这会创建“&lt;id-of-parent&gt;|apple”、“&lt;id-of-parent&gt;|orange”等形式的键值。


编辑:在您的评论中,您说“在我的实际数据中,子节点不是父节点的直接子节点。父节点和子节点之间有 2 个级别,例如 parent/././child”

在这种情况下,原理相同,您只需要稍微调整一下键即可。关键是键值需要包含定义唯一性检查范围的节点的generate-id。因此,如果您知道您之间总是恰好有两个级别 (parent/x/y/child),那么您会使用

<xsl:key name="children" match="child"
   use="concat(generate-id(../../..), '|', .)" />

或者如果child 元素可能位于parent 中的不同级别,那么您可以使用类似

<xsl:key name="children" match="child"
   use="concat(generate-id(ancestor::parent[1]), '|', .)" />

ancestor::parent[1] 是目标元素的最近祖先,其名称为parent

【讨论】:

  • 感谢 Ian 的回复,但使用上面的代码会返回空白
  • 在我的实际数据中,子节点不是父节点的直接子节点。父母和孩子之间有2个级别,例如parent/././child 有什么不同吗?
  • 我显然已经修改了 for-each 中选择的第一部分以反映这一点
  • 以上是导致问题的原因,在这里找到了我的答案 - concat(generate-id(../../..), '|' etc.
  • @DerekHo 如果你想在祖父母中挑选出不同的值,那么原理是一样的,你只需要调整键以包含正确范围节点的generate-id
猜你喜欢
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 2011-03-08
  • 2022-10-07
  • 1970-01-01
  • 2019-12-07
  • 1970-01-01
  • 2013-05-29
相关资源
最近更新 更多