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