[xsl] Recursively adding elements to a string

Subject: [xsl] Recursively adding elements to a string
From: "Gibson, Nathan" <nathan.gibson@xxxxxxxxxxxxxx>
Date: Wed, 5 Jun 2013 16:59:47 +0000
Hi,

I'm trying to put some names into TEI format using data that looks like this.

<root>
    <full-name>Doe, John J.</full-name>
    <given-name>John</given-name>
    <family-name>Doe</family-name>
    <middle-name>J.</middle-name>
</root>

I would like to transform it into something like this:
<persName><surname>Doe</surname>, <forename>John</forename>
<addName>J.</addName></persName>

In other words, the given, family, and middle name fields simply show where
the forename, surname, and addName tags should be placed within the full name.
(As I need to keep the order and formatting of the full name in the source,
which are not standardized, I cannot simply recompose the full name from the
name parts. I won't go into all the details, but trust me on that.)

So I'm using a recursive template to try to do this, but it only keeps the
final element it processes. Here's the code:

<xsl:template match="/root/full-name">
        <persName>
            <xsl:call-template name="process-names">
                <xsl:with-param name="full-name" select="."/>
                <xsl:with-param name="count" select="1"/>
            </xsl:call-template>
        </persName>
    </xsl:template>


    <xsl:template name="process-names">
        <xsl:param name="full-name"/>
        <xsl:param name="count"/>
        <xsl:param name="name-part" select="following-sibling::*[$count]"/>
        <xsl:choose>
            <xsl:when test="contains(name($name-part), 'given')">
                <xsl:call-template name="process-names">
                    <xsl:with-param name="full-name">
                        <xsl:copy-of select="substring-before($full-name,
$name-part)"/>
                        <xsl:element name="forename">
                            <xsl:value-of
select="following-sibling::*[$count]"/>
                        </xsl:element>
                        <xsl:copy-of select="substring-after($full-name,
$name-part)"/>
                    </xsl:with-param>
                    <xsl:with-param name="count" select="$count + 1"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:when test="contains(name($name-part), 'family')">
                <xsl:call-template name="process-names">
                        <xsl:with-param name="full-name">
                            <xsl:copy-of select="substring-before($full-name,
$name-part)"/>
                            <xsl:element name="surname">
                                <xsl:value-of
select="following-sibling::*[$count]"/>
                            </xsl:element>
                            <xsl:copy-of select="substring-after($full-name,
$name-part)"/>
                        </xsl:with-param>
                        <xsl:with-param name="count" select="$count + 1"/>
                    </xsl:call-template>
            </xsl:when>
            <xsl:when test="contains(name($name-part), 'middle')">
                <xsl:call-template name="process-names">
                    <xsl:with-param name="full-name">
                        <xsl:copy-of select="substring-before($full-name,
$name-part)"/>
                        <xsl:element name="addName">
                            <xsl:value-of
select="following-sibling::*[$count]"/>
                        </xsl:element>
                        <xsl:copy-of select="substring-after($full-name,
$name-part)"/>
                    </xsl:with-param>
                    <xsl:with-param name="count" select="$count + 1"/>
                </xsl:call-template>
            </xsl:when>
            <xsl:otherwise>
                <xsl:copy-of select="$full-name"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:template>
</xsl:stylesheet>

And here's what it creates:

    <persName>Doe, John <addName>J.</addName></persName>
    John
    Doe
    J.

As best I can tell from debugging, the substring-before function flattens the
sequence contained in $full-name into string that contains no elements, thus
removing <forename> and <surname>. So I figure I either need to use a function
that plays well with sequences or figure out a way for elements to be parsed
as strings. But I haven't come up with how to do either one of those.
Suggestions?

I'm using XSL 2.0 and Saxon EE 9.4.0.6 with Oxygen 14.2.

Thanks,
Nathan

Current Thread