I have just started to learn XSLT and am having trouble ignoring duplicated elements.
I have been searching through Stack Overflow and have seen people ask similar questions. I tried a small example to see where I was going wrong on my file, and was able to ignore duplicated elements. However the problem for me seems to arise when I have more than one type of an element.
For Example:
File1.xml
<?xml-stylesheet type="text/xsl" href="merge2.xsl"?>
<Main>
<Records>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>B</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
</Records>
</Main>
merge2.xsl
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/Transform">
<xsl:output method="html"/>
<xsl:template match="/">
<table border="1">
<tr>
<th>Type</th>
<th>Count</th>
</tr>
<xsl:for-each select="Main/Records/Record">
<xsl:if test ="not(preceding-sibling::Record(Description/text() = current()/Description/text()])">
<tr>
<td><xsl:value-of select="Description"/></td>
<td><xsl:value-of select="count(//Record[Description/text()=current()/Description/text()])"/></td>
</tr>
</xsl:if>
</xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>
This works fine and gives me the desired results.
Type Count
A 2
B 1
C 1
However if I were to add another Records element it seems to process the two one after another e.g.
<?xml-stylesheet type="text/xsl" href="merge2.xsl"?>
<Main>
<Records>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>B</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
</Records>
<Records>
<Record>
<Description>B</Description>
</Record>
<Record>
<Description>A</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
<Record>
<Description>C</Description>
</Record>
</Records>
</Main>
This would produce the following.
Type Count
A 3
B 2
C 3
B 2
A 3
C 3
Where it seems to process the first instance of Records, then move onto the next. Is there any way of making it so that it would remove duplicates across the two?
I have tried changing the for-each to go through each instance of Records, and have tried to create a separate template for it, however I still seem to be missing something as I have not managed to get it working.
Many thanks for any help.
Even though @kjhughes was able to answer the question you have, for a more efficient approach you will want to use the Muenchain Method.
To do that you would define a key to group on
Then group those items using that key
And then use that key to count only those specific items
This process is much more efficient and doesn't require navigating the entire structure each time.
So, altogether, when you take this XML
And apply this XSLT to it
It produces this output
Try replacing
preceding-sibling
with justpreceding
in yourxsl:if statement
.You had the right idea to craft your test so that you only emit a
tr
once per encounteredDescription
value. However,preceding-sibling
stops checking back through immediate children of the parent;preceding
continues checking earlier in the document, which is what you want to avoid the duplication acrossRecords
.Fyi, there's also a typo where
Record(
should beRecord[
. Here's a complete, operational transformation including those changes: