Reputation: 73
I am a bit new to XSLT so I apologise for the basic question.
I am trying to create an XSL stylesheet that will pull out from the XML (below) the third <cell>
- i.e. CODE1, CODE2 - value from each node and place it into a dropdown box. I also want to compare each of the nodes and take anything that is repetitive out so that it will only show one instance of CODE1 and CODE2 rather than CODE1, CODE1, CODE2.
XML:
<dvm>
<description>This is a description</description>
<columns>
<column name="lang"/>
<column name="text"/>
<column name="code" qualifier="true" order="1"/>
<column name="comm" qualifier="true" order="2"/>
<column name="subj"/>
<column name="copy"/>
<column name="flag"/>
</columns>
<rows>
<row>
<cell>English</cell>
<cell></cell>
<cell>CODE1</cell>
<cell>Fixed</cell>
<cell>Title1</cell>
<cell/><cell/>
<cell/><cell/>
</row>
<row>
<cell>English</cell>
<cell></cell>
<cell>CODE1</cell>
<cell>Wired</cell>
<cell>Title2</cell>
<cell/><cell/>
<cell/><cell/>
</row>
<row>
<cell>English</cell>
<cell></cell>
<cell>CODE2</cell>
<cell>Fixed</cell>
<cell>Title3</cell>
<cell/><cell/>
<cell/><cell/>
</row>
</dvm>
Upvotes: 0
Views: 973
Reputation: 3696
When you are able to apply XSLT 2.0, then use the following:
<xsl:value-of select="distinct-values(dvm/rows/row/cell[3])"/>
In XSLT 1.0, use Muenchian grouping as mentioned by Michael Kay. A demonstration:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="Cells" match="dvm/rows/row/cell[3]" use="."/>
<xsl:template match="/">
<root>
<w>
<xsl:for-each select="dvm/rows/row/cell[3]">
<item>
<xsl:value-of select="."/>
</item>
</xsl:for-each>
</w>
<z>
<xsl:for-each select="dvm/rows/row/cell[3]">
<xsl:if test="generate-id() = generate-id(key('Cells', .)[1])">
<item>
<xsl:value-of select="."/>
</item>
</xsl:if>
</xsl:for-each>
</z>
</root>
</xsl:template>
</xsl:stylesheet>
which leads to the following result:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<w>
<item>CODE1</item>
<item>CODE1</item>
<item>CODE2</item>
</w>
<z>
<item>CODE1</item>
<item>CODE2</item>
</z>
</root>
Explanation:
xsl:key
assigns key values to each occurrence of the node constructed from match / use
values - the cell[3]
values you wish to focus on. Then loop through all these cell[3]
values, checking whether the value has a unique id (each node has a unique id which can be accessed by applying the generate-id()
function) equal to the id of the first element in the set of nodes with the same key value (this set is selected by using the key()
function). Effectively you are checking whether the node processed is the same node as the first one in the node-set defined by the Cells
key when applied on the current node value as key value.
Actually the index [1]
is superfluous because when it is left out, the equality is checked with the first element of the set anyway, because generate-id(..node-set..)
will automatically only generate an id for the first node in the node-set, but it is a little bit neater to add the index.
Note that this leads to selecting just one occurrence of the CODE1
cell[3] values.
A practical application of this could be to define an xsl:variable
with contents equal to those of the <z>
element above (hence, the xsl:for-each
etcetera), then use that variable to loop through the <item>
elements in it and show these in the list you were speaking about.
Upvotes: 0
Reputation: 163675
Removing duplicates is a special case of the class of problems generally called "grouping". There are a couple of features in XSLT 2.0 to help with grouping problems, the distinct-values() function and the xsl:for-each-group instruction. In XSLT 1.0 it's more difficult: search for "Muenchian grouping" (or wait for someone with more time than I have to explain it here...)
Upvotes: 2