سؤال

I often use this xpath sum(preceding::*/string-length())

It does what I need it to do (provides a character count of all text up to this context in the XML file).

Problem: it is slow.

Is there a different built in function that I should be using instead? Or an extension?

UPDATE:

Based on Michael Kay's comment, I explored XSLT 3.0 <accumulator>. It was my first try with 3.0 (I had to update OxygenXML to make it work). I haven't fully adapted it to my needs, but initial test below shows promise.

<xsl:output method="xml" />

<xsl:accumulator 
    name="f:string-summ"
    post-descent="f:accum-string-length"
    as="xs:integer"
    initial-value="0">
    <xsl:accumulator-rule 
        match="text/*" 
        new-value="$value + string-length()"/>
</xsl:accumulator>

<xsl:template match="text/*">
        <xsl:value-of select="f:accum-string-length()" />
</xsl:template>

Off topic: Stack Overflow needs an "XSLT-3.0" tag.

هل كانت مفيدة؟

المحلول

If you call this function on every node, then you stylesheet performance will be O(n^2) in the number of nodes.

The function is incorrect anyway. The preceding axis gives you your parent's preceding siblings and also the children of your parent's preceding siblings, so the string length of your cousins is being counted more than once.

Try defining a memo function something like this:

<xsl:function name="f:preceding-string-length" saxon:memo-function="yes">
  <xsl:param name="n" as="element()"/>
  <xsl:sequence select="sum(ancestor::*/preceding-sibling::*[1]/(f:preceding-string-length(.) + string-length(.)))"/>
</xsl:function>

Or use an XSLT 3.0 accumulator, which amounts to much the same thing.

نصائح أخرى

I don't think the sum function is slow, the navigation to all preceding elements and the computation of the string length of all contents is expensive. As for optimizing it, which XSLT 2.0 processor do you use?

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top