midnightflight
midnightflight

Reputation: 41

Use XSLT to find node and specific attribute value

This is an example of my xml code:

<db>
  <group>
  <name>Team1</name>
    <set num="1">AAA</set>
    <set num="2">BBB</set>
    <set num="3">CCC</set>
  </group>
  <group>
  <name>Team2</name>
    <set num="1">DDD</set>
    <set num="2">AAA</set>
    <set num="3">FFF</set>
    <set num="4">EEE</set>
  </group>
  <group>
  <name>Team3</name>
    <set num="1">AAA</set>
    <set num="2">GGG</set>
    <set num="3">FFF</set>
  </group>
  <group>
  <name>Team4</name>
    <set num="1">BBB</set>
    <set num="2">EEE</set>
    <set num="3">AAA</set>
  </group>
</db>

How would I use xslt to display the name and num of all instances where AAA has a num less than 3, so my output would look something like this:

<result value="AAA">
  <name num="1">Team1</name>
  <name num="2">Team2</name>
  <name num="1">Team3</name>
</result>

The code I have been trying to use is as follows:

...
<xsl:template match="/db">
  <result value="AAA">
    <xsl:for-each select="group[set/@num &lt; '3' and set='AAA']">
      <name num="{@num}">
        <xsl:value-of select="name" />
      </name>
    </xsl:for-each>
  </result>
</xsl:template>

But this give me all groups that contain "AAA" regardless of num, and the num always displays as "" no matter what.

Any help would be appreciated as I am new to XSLT. Thanks!

Upvotes: 1

Views: 10324

Answers (1)

MiMo
MiMo

Reputation: 11953

This should do it:

  <xsl:template match="/db">
    <result value="AAA">
      <xsl:for-each select="group[set[@num &lt; 3 and string(.)='AAA']]">
        <name num="{set[@num &lt; 3 and string(.)='AAA']/@num}">
          <xsl:value-of select="name" />
        </name>
      </xsl:for-each>
    </result>
  </xsl:template>

the problem is that set/@num &lt; '3' and set='AAA' tests separately @num and set, whereas what is needed is a set element that matches both conditions at the same time - that is done with the nested restriction [set[@num &lt; 3 and string(.)='AAA']] = all groups that have a set sub-element that has @num less than 3 and contains AAA.

The same test is repeated to get the value of @num from the correct set sub-element.

An alternative to avoid repeating the test:

  <xsl:template match="/db">
    <result value="AAA">
      <xsl:for-each select="group">
        <xsl:variable name="theSet" select="set[@num &lt; 3 and string(.)='AAA']"/>
        <xsl:if test="$theSet">
          <name num="{$theSet/@num}">
            <xsl:value-of select="name" />
          </name>
        </xsl:if>
      </xsl:for-each>
    </result>
  </xsl:template>

Upvotes: 1

Related Questions