Subject: Re: 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.
> ________________________________________________________________________
|