如何使用 XSLT 为给定属性的每个值选择第一个节点?

发布于 2024-10-21 21:15:37 字数 1058 浏览 2 评论 0原文

我有一个如下所示的文档:

<template>
 <otherstuff>
 <group name="foo">
 ...stuff...
 </group>
</template>
<template>
 <otherstuff>
 <group name="bar">
 ...different stuff...
 </group>
</template>
<template>
 <otherstuff>
 <group name="foo">
 ...same stuff as first foo group...
 </group>
</template>

我想要做的是为给定组名的每个实例调用特定模板 - 因此一次为“foo”,一次为“bar”。由于它们是相同的,所以我不在乎使用它们中的哪一个来调用此模板。

按照的答案选择基于两个属性值的组合,我生成了以下代码:

<xsl:key name="groupsByName" match="//group" use="@name"/>

<xsl:template match="/">
    <xsl:for-each select="//group[count(.|key('groupsByName',@name)[1])!=1]">
        <xsl:call-template name="template-or-group"/>
    </xsl:for-each>
</xsl:template>

但是,结果是未调用模板。我还怀疑,由于我的案例比我基于代码的问题更简单,因此可能有一种更简单的方法。不过,我的 XSLT 还不够强大,无法弄清楚它可能是什么。

I have a document that looks like this:

<template>
 <otherstuff>
 <group name="foo">
 ...stuff...
 </group>
</template>
<template>
 <otherstuff>
 <group name="bar">
 ...different stuff...
 </group>
</template>
<template>
 <otherstuff>
 <group name="foo">
 ...same stuff as first foo group...
 </group>
</template>

What I want to do is to call a particular template for each instance of a given group name - so once for "foo" and once for "bar". Since they're identical, I don't care which of them is used to call this template.

Following the answers to Select unique nodes based on a combination of two attribute values, I've produced this code:

<xsl:key name="groupsByName" match="//group" use="@name"/>

<xsl:template match="/">
    <xsl:for-each select="//group[count(.|key('groupsByName',@name)[1])!=1]">
        <xsl:call-template name="template-or-group"/>
    </xsl:for-each>
</xsl:template>

The result, however, is that the template isn't called. I also suspect that since my case is simpler than the question I based my code on, there's probably a simpler way. My XSLT isn't strong enough to work out what it might be, though.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

幽梦紫曦~ 2024-10-28 21:15:38

我建议将您的模板替换为:

<xsl:template match="group[generate-id(.) = generate-id(key('groupsByName',@name)[1])]">
  ....
</xsl:template>

或者将您的 xpath 表达式更改为 //group[generate-id(.) =generate-id(key('groupsByName',@name)[1])].

count(.|some-node-set) 通常用于检查某个节点是否属于集合。在这里,您需要将当前节点与每个组的第一个唯一节点进行比较。此外,改进 Xpath 表达式并仅匹配那些具有 @name 属性的组元素也可能很有用。说了这么多,我们得到://group[@name][generate-id(.) =generate-id(key('groupsByName', @name)[1])]

I would suggest to replace your template with:

<xsl:template match="group[generate-id(.) = generate-id(key('groupsByName',@name)[1])]">
  ....
</xsl:template>

Or just change your xpath expression to //group[generate-id(.) = generate-id(key('groupsByName',@name)[1])].

count(.|some-node-set) is usually used to check whether some node belongs to the set or not. Here you need to compare current node with the first some unique node for each group. Also it might be useful to improve an Xpath expression and match only those group elements which have @name attributes. Having said all this we get: //group[@name][generate-id(.) = generate-id(key('groupsByName', @name)[1])].

梦里的微风 2024-10-28 21:15:38

只需替换

//group[count(.|key('groupsByName',@name)[1])!=1]

//group[count(.|key('groupsByName',@name)[1])=1]

这是一个完整的解决方案

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="groupsByName" match="//group"
      use="@name"/>

 <xsl:template match="/">
  <xsl:for-each select=
   "//group[count(.|key('groupsByName',@name)[1])=1]">
   <xsl:call-template name="template-or-group"/>
  </xsl:for-each>
 </xsl:template>

 <xsl:template name="template-or-group">
  <xsl:value-of select="@name"/>
  <xsl:text>
</xsl:text>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于提供的 XML 文档时(固定为良好) -形成):

<t>
    <template>
        <otherstuff/>
        <group name="foo">  ...stuff...  </group>
    </template>
    <template>
        <otherstuff/>
        <group name="bar">  ...different stuff...  </group>
    </template>
    <template>
        <otherstuff/>
        <group name="foo">  ...same stuff as first foo group...  </group>
    </template>
</t>

产生了想要的正确结果:

foo
bar

Just replace:

//group[count(.|key('groupsByName',@name)[1])!=1]

with:

//group[count(.|key('groupsByName',@name)[1])=1]

Here is a complete solution:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output method="text"/>

 <xsl:key name="groupsByName" match="//group"
      use="@name"/>

 <xsl:template match="/">
  <xsl:for-each select=
   "//group[count(.|key('groupsByName',@name)[1])=1]">
   <xsl:call-template name="template-or-group"/>
  </xsl:for-each>
 </xsl:template>

 <xsl:template name="template-or-group">
  <xsl:value-of select="@name"/>
  <xsl:text>
</xsl:text>
 </xsl:template>
</xsl:stylesheet>

when this transformation is applied on the provided XML document (fixed to be well-formed):

<t>
    <template>
        <otherstuff/>
        <group name="foo">  ...stuff...  </group>
    </template>
    <template>
        <otherstuff/>
        <group name="bar">  ...different stuff...  </group>
    </template>
    <template>
        <otherstuff/>
        <group name="foo">  ...same stuff as first foo group...  </group>
    </template>
</t>

the wanted, correct result is produced:

foo
bar
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文