XSL unique values per node
ok i have this xml
<roots>
<root>
<name>first</name>
<item type='test'><something>A</something></item>
<item type='test'><something>B</something></item>
<item type='test'><something>C</something></item>
<item type='test'><something>A</something></item>
<item type='other'><something>A</something></item>
<item type='test'><something>B</something></item>
<item type='other'><something>D</something></item>
</root>
<root>
<name>second</name>
<item type='test'><something>E</something></item>
<item type='test'><something>B</something></item>
<item type='test'><something>F</something&g开发者_运维百科t;</item>
<item type='test'><something>A</something></item>
<item type='other'><something>A</something></item>
<item type='test'><something>B</something></item>
<item type='other'><something>D</something></item>
</root>
</roots>
now i need to get the unique values of each root node so far i have
<?xml version="1.0" encoding="ISO-8859-1"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="text"/>
<xsl:key name="item-by-value" match="something" use="."/>
<xsl:key name="rootkey" match="root" use="name"/>
<xsl:template match="/">
<xsl:for-each select="key('rootkey','second')">
<xsl:for-each select="item/something">
<xsl:if test="generate-id() = generate-id(key('item-by-value', normalize-space(.)))">
<xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
if i use "First" as the key to get only the first root i get a good result ABCD
how ever if i use "second" i only get EF but i need the result to be ABDFE
I get EBFAD
with a slight modification of your xsl. The key is that if you're using the key to find the first node with this content under the given root element, then the key needs to be specific to the root element. I changed the xsl:key
to:
<xsl:key name="item-by-value" match="something"
use="concat(normalize-space(.), ' ', generate-id(./ancestor::root))"/>
Then the xsl:if
test becomes:
<xsl:if test="generate-id() = generate-id(key('item-by-value',
concat(normalize-space(.), ' ', generate-id(./ancestor::root))))">
This is a case where you must use a compound key.
This transformation:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:key name="kSomethingByNameAndVal" match="something"
use="concat(../../name, '+', .)"/>
<xsl:template match="/">
<xsl:for-each select="*/*">
<xsl:for-each select=
"item/something
[generate-id()
=
generate-id(key('kSomethingByNameAndVal',
concat(../../name, '+', .)
)
)
]
">
<xsl:value-of select="."/>
</xsl:for-each>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
when applied on the provided XML document correctly produces the wanted result:
ABCD
EBFAD
I think you're pretty close. But you only want the first value of the item-by-value key which has the correct root as parent:
<xsl:for-each select="key('rootkey','second')">
<xsl:variable name="root" select="generate-id()" />
<xsl:for-each select="item/something">
<xsl:sort order="ascending" select="." data-type="text"/>
<xsl:if test="generate-id() = generate-id(key('item-by-value', .)[generate-id(ancestor::root)=$root][1])">
<xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
精彩评论