Re: [xsl] Can I use xsl:key to select elements up to certain ancestor

Subject: Re: [xsl] Can I use xsl:key to select elements up to certain ancestor
From: "David Carlisle d.p.carlisle@xxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Wed, 30 Aug 2017 19:08:17 -0000
You seem to be listing ancestor-or-self rather than ancestor, I think
you only need to go up the ancestor axis once in each case, something
like

<xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>


 <xsl:template match="/">
  <xsl:apply-templates select="//p"/><!-- just for testing-->
 </xsl:template>


 <xsl:template match="*">
  <xsl:copy>
   <xsl:apply-templates select="." mode="a"/>
  </xsl:copy>
 </xsl:template>

 <xsl:template match="*" mode="a">
  <xsl:param name="trail" select="()"/>
  <xsl:apply-templates select="parent::*" mode="a">
   <xsl:with-param name="trail" select="name(),$trail"/>
  </xsl:apply-templates>
 </xsl:template>

 <xsl:template match="*[@id]" mode="a">
  <xsl:param name="trail" select="()"/>
   <xsl:copy-of select="@id,'Ancestors:', name(), $trail"/>
 </xsl:template>

</xsl:stylesheet>


which makes


<p id="x13">Ancestors: bar div p</p>

On 30 August 2017 at 19:49, Michael MC<ller-Hillebrand mmh@xxxxxxxxx
<xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx> wrote:
> Hi all,
>
> I had an embarrassing moment today, when I found that the source of a severe
performance problem was sitting in front of the screen.
>
> Using XSLT 2.0 I am transforming elements and at many points I have to look
up the ancestor axis, but only up to an element with an attribute "id".
Basically I have a deeply nested structure of topics and I want to analyze
ancestors inside the current topic.
>
> The nearest topic is easy to find:
>
> <xsl:variable name="topic" select="ancestor-or-self::*[@id][1]"
as="element()"/>
>
> And then I was doing the following to find all ancestors that share the same
"topic ancestor":
>
> <xsl:variable name="ancestors-in-topic"
>   select="ancestor-or-self::*[ancestor-or-self::* = $topic]"
as="element()*"/>
>
> This did not what I expected and also wasted a lot of resources because the
predicate was true for all or most elements. After some testing I went with
this:
>
> <xsl:variable name="ancestors-in-topic"
>   select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
generate-id($topic)]" as="element()*"/>
>
> Since that calculation is done very often I am wondering if xsl:key could be
used to speed things up?
>
> Any pointers are very welcome, as always, thanks,
>
> - Michael
>
> PS: My sample XML and XSLT below.
>
> <?xml version="1.0" encoding="UTF-8"?>
> <bars id="x0">
>   <bar id="x1">
>     <bar id="x11">
>       <bar id="x12">
>         <div>
>           <bar id="x13">
>             <div>
>               <p/>
>             </div>
>           </bar>
>         </div>
>       </bar>
>     </bar>
>   </bar>
> </bars>
>
>
> <?xml version="1.0" encoding="UTF-8"?>
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
xmlns:xs="http://www.w3.org/2001/XMLSchema"; version="2.0">
>   <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/>
>   <xsl:strip-space elements="*"/>
>
>   <xsl:template match="p">
>     <xsl:variable name="topic" select="ancestor-or-self::*[@id][1]"
as="element()"/>
>     <xsl:variable name="ancestors-in-topic"
select="ancestor-or-self::*[ancestor-or-self::*/generate-id() =
generate-id($topic)]" as="element()*"/>
>     <xsl:copy>
>       <xsl:attribute name="topic" select="$topic/@id"/>
>       <xsl:text>Ancestors: </xsl:text>
>        <xsl:sequence select="$ancestors-in-topic/name()"/>
>     </xsl:copy>
>   </xsl:template>
>
>   <xsl:template match="* | @*">
>     <xsl:copy>
>       <xsl:apply-templates select="@*, node()"/>
>     </xsl:copy>
>   </xsl:template>
> </xsl:stylesheet>
>
>
> Expected output for <p>: <p topic="x13">Ancestors: bar div p</p>

Current Thread