Using XSLT to select after an EACH instance in a string / substring

I am trying to write an XSLT stylesheet that will process the Dublin Core cataloging entry (XML) and generate Chicago, APA, and MLA quote versions for each book. Everything worked out fine for me, except for the author of APA. For the APA style, authors need the authorโ€™s name (done), a comma, the first initial (done), and any other initials (my problem is with a stuck place).

What I have right now (and a sample DC element below):

<xsl:value-of select="substring-before(dc:creator[1],',')" /><xsl:text>, </xsl:text><xsl:value-of select="substring(substring-after(dc:creator[1],' '),1,1)" /><xsl:for-each select="dc:creator[position()!=1]"><xsl:choose><xsl:when test="position()=last()"><xsl:text>., &amp; </xsl:text></xsl:when><xsl:otherwise>., </xsl:otherwise></xsl:choose><xsl:value-of select="substring-before(.,',')" /><xsl:text>, </xsl:text><xsl:value-of select="substring(substring-after(.,' '),1,1)" /><xsl:if test="position()=last()">.</xsl:if></xsl:for-each> 

For instances of the following format (which directory uses the directory):

 <dc:creator>Friend, Natasha</dc:creator> 

this works just fine and returns: Friend, N.

But for

 <dc:creator>Tolkien, JRR</dc:creator> 

he returns: Tolkien, J.

In many cases, this does not matter, but there will be cases when you really need to return the average initial authors, for example, JRR Tolkien or JK Rowling .

So, I need to return the letter that appears after each space, and not just for the first copy of the space.

Any ideas?

+3
source share
1 answer

I. Here is a simple and natural XSLT 2.0 solution:

 <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="/*/*"> <xsl:value-of separator=", " select= "substring-before(., ',') , for $n in tokenize(substring-after(., ','), '\s')[.] return substring($n, 1,1) "/> <xsl:text>&#xA;</xsl:text> </xsl:template> </xsl:stylesheet> 

When this conversion is applied to the following XML document:

 <t xmlns:dc="some:dc"> <dc:creator >Friend, Natasha</dc:creator> <dc:creator>Tolkien, JRR</dc:creator> </t> 

the desired, correct result is output:

 Friend, N Tolkien, J., R., R. 

II. XSLT 1.0 Solution :

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="/*/*/text()"> <xsl:value-of select="substring-before(., ',')"/> <xsl:call-template name="replaceTokenDelims"> <xsl:with-param name="pStr" select= "concat(normalize-space(substring-after(., ',')), ' ')"/> <xsl:with-param name="pToken" select="' '"/> <xsl:with-param name="pReplacement" select="', '"/> </xsl:call-template> <xsl:text>&#xA;</xsl:text> </xsl:template> <xsl:template name="replaceTokenDelims"> <xsl:param name="pStr"/> <xsl:param name="pToken"/> <xsl:param name="pReplacement"/> <xsl:if test="$pStr"> <xsl:value-of select="$pReplacement"/> <xsl:value-of select= "substring(substring-before($pStr, $pToken), 1, 1)"/> <xsl:call-template name="replaceTokenDelims"> <xsl:with-param name="pStr" select="substring-after($pStr, $pToken)"/> <xsl:with-param name="pToken" select="$pToken"/> <xsl:with-param name="pReplacement" select="$pReplacement"/> </xsl:call-template> </xsl:if> </xsl:template> </xsl:stylesheet> 

When this conversion is applied to the same XML document (above), the same correct result is obtained again :

 Friend, N Tolkien, J., R., R. 
+3
source

All Articles