xsl-list
[Top] [All Lists]

[xsl] Recursive function problem

2010-06-30 03:29:16
Good morning 

I'm writing a function to be used as part of a content conversion from one
DTD to another. The input is in the following form:

<names>
    <nameGrp role="editor" foreNames="Donald B." 
        mainName="Redford">Donald B. Redford</nameGrp>
    <nameGrp 
        foreNames="Thutmose" foreTitle="III">Thutmose III</nameGrp>
</names>

and I need to get the output into the form:

<names>
    <name><fname>Donald B.</fname> <sname>Redford</sname></name>
    <name><fname>Thutmose</fname> <ntitle>III</ntitle></name>
</names>

I've clearly made an error in the function as the output I am getting is
on the lines of:

<names>
    <name>Donald B. Redford</name>
    <name>Thutmose III</name>
</names>

The relevant portions of the stylesheet are:

<xsl:stylesheet
    xmlns:dtg="http://dtg.oup.com/functions";
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; 
xmlns:xd="http://www.oxygenxml.com/ns/doc/xsl";
    xmlns:xs="http://www.w3.org/2001/XMLSchema";
    version="2.0" exclude-result-prefixes="dtg xd xs">
    
    <xsl:variable name='name-attrs' select="('foreNames', 'mainName', 
'foreTitle')"/>
    <xsl:variable name='name-elems' select="('fname', 'sname', 'ntitle')"/>
   
    <xsl:template match="/">
        <names>
            <xsl:apply-templates select='names/nameGrp'/>
        </names>
    </xsl:template>
    
    <xsl:template match='nameGrp'>
        <name>
            <xsl:copy-of select='@role'/>
            <xsl:value-of select='dtg:attributes-to-elements(., $name-attrs, 
$name-elems)'/>
        </name>
    </xsl:template>
    
    
    <xsl:function name='dtg:attributes-to-elements'>

        <xsl:param name="element"/>
        <xsl:param name='attributes'/>
        <xsl:param name='elements'/>
        
        <!-- only the listed attributes, not all of them -->
        <xsl:variable name="attribs" select='$element/@*[local-name(.) = 
$attributes]'></xsl:variable>
        
        <!-- we want the attributes reverse sorted by the length of their 
values. -->
        <xsl:variable name='sorted-attribs' as='item()*'>
            <xsl:perform-sort select='$attribs' > 
                <xsl:sort select='string-length(string(.))' order="descending"/>
            </xsl:perform-sort>
        </xsl:variable>

        <xsl:if test='count($attributes) != count($elements)'>
            <xsl:message terminate="yes">attributes-to-elements - attribute and 
element sequences must be the same size.</xsl:message>
        </xsl:if>
        
        <xsl:value-of select='dtg:attr-to-elem-impl(string($element), 
$sorted-attribs, $attributes, $elements)'/>
    
    </xsl:function>
    
    
    <xsl:function name="dtg:attr-to-elem-impl">
        
        <xsl:param name='source'/>
        <xsl:param name='input-attribs'/>
        <xsl:param name='attrib-names'/>
        <xsl:param name='element-names'/>
        
        <xsl:variable name='current-val' select='string($input-attribs[1])'/>
        <xsl:variable name='current-name' 
select='local-name($input-attribs[1])'/>
        <xsl:variable name='index' select='index-of($attrib-names, 
$current-name)'/>
        <xsl:variable name='output-element' select='$element-names[$index]'/>
        <xsl:variable name="next-attribs" select='$input-attribs[position() gt 
1]'/>
        
        <xsl:choose>
            
            <xsl:when test="$source = ''">
                <xsl:value-of select="$source"/>
            </xsl:when>
            
            <xsl:when test="count($input-attribs) = 0">
                <xsl:value-of select="$source"/>
            </xsl:when>
            
            <xsl:when test="contains($source, $current-val)">
                
                <xsl:variable name='new-element'>
                    <xsl:element name="{$output-element}"><xsl:value-of 
select="$current-val"/></xsl:element>
                </xsl:variable>
                
                <xsl:variable name='before' select="substring-before($source, 
$current-val)"/>
                <xsl:variable name='after' select="substring-after($source, 
$current-val)"/>
                
                <xsl:variable name='result-before' 
                    select="dtg:attr-to-elem-impl($before, $next-attribs, 
$attrib-names, $element-names)"/>
                <xsl:variable name='result-after' 
                    select="dtg:attr-to-elem-impl($after, $next-attribs, 
$attrib-names, $element-names)"/>
                
                <xsl:sequence select="($result-before, $new-element, 
$result-after)"/>
                                        
            </xsl:when>
            
            <xsl:otherwise>
                <xsl:sequence select="dtg:attr-to-elem-impl($source, 
$next-attribs, $attrib-names, $element-names)"/>
            </xsl:otherwise>
            
        </xsl:choose>

    </xsl:function>
    
</xsl:stylesheet>

The large number of variables is due to my having traced through this in the 
oXygen debugger.
I've seen (in the degugger) that $new-element does contain the element created 
but it 
appears to be lost before the result is generated.

I'm pretty sure the error is in either the variable (new-element) that should be
creating the element or in the xsl:sequence instructions. However, I'm having a 
failing
to see the wood for the trees moment. Any pointers would be gratefully received.

By the way the recursion for result-before and result-after shoudl be safe as I 
know 
that the content of each attribute can only occur once in the text.

cheers

nic 


--~------------------------------------------------------------------
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>