Home > OS >  Finding Duplicates with xsl:key?
Finding Duplicates with xsl:key?

Time:11-24

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>
  • Related