Re: [xsl] (re-)calculating attribute values

Subject: Re: [xsl] (re-)calculating attribute values
From: "Joerg Heinicke" <joerg.heinicke@xxxxxx>
Date: Mon, 11 Mar 2002 23:04:48 +0100
Hello Christian,

it's important to know the difference between the input-tree and the
output-tree. You can't access the calculated values after the first gap, if
you only write them to the output-tree.

The best solution in my eyes is to use a recursive template, which processes
node by node:

<xsl:template match="root">
    <!-- copy all As and Bs before any gap, because they must not be
processed recursively -->
    <xsl:variable name="before-gap"
select="(A|B)[not(preceding-sibling::C)]"/>
    <xsl:copy-of select="$before-gap"/>
    <!-- apply templates on the first A or B after a gap -->
    <xsl:apply-templates select="(A|B)[preceding-sibling::C][1]">
        <xsl:with-param name="start" select="$before-gap[last()]/@end + 1"/>
    </xsl:apply-templates>
</xsl:template>

<xsl:template match="A|B">
    <xsl:param name="start" select="1"/>
    <xsl:variable name="end" select="$start + (@end - @start)"/>
    <xsl:copy>
        <xsl:attribute name="start"><xsl:value-of
select="$start"/></xsl:attribute>
        <xsl:attribute name="end"><xsl:value-of
select="$end"/></xsl:attribute>
        <xsl:apply-templates/>
    </xsl:copy>
    <xsl:apply-templates select="following-sibling::*[self::A or
self::B][1]">
        <xsl:with-param name="start" select="$end + 1"/>
    </xsl:apply-templates>
</xsl:template>

You have got already a solution with for-each from Michael Kay. But there
every preceding node must be accessed and totalized again. According to your
file size this will make no difference, but when it's big you will see the
time differences.

Furthermore you can shorten the code in the first template if you process
the first nodes in front of the frst C too, i.e. calculating their @start
and @end too, even it's not needed, because you know already the values:

<xsl:template match="root">
    <xsl:apply-templates select="(A|B)[1]">
        <xsl:with-param name="start" select="(A|B)[1]/@start"/>
    </xsl:apply-templates>
</xsl:template>

Regards,

Joerg


> hello *.*,
>   following xml-file:
>
> <A start="20" end="28">Text1</A>
> <B start="29" end="35">Text2</B>
> <C start="36" end="39">Text3</C>
> <C start="40" end="44">Text4</C>
> <A start="45" end="51">Text5</A>
> <C start="52" end="58">Text6</C>
> <B start="59" end="69">Text7</B>
> ...
>
> i want to write a xslt file which removes all <C> elements (no problem)
and
> recalculates start and end values by filling up the gaps. and here i have
> the problem: in the first case it is possible to fill up the gab between
the
> first <B> and second <A>:
>
> 1: <A start="20" end="28">Text1</A>
> 2: <B start="29" end="35">Text2</B>
> 3: <!-- removed <C> element(s) -->
> 4: <A start="36" end="42">Text5</A>
> 5: <!-- removed <C> element(s) -->
> 6: <B start="52" end="62">Text7</B>   (problem!!!)
>
> The problem arises at the second gap (line 6). the gap is calculated by
> using end value of second <A> and start value of last <B> (59-51=8) and
not
> by using already recalculated values in previous step (59-42=17).
>
> what's going wrong here? has anyone a hint or maybe a solution for me?
>
> any help would be appreciated!
>
> regards
>   christian


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list


Current Thread