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 |