Re: [xsl] XSL/XPath 2.0 - most efficient way to find route to target element

Subject: Re: [xsl] XSL/XPath 2.0 - most efficient way to find route to target element
From: Robert Koberg <rob@xxxxxxxxxx>
Date: Sun, 27 Apr 2008 09:02:51 -0400
Here is what I tried (probably uses too much XSLT 1.0 thinking), but it
does not work. I tried using intersect to get the nearest common
ancestor, but I can't seem to get it. What am I doing wrong?

The XSL is followed by the XML:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
version="2.0">

  <xsl:key name="config" match="*" use="@id"/>

  <xsl:template match="/">
    
    <test>
      <xsl:variable name="target"  select="key('config', 'b3')"/>
      
      <xsl:variable name="target-anc-and-self">
        <xsl:apply-templates select="key('config', 'b3')"
mode="ancestry"/>
      </xsl:variable>
      
      <xsl:variable name="a3-anc-and-self">
        <xsl:apply-templates select="key('config', 'a3')"
mode="ancestry"/>
      </xsl:variable>
      
      <xsl:variable name="a3-common-ancestor" select="($a3-anc-and-self
intersect $target-anc-and-self)[1]"/>
      <xsl:copy-of select="$a3-common-ancestor"/>
      
      <xsl:variable name="a3-to-target">
        <xsl:apply-templates select="key('config', 'a3')"
mode="path-up">
          <xsl:with-param name="common-ancestor"
select="$a3-common-ancestor"/>
        </xsl:apply-templates>
        <xsl:apply-templates select="$target" mode="path-down">
          <xsl:with-param name="common-ancestor"
select="$a3-common-ancestor"/>
        </xsl:apply-templates>
      </xsl:variable>
      
      <path href="{$a3-to-target}"/>
      
      <xsl:variable name="b4-anc-and-self">
        <xsl:apply-templates select="key('config', 'b4')"
mode="ancestry"/>
      </xsl:variable>
      
      <xsl:variable name="b4-common-ancestor" select="($b4-anc-and-self
intersect $target-anc-and-self)[1]"/>
      <xsl:copy-of select="$b4-common-ancestor"/>
      
      <xsl:variable name="b4-to-target">
        <xsl:apply-templates select="key('config', 'b4')"
mode="path-up">
          <xsl:with-param name="common-ancestor"
select="$b4-common-ancestor"/>
        </xsl:apply-templates>
        <xsl:apply-templates select="$target" mode="path-down">
          <xsl:with-param name="common-ancestor"
select="$b4-common-ancestor"/>
        </xsl:apply-templates>
      </xsl:variable>
      
      <path href="{$b4-to-target}"/>
      
      <xsl:variable name="c3-anc-and-self">
        <xsl:apply-templates select="key('config', 'c3')"
mode="ancestry"/>
      </xsl:variable>
      
      <xsl:variable name="c3-common-ancestor" select="($c3-anc-and-self
intersect $target-anc-and-self)[1]"/>
      <xsl:copy-of select="$c3-common-ancestor"/>
      
      <xsl:variable name="c3-to-target">
        <xsl:apply-templates select="key('config', 'c3')"
mode="path-up">
          <xsl:with-param name="common-ancestor"
select="$c3-common-ancestor"/>
        </xsl:apply-templates>
        <xsl:apply-templates select="$target" mode="path-down">
          <xsl:with-param name="common-ancestor"
select="$c3-common-ancestor"/>
        </xsl:apply-templates>
      </xsl:variable>
      
      <path href="{$c3-to-target}"/>
      
    </test>
  </xsl:template>
  
  <xsl:template match="*" mode="ancestry">
    <xsl:sequence select="ancestor-or-self::*"/>
  </xsl:template>
  
  <xsl:template match="*" mode="path-up">
    <xsl:param name="common-ancestor"/>
    <xsl:choose>
      <xsl:when test=". = $common-ancestor"/>
      <xsl:otherwise>
        <xsl:text>../</xsl:text>
        <xsl:apply-templates select="parent::*" mode="path-up"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
  <xsl:template match="*" mode="path-down">
    <xsl:param name="common-ancestor"/>
    <xsl:choose>
      <xsl:when test=". = $common-ancestor"/>
      <xsl:otherwise>
        <xsl:apply-templates select="parent::*" mode="path-down"/>
        <xsl:text>/</xsl:text>
        <xsl:value-of select="@name"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  
</xsl:stylesheet>


<?xml version="1.0" encoding="UTF-8"?>
<node name="foo" id="x">
  <node name="bar" id="b1">
    <node>
      <node/>
      <node/>
    </node>
    <node name="baz" id="b2">
      <node name="bat" id="b3"/>o;?
      <node name="bat" id="b4"/>
    </node>
    <node>o;?
      <node name="saz" id="c2">
        <node name="sat" id="c3"/>
      </node>
    </node>
  </node>
  <node name="gar" id="a1">
    <node name="gaz" id="a2">
      <node name="gat" id="a3"/>
      <node/>
    </node>
    <node>
      <node/>
    </node>
    <node>
      <node/>
    </node>
  </node>
</node>




On Sat, 2008-04-26 at 23:43 +0100, David Carlisle wrote:
> 
> This doesn't get quite the result you ask for I get ../bat for the last
> one, also I assume that nodes without a name should not contribute to
> the path (otherwise I'd need an extra ../ to get out of the unnamed
> node that contains c2).
> 
> <xsl:stylesheet version="2.0"
> 		xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
> 		xmlns:f="data:,f">
>  
> <xsl:key name="id" match="*" use="@id"/>
> <xsl:variable name="r" select="/"/>
> <xsl:template match="/">
> 
> a3 to b3 <xsl:value-of select="f:path('a3','b3')"/>
> c3 to b3 <xsl:value-of select="f:path('c3','b3')"/>
> b4 to b3 <xsl:value-of select="f:path('b4','b3')"/>
> 
> </xsl:template>
> 
> 
> <xsl:function name="f:path">
>  <xsl:param name="a"/>
>  <xsl:param name="b"/>
>  <xsl:variable name="an" select="key('id',$a,$r)"/>
>  <xsl:variable name="bn" select="key('id',$b,$r)"/>
>  <xsl:value-of>
>   <xsl:sequence select="($an/ancestor-or-self::node[@name] except $bn/ancestor::node)/'../'"/>
>   <xsl:value-of separator="/" select="($bn/ancestor-or-self::node[@name] except $an/ancestor::node)/@name"/>
>  </xsl:value-of>
> </xsl:function>
> 
> </xsl:stylesheet>
> 
> ________________________________________________________________________
> The Numerical Algorithms Group Ltd is a company registered in England
> and Wales with company number 1249803. The registered office is:
> Wilkinson House, Jordan Hill Road, Oxford OX2 8DR, United Kingdom.
> 
> This e-mail has been scanned for all viruses by Star. The service is
> powered by MessageLabs. 
> ________________________________________________________________________

Current Thread