HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Extracting the first two initials of a person's name

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
persontheinitialstwofirstnameextracting

Problem

I've come up with a hackish approach to get my XSL function to only return the first 2 initials of a person. I think there should be a more efficient way to do this though. The replace specifically is what I think I should be able to get rid of, looking through docs though I can't figure out how to correctly iterate with the split.

So 5 examples of my XML:


    Test I
    Chris

    Test II
    Chris Chris

    Test III
    Chris Eat Meat

    Test IV
    Chris-Eat Meat

    Test V
    Chris-Eat-Meat


My function call:

 


and my inefficient XSL function:


    
     0]
                    return concat(substring($token,1,1),'.'),
                ''), '(\w\.\w?\.?).*', '$1')
                    "/>


So with the first two XML blocks the expected output/return is:

C.


and

C. C.


The remaining three should return (as expected, no M. because we only want the first 2 initials)

C. E.


but I thought there would be a way to stop the iteration. For example my PHP just has:

$abbreviated_firstnames = array();
$firstnames = mb_split('(\s+|-)', html_entity_decode($this->firstname,ENT_QUOTES,'UTF-8'));
$intial_count = 0;
foreach ($firstnames as $firstname) {
    $intial_count++;
    $firstinit = mb_substr($firstname,0,1,'UTF-8');
    if ($firstinit) {
        $abbreviated_firstnames[] = $firstinit . '.';
        if($intial_count >= 2) {
            break; // <---- we got 2 matches stop NOW
        }
    }
}
return implode(' ',$abbreviated_firstnames);

Solution

I think you should be able to get rid of the replace() by testing the position of the token in an additional predicate.

You should also be able to remove the string-join() (unless you don't want spaces between the initials).

You can also remove the string-length() test by adjusting the regex for -.

New function based on above suggestions:


  
  = position()]
    return concat(substring($token,1,1),'.')
    "/>


Complete example (used Saxon-HE 9.5 to test)...

XML Input (Added test VI)


    
        Test I
        Chris
    
    
        Test II
        Chris Chris
    
    
        Test III
        Chris Eat Meat
    
    
        Test IV
        Chris-Eat Meat
    
    
        Test V
        Chris-Eat-Meat
    
    
        Test VI
        Chris---Eat----Meat
    


XSLT 2.0


  
  

  
    
    = position()]
      return concat(substring($token,1,1),'.')
      "/>
  

  
    
      
    
  

  
    
      
      
    
  


XML Output


   
      Test I
      Chris
      C.
   
   
      Test II
      Chris Chris
      C. C.
   
   
      Test III
      Chris Eat Meat
      C. E.
   
   
      Test IV
      Chris-Eat Meat
      C. E.
   
   
      Test V
      Chris-Eat-Meat
      C. E.
   
   
      Test V
      Chris---Eat----Meat
      C. E.
   

Code Snippets

<xsl:function name="pull_it:get_initials">
  <xsl:param name="names"/>
  <xsl:value-of select="
    for $token in tokenize($names,'(-+|\s+)')[2 >= position()]
    return concat(substring($token,1,1),'.')
    "/>
</xsl:function>
<doc>
    <name>
        <surname>Test I</surname>
        <given-names>Chris</given-names>
    </name>
    <name>
        <surname>Test II</surname>
        <given-names>Chris Chris</given-names>
    </name>
    <name>
        <surname>Test III</surname>
        <given-names>Chris Eat Meat</given-names>
    </name>
    <name>
        <surname>Test IV</surname>
        <given-names>Chris-Eat Meat</given-names>
    </name>
    <name>
        <surname>Test V</surname>
        <given-names>Chris-Eat-Meat</given-names>
    </name>
    <name>
        <surname>Test VI</surname>
        <given-names>Chris---Eat----Meat</given-names>
    </name>
</doc>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
  xmlns:pull_it="pull_it"
  exclude-result-prefixes="pull_it">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:function name="pull_it:get_initials">
    <xsl:param name="names"/>
    <xsl:value-of select="
      for $token in tokenize($names,'(-+|\s+)')[2 >= position()]
      return concat(substring($token,1,1),'.')
      "/>
  </xsl:function>

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

  <xsl:template match="name">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
      <initials><xsl:value-of select="pull_it:get_initials(given-names)"/></initials>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
<doc>
   <name>
      <surname>Test I</surname>
      <given-names>Chris</given-names>
      <initials>C.</initials>
   </name>
   <name>
      <surname>Test II</surname>
      <given-names>Chris Chris</given-names>
      <initials>C. C.</initials>
   </name>
   <name>
      <surname>Test III</surname>
      <given-names>Chris Eat Meat</given-names>
      <initials>C. E.</initials>
   </name>
   <name>
      <surname>Test IV</surname>
      <given-names>Chris-Eat Meat</given-names>
      <initials>C. E.</initials>
   </name>
   <name>
      <surname>Test V</surname>
      <given-names>Chris-Eat-Meat</given-names>
      <initials>C. E.</initials>
   </name>
   <name>
      <surname>Test V</surname>
      <given-names>Chris---Eat----Meat</given-names>
      <initials>C. E.</initials>
   </name>
</doc>

Context

StackExchange Code Review Q#132647, answer score: 2

Revisions (0)

No revisions yet.