...">

Using the xslt key to find unique values

<ROOT> <AA Aattr="xyz1"> <BB bAttr1="firefox" bAttr2="aaa" > </BB> <BB bAttr1="chrome" bAttr2="aaa" > </BB> <BB bAttr1="firefox" bAttr2="bbb" > </BB> <BB bAttr1="chrome" bAttr2="bbb" > </BB> </AA> <AA Aattr="xyz2"> <BB bAttr1="firefox" bAttr2="aaa" > </BB> <BB bAttr1="chrome" bAttr2="ccc" > </BB> <BB bAttr1="firefox" bAttr2="ddd" > </BB> </AA> 

I want to select the various \ unique attitute 'bAttr2' values ​​in node 'BB', from node 'AA', where the attribute 'Aattr' is xyz1

let's say for this xml, I need to output as "aaa", "bbb"

I tried the following logic with a key. But it didn’t work. Please, help

 <xsl:key name="nameDistinct" match="BB" use="@bAttr1"/> <xsl:template match="/"> <xsl:for-each select="ROOT/AA[@Aattr='xyz1']"> <xsl:for-each select="BB[generate-id()=generate-id(key('nameDistinct',@bAttr2)[1])]"> <xsl:value-of select="@bAttr2"/> </xsl:for-each> </xsl:for-each> </xsl:template> 
+4
source share
2 answers

You have two options:

Filter out the elements available for the key when you define it:

  <xsl:key name="nameDistinct" match="AA[@Aattr = 'xyz1']/BB" use="@bAttr2"/> <xsl:template match="/"> <xsl:for-each select="ROOT/AA/BB[generate-id() = generate-id(key('nameDistinct', @bAttr2)[1])]"> <xsl:value-of select="@bAttr2"/> </xsl:for-each> </xsl:template> 

or filter inside a grouping expression:

  <xsl:key name="nameDistinct" match="BB" use="@bAttr2"/> <xsl:template match="/"> <xsl:for-each select="ROOT/AA/BB[generate-id() = generate-id(key('nameDistinct', @bAttr2) [../@Aattr = 'xyz1'] [1])]"> <xsl:value-of select="@bAttr2"/> </xsl:for-each> </xsl:template> 

the former approach is slightly less dirty and slightly more efficient, while the latter allows you to parameterize the grouping (ie the group by values ​​that are not hardcoded as "xyz1"), for example:

  <xsl:key name="nameDistinct" match="BB" use="@bAttr2"/> <xsl:template match="/"> <xsl:for-each select="ROOT/AA"> <xsl:for-each select="BB[generate-id() = generate-id(key('nameDistinct', @bAttr2) [../@Aattr = current()/@Aattr] [1])]"> <xsl:value-of select="@bAttr2"/> </xsl:for-each> </xsl:for-each> </xsl:template> 
+2
source

This conversion is :

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:key name="kCompoundAttribs" match="BB" use="concat(generate-id(..), '+', @bAttr2)"/> <xsl:template match="/"> <xsl:copy-of select= "/*/*[1]/* [generate-id() = generate-id(key('kCompoundAttribs', concat(generate-id(..),'+', @bAttr2) )[1] ) ]"/> </xsl:template> </xsl:stylesheet> 

when applied to the provided XML document:

 <ROOT> <AA Aattr="xyz1"> <BB bAttr1="firefox" bAttr2="aaa" ></BB> <BB bAttr1="chrome" bAttr2="aaa" ></BB> <BB bAttr1="firefox" bAttr2="bbb" ></BB> <BB bAttr1="chrome" bAttr2="bbb" ></BB> </AA> <AA Aattr="xyz2"> <BB bAttr1="firefox" bAttr2="aaa" ></BB> <BB bAttr1="chrome" bAttr2="ccc" ></BB> <BB bAttr1="firefox" bAttr2="ddd" ></BB> </AA> </ROOT> 

creates two BB elements whose bAttr2 attributes have the desired set of different values (if you only need the string values ​​of the attributes, just use xsl:apply-templates or xsl:for-each for this expression):

 <BB bAttr1="firefox" bAttr2="aaa"/> <BB bAttr1="firefox" bAttr2="bbb"/> 

Please note :

This solution is simpler and more understandable and more efficient than "filtering" :)

+2
source

All Articles