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:22:59 -0400 |
Here is a slightly more reasonable verion of the XSL. I moved the common path building to a common template and I am using last() to find the closest common ancestor in the two sequences (they should be in document order, right?). But it still doesn't work. <?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:apply-templates select="key('config', 'a3')" mode="path"> <xsl:with-param name="target-id" select="'b3'"/> </xsl:apply-templates> <xsl:apply-templates select="key('config', 'b4')" mode="path"> <xsl:with-param name="target-id" select="'b3'"/> </xsl:apply-templates> <xsl:apply-templates select="key('config', 'c3')" mode="path"> <xsl:with-param name="target-id" select="'b3'"/> </xsl:apply-templates> </test> </xsl:template> <xsl:template match="*" mode="path"> <xsl:param name="target-id"/> <xsl:variable name="target-anc-and-self"> <xsl:apply-templates select="key('config', $target-id)" mode="ancestry"/> </xsl:variable> <xsl:variable name="anc-and-self"> <xsl:apply-templates select="." mode="ancestry"/> </xsl:variable> <xsl:variable name="common-ancestor" select="($anc-and-self intersect $target-anc-and-self)[last()]"/> <xsl:copy-of select="$common-ancestor"/> <xsl:variable name="path-to-target"> <xsl:apply-templates select="." mode="path-up"> <xsl:with-param name="common-ancestor" select="$common-ancestor"/> </xsl:apply-templates> <xsl:apply-templates select="key('config', $target-id)" mode="path-down"> <xsl:with-param name="common-ancestor" select="$common-ancestor"/> </xsl:apply-templates> </xsl:variable> <path href="{$path-to-target}"/> </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> On Sun, 2008-04-27 at 09:02 -0400, Robert Koberg wrote: > 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 |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] XSL/XPath 2.0 - most effi, Robert Koberg | Thread | Re: [xsl] XSL/XPath 2.0 - most effi, Liam Quin |
Re: [xsl] XSL/XPath 2.0 - most effi, Robert Koberg | Date | Re: [xsl] Comparison of XSD, NVDL, , Florent Georges |
Month |