xsl-list
[Top] [All Lists]

Re: [xsl] Recursively adding elements to a string

2013-06-05 18:33:33
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(_dot_)gibson(_at_)vanderbilt(_dot_)edu> 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

--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: 
<mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--





--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--


<Prev in Thread] Current Thread [Next in Thread>