Vic
Vic

Reputation: 13

Using XSLT to generate usernames(comparing nodes)

Here is my Requirment:

Lastname is the username, if lastname is same use lastname + First initial, if lastname + First initial is same use lastname + First initial+second letter first name.

I have tried using keys but i was not successful.(Input is an XML document with demographic data and may have about 1200 records in total, need to compare the last names from this XML file and generate the username according to the condition as described above). This is my first question ever, so kindly let me know what info you need to answer.

I can use XSLT 1.0 or 2.0

Here is a sample XML:

<XML>
<Data>
        <First_Name>Chris</First_Name>
        <Middle_Name>E</Middle_Name>
        <Last_Name>Kyle</Last_Name>
        <Employee_ID>100</Employee_ID>
</Data>
<Data>
        <First_Name>Allen</First_Name>
        <Middle_Name></Middle_Name>
        <Last_Name>Kyle</Last_Name>
        <Employee_ID>101</Employee_ID>
</Data>
<Data>
        <First_Name>Aron</First_Name>
        <Middle_Name></Middle_Name>
        <Last_Name>Kyle</Last_Name>
        <Employee_ID>102</Employee_ID>
</Data>
<Data>
        <First_Name>Luffy</First_Name>
        <Middle_Name>D</Middle_Name>
        <Last_Name>Monkey</Last_Name>
        <Employee_ID>103</Employee_ID>
</Data>
<XML>

For this example after transformation i should get the usernames as follows: 1)Kylec 2)Kyleal 3)Kylear 4)Monkey

Here is my XSLT which partially works(had multiple changes but currently stuck here)

   <xsl:template match="/">
            <xsl:call-template name="HeaderRecord"/>

            <xsl:for-each select="//XML/Data[generate-id(.)= generate-id(key('ELN',Last_Name)[1])]">
            <xsl:sort select="Last_Name" order="ascending"/>
            <xsl:for-each select="key('ELN',Last_Name)">

                <xsl:if test="position()=0">
                    <xsl:call-template name="DataRecords"/>
                </xsl:if>

                <xsl:if test="position()=1">
                    <xsl:for-each select="//XML/Data[generate-id(.)= generate-id(key('EFN1',substring(First_Name,1,1))[1])]">
                        <xsl:for-each select="key('EFN1',substring(First_Name,1,1))">
                            <xsl:sort select="First_Name" order="ascending"/>
                            <xsl:if test="position()=0">
                            <xsl:call-template name="DuplicateDataRecords"/>
                            </xsl:if>
                            <xsl:if test="position()=1">
                            <xsl:call-template name="DuplicateDataRecords2"/>
                             </xsl:if>
                         </xsl:for-each>
                      </xsl:for-each>  
                </xsl:if>
            </xsl:for-each>
        </xsl:for-each>
    </xsl:template>

Thanks!!

Upvotes: 0

Views: 221

Answers (1)

Tim C
Tim C

Reputation: 70638

You could define a separate key for each condition on checking for existing names; so one for the Last_Name only, one for Last_Name plus first letter of First_Name, abd one for Last_Name plus first two letters of First_Name

<xsl:key name="ELN" match="Data" use="Last_Name" />
<xsl:key name="EFN1" match="Data" use="concat(Last_Name, substring(First_Name,1,1))" />
<xsl:key name="EFN2" match="Data" use="concat(Last_Name, substring(First_Name,1,2))" />

Then, you could have a template matching Data in which there is an xsl:choose that tests all of the conditions using the keys in turn.

So, to check this was the first occurrence of the Last_Name (and so use the last name as the user name), do this

<xsl:when 
     test="generate-id(.)= generate-id(key('ELN',Last_Name)[1])">

The next xsl:when would test for Last_Name + First character of First_Name, but it would also have to check this combination is not a valid Last_Name anywhere.

<xsl:when 
     test="generate-id(.)= generate-id(key('EFN1',concat(Last_Name, substring(First_Name,1,1)))[1])
           and not(key('ELN', concat(Last_Name, substring(First_Name,1,1))))">

And similarly for checking the first two characters of First_Name

<xsl:when 
     test="generate-id(.)= generate-id(key('EFN2',concat(Last_Name, substring(First_Name,1,2)))[1])
           and not(key('EFN1', concat(Last_Name, substring(First_Name,1,2))))
           and not(key('ELN', concat(Last_Name, substring(First_Name,1,2))))">

Try this XSLT...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <xsl:output method="xml" encoding="UTF-8" indent="yes" />

    <xsl:key name="ELN" match="Data" use="Last_Name" />
    <xsl:key name="EFN1" match="Data" use="concat(Last_Name, substring(First_Name,1,1))" />
    <xsl:key name="EFN2" match="Data" use="concat(Last_Name, substring(First_Name,1,2))" />

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

    <xsl:template match="Data">
        <User_Name>
        <xsl:choose>
            <xsl:when test="generate-id(.)= generate-id(key('ELN',Last_Name)[1])">
                <xsl:value-of select="Last_Name" />
            </xsl:when>
            <xsl:when test="generate-id(.)= generate-id(key('EFN1',concat(Last_Name, substring(First_Name,1,1)))[1])
                            and not(key('ELN', concat(Last_Name, substring(First_Name,1,1))))">
                <xsl:value-of select="concat(Last_Name, substring(First_Name,1,1))" />
            </xsl:when>
            <xsl:when test="generate-id(.)= generate-id(key('EFN2',concat(Last_Name, substring(First_Name,1,2)))[1])
                            and not(key('EFN1', concat(Last_Name, substring(First_Name,1,2))))
                            and not(key('ELN', concat(Last_Name, substring(First_Name,1,2))))">
                <xsl:value-of select="concat(Last_Name, substring(First_Name,1,2))" />
            </xsl:when>
            <xsl:otherwise>
                <xsl:variable name="username" select="concat(Last_Name, substring(First_Name,1,2))" />
                <xsl:value-of select="$username" />
                <xsl:value-of select="count(preceding-sibling::Data[concat(Last_Name, substring(First_Name,1,2)) = $username]) + 1" />
            </xsl:otherwise>
        </xsl:choose>
        </User_Name>
    </xsl:template>
</xsl:stylesheet>

Note that in the case of Last_Name + first two letters of First_Name not being unique, the fall back I have used is to append a number at the end of the user name.

Upvotes: 1

Related Questions