Как выбрать первый узел для каждого значения данного атрибута, используя XSLT? - PullRequest
1 голос
/ 10 марта 2011

У меня есть документ, который выглядит следующим образом:

<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» и один раз для"бар".Поскольку они идентичны, мне все равно, какой из них используется для вызова этого шаблона.

После ответов на Выбор уникальных узлов на основе комбинации двух значений атрибута , япроизвел этот код:

<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 недостаточно силен, чтобы понять, что это может быть.

Ответы [ 2 ]

1 голос
/ 10 марта 2011

Просто замените :

//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>&#xA;</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
1 голос
/ 10 марта 2011

Я бы предложил заменить ваш шаблон на:

<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])].

...