Reputation: 13
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
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