Flag
Flag

Reputation: 577

XSLT - references to duplicated elements

Using XSLT2 and given the following sort of file:

<refbody>
  <p>That's line 1<fn>It does this</fn></p>
  <b>That's line 2<fn>It does that</fn></b>
  <div>
    <p>That's line 3<fn>It does this</fn></p>
  </div>
</refbody>

I would like create the following:

<refbody>
  <p>That's line 1<fn id="123">It does this</fn></p>
  <b>That's line 2<fn>It does that</fn></b>
  <div>
    <p>That's line 3<xref href="123"/></p>
  </div>
</refbody>

So the idea is:

For each fn tag, check if it has duplicates (i.e same text).

These fn elements can be in any level, grouped or not, their position is absolutely unpredictable.

I have tried the following so far:

 <xsl:template match="fn">
        <xsl:variable name="duplicated" select="//fn[text()=.]"/>
        <xsl:choose>
            <xsl:when test="count($duplicated) gt 1">
                <xsl:choose>
                    <xsl:when test="not(preceding-sibling::fn[text()=.] or preceding::fn[text()=.])">
                        <fn id="{generate-id(.)}">
                            <xsl:value-of select="text()"/>
                        </fn>
                    </xsl:when>
                    <xsl:otherwise>
                        <xsl:variable name="root" select="name(node()[1])"/>
                        <xsl:variable name="id" select="$duplicated[1]/@id"/>
                        <xref href="{$id}"/> 
                    </xsl:otherwise>
                </xsl:choose>
            </xsl:when>          
            <xsl:otherwise>
                <xsl:copy-of select="."></xsl:copy-of>
            </xsl:otherwise>
        </xsl:choose>                    
    </xsl:template>

Obviously, I don't have access to the ID doing that, so this is not good.

Upvotes: 1

Views: 76

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167506

Use a key to identify duplicates:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs"
    version="2.0">

    <xsl:key name="fn" match="fn" use="."/>

    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* , node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="fn[. is key('fn', .)[1] and key('fn', .)[2]]">
        <fn id="{generate-id()}">
            <xsl:apply-templates/>
        </fn>
    </xsl:template>

    <xsl:template match="fn[not(. is key('fn', .)[1])]">
        <xref href="{generate-id(key('fn', .)[1])}"/>
    </xsl:template>

</xsl:stylesheet>

Upvotes: 3

Related Questions