|
Subject: Re: [xsl] Recursively adding elements to a string From: "Gibson, Nathan" <nathan.gibson@xxxxxxxxxxxxxx> Date: Wed, 5 Jun 2013 23:33:22 +0000 |
Looks like I can do it by using <xsl:analyze-string> recursively, as follows.
(I haven't yet implemented different element names for different parts of the
name---currently all use the generic <name> element.)
<xsl:template match="/root/full">
<persName>
<xsl:call-template name="process-names">
<xsl:with-param name="name" select="."/>
<xsl:with-param name="count" select="1"/>
<xsl:with-param name="all-name-parts"
select="/root/*[ends-with(name(), 'name')]"/>
</xsl:call-template>
</persName>
</xsl:template>
<xsl:template name="process-names">
<xsl:param name="name"/>
<xsl:param name="count"/>
<xsl:param name="all-name-parts"/>
<xsl:param name="name-part" select="$all-name-parts[$count]"/>
<xsl:choose>
<xsl:when test="$name-part">
<xsl:analyze-string select="$name" regex="{$name-part}"
flags="i">
<xsl:matching-substring>
<xsl:element name="name"><xsl:value-of
select="substring($name, string-length(substring-before($name, $name-part)) +
1, string-length($name) - string-length(substring-before($name, $name-part)) -
string-length(substring-after($name, $name-part)))"/></xsl:element>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:call-template name="process-names">
<xsl:with-param name="name" select="."/>
<xsl:with-param name="count" select="$count +
1"/>
<xsl:with-param name="all-name-parts"
select="$all-name-parts"/>
</xsl:call-template>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="."/>
</xsl:otherwise>
</xsl:choose>
The result is
<persName><name>Doe</name>, <name>John</name> <name>J.</name></persName>
John
Doe
J.
On Jun 5, 2013, at 12:59 PM, "Gibson, Nathan" <nathan.gibson@xxxxxxxxxxxxxx>
wrote:
> 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 |
|---|
|
| <- Previous | Index | Next -> |
|---|---|---|
| [xsl] Recursively adding elements t, Gibson, Nathan | Thread | [xsl] German umlaut sort, Jean-Pierre Lamon |
| [xsl] Balisage 2013: Call for Late-, Tommie Usdin | Date | [no subject], Unknown |
| Month |