The following code works to output bag numbers in "g" found in other groups. Is there any way to achieve the same using xsl:key
? Ideally "g" would be a parameter so I don't have to repeat similar code for "h", "i", etc.
<?xml version="1.0" encoding="UTF-8"?>
<root>
<g>
<bagn>A</bagn>
<bagn>B</bagn>
</g>
<h>
<bagn>C</bagn>
<bagn>D</bagn>
<bagn>A</bagn>
</h>
<i>
<bagn>B</bagn>
<bagn>F</bagn>
<bagn>G</bagn>
</i>
</root>
<xsl:variable name="gDups">
<xsl:for-each select="/root/g/bagn[.=/root/node()[not(self::g)]/bagn]">
<xsl:choose>
<xsl:when test="position()=1">
<xsl:value-of select="concat('|',.,'|')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(.,'|')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
<xsl:value-of select="$gDups"/>
CodePudding user response:
Consider the following example:
XSLT 1.0
<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="bagn" match="bagn" use="." />
<xsl:template match="/root">
<duplicates>
<xsl:for-each select="*">
<!-- duplicates in siblings -->
<xsl:variable name="dups" select="key('bagn', bagn)[not(generate-id(..) = generate-id(current()))]" />
<xsl:if test="$dups">
<xsl:copy>
<xsl:for-each select="$dups">
<xsl:value-of select="."/>
<xsl:if test="position()!=last()">|</xsl:if>
</xsl:for-each>
</xsl:copy>
</xsl:if>
</xsl:for-each>
</duplicates>
</xsl:template>
</xsl:stylesheet>
Applied to your example input, this will return:
Result
<?xml version="1.0" encoding="UTF-8"?>
<duplicates>
<g>A|B</g>
<h>A</h>
<i>B</i>
</duplicates>
Note that this returns a list of duplicates in other siblings, even if the siblings have the same name. For example, for input of:
<root>
<g>
<bagn>A</bagn>
<bagn>B</bagn>
</g>
<g>
<bagn>C</bagn>
<bagn>D</bagn>
<bagn>A</bagn>
</g>
<g>
<bagn>B</bagn>
<bagn>F</bagn>
<bagn>G</bagn>
</g>
</root>
the result will be:
<?xml version="1.0" encoding="UTF-8"?>
<duplicates>
<g>A|B</g>
<g>A</g>
<g>B</g>
</duplicates>