| 
 
Subject: Re: [xsl] Processing milestoned XML leads to many preceding::  calls and horrible performance From: Andrew Welch <andrew.j.welch@xxxxxxxxx> Date: Tue, 21 Feb 2012 10:02:18 +0000  | 
>    <xsl:template name="genRef">
>        <xsl:variable name="refKniha" select="//kniha[1]/@jmeno"/>
>        <xsl:variable name="refKapitola" select="preceding::kap[1]/@n"/>
>        <xsl:value-of select="concat($refKniha,'.',$refKapitola,'.')"/>
>    </xsl:template>
Did you really want "//kniha[1]" or "(//Kniha)[1]" ?   It's a common
gotcha...  The former can select multiple elements, not just one.
Also, with named templates I always think you should pass in the
$context as a parameter rather than rely on the implicit one as then
you can give it a sequence type helping the maintain know what it
expected (and it helps debugging).  In this case, as you returning an
atomic you should really use a function.
>        <xsl:element name="verse">
You can just write <verse> directly here, no need for xsl:element.
>            <xsl:variable name="prevVerseID">
>                <xsl:value-of select="./preceding::vers[1]/@n" />
>            </xsl:variable>
You should use the select attribute here, eg:
<xsl:variable name="prevVerseID" select="preceding::vers[1]/@n" />
>            <xsl:attribute name="eID">
>                <xsl:value-of select="concat($rBase,$prevVerseID)" />
>            </xsl:attribute>
That could be an "attribute value template" (then there's no need for
the above):
<verse eID="{concat($rBase, preceding::vers[1]/@n}"/>
...however you could probably use a tunnelled parameter to pass the @n
forwards rather than look back for it.
>        <xsl:variable name="refBase">
>            <xsl:call-template name="genRef" />
>        </xsl:variable>
Again, this is a bit nasty and should replaced with a function call.
>        <xsl:variable name="curPos"
>
>
select="count(./preceding::kap[1]/following::*[not(count(preceding-sibling::v
ers|current())
> = count(preceding-sibling::vers))])" />
You say that's to check if it's the first <vers> in the chapter... a
good way to do that is at the parent node select the <vers> child you
want to treat as the first, and then pass it is as a parameter.  Then
in the <vers> template, you can say:
select=". is $first-vers"
to see if the <vers> you are processing is the one you want to treat
as the first.  This makes it clear what you are trying to do, and
avoids looking back up the tree.
>        <xsl:if test="not($curPos=1)">
>            <xsl:call-template name="endVerse">
>                <xsl:with-param name="rBase">
>                    <xsl:value-of select="$refBase" />
>                </xsl:with-param>
>            </xsl:call-template>
>        </xsl:if>
The last thing to say is: avoid named templates.  You very rarely need
them, typically only when you want to output boilerplate markup, and
even then moded templates are often better.
> Any ideas? Would some other XSLT processors other than xsltproc (libxml
> 20706, libxslt 10126 and libexslt 815) I am using be able to optimize this
> somehow?
ahhh... most of the above only applies for xslt 2.0.  These days it's
helpful to mention the version you are using near the top :)
--
Andrew Welch
http://andrewjwelch.com
| Current Thread | 
|---|
 
  | 
| <- Previous | Index | Next -> | 
|---|---|---|
| Re: [xsl] Processing milestoned XML, Matěj Cepl | Thread | Re: [xsl] Processing milestoned XML, Tony Graham | 
| Re: [xsl] Processing milestoned XML, Emmanuel Bégué | Date | Re: [xsl] Processing milestoned XML, Tony Graham | 
| Month |