Re: [xsl] Overflow on building relative paths for one case only

Subject: Re: [xsl] Overflow on building relative paths for one case only
From: "Sam Byland" <shbyland@xxxxxxxxxxx>
Date: Sat, 12 Jan 2008 12:18:43 -0800
Thanks Michael for correcting my flawed fix :) -- and it would always avoid her infinite loop :)

I've scrutinized her code more closely, and I think I've figured out what the OP was intending to do (she was on the right track with <!--<xsl:when test="starts-with($to,$from)">--> but had commented it out). Since the $samePath variable is only used once in the following xsl:choose, the relativeUrl template could be further simplified as:

<xsl:template name="relativeUrl">
 <xsl:param name="from"/>
 <xsl:param name="to"/>

 <xsl:choose>
   <xsl:when test=" starts-with($to,$from) ">

<xsl:value-of select="substring-after(substring-after($to,$from),'/')"/>

   </xsl:when>
   <xsl:otherwise>

<xsl:variable name="strFrom">

       <xsl:call-template name="str">
         <xsl:with-param name="from" select="$from"/>
         <xsl:with-param name="to" select="$to"/>
       </xsl:call-template>

</xsl:variable>

     <xsl:variable name="dotdotSlash">
       <xsl:call-template name="dotSlash">
         <xsl:with-param name="convert" select="$strFrom"/>
       </xsl:call-template>
     </xsl:variable>

<xsl:variable name="url">
<xsl:value-of select="$dotdotSlash"/>
<xsl:value-of select="substring-after(substring-after($to,substring-before($from,$strFrom)),'/')"/>
</xsl:variable>


<xsl:value-of select="$url"/>

   </xsl:otherwise>
 </xsl:choose>
</xsl:template>

But that doesn't address the recursion problem with the str template. Looking at this template rule more closely, it appears that all she's trying to do is figure out if the "first" directory in the path is the same, and if so, check the "next" directory, and so-on. Making a few corrections, I came up with this:

<xsl:template name="str">
 <xsl:param name="from"/>
 <xsl:param name="to"/>

<xsl:variable name="strFromBetweenSlashes" select="substring-before(substring-after($from,'/'),'/')"/>
<xsl:variable name="strToBetweenSlashes" select="substring-before(substring-after($to,'/'),'/')"/>


<xsl:choose>
<xsl:when test=" $strFromBetweenSlashes = $strToBetweenSlashes and contains(substring-after($from,'/'),'/') ">


<xsl:call-template name="str">
<xsl:with-param name="from" select="substring-after(substring-after($from,'/'),$strFromBetweenSlashes)"/>
<xsl:with-param name="to" select="substring-after(substring-after($to,'/'),$strToBetweenSlashes)"/>
</xsl:call-template>


   </xsl:when>
   <xsl:otherwise>

<xsl:value-of select="$from"/>

   </xsl:otherwise>
 </xsl:choose>
</xsl:template>

The above two updates look like they get decent results...

Cheers,

...sam


----- Original Message ----- From: "Michael Kay" <mike@xxxxxxxxxxxx>
To: <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
Sent: Saturday, January 12, 2008 10:18 AM
Subject: RE: [xsl] Overflow on building relative paths for one case only



It looks like your problem is associated with setting your
variable $samePath to the boolean true() or false(), and then
later on checking if $samePath equals the string 'false':

That doesn't look wrong to me. <xsl:value-of select="false()"/> will create a text node whose string value is "false", just as if you wrote <xsl:text>false</xsl:text>.

Moreover, <xsl:when test="not($samePath)"> is definitely wrong. $samePath
is
a result tree fragment, and converting a result tree fragment to a boolean
should always give true.

Looking at the logic, why not make $samePath a boolean variable? This is
possible even in XSLT 1.0:

<xsl:variable name="samePath" select="$to=$from and
not(contains(substring-after(substring-after($to,$from),'/'),'/'))"/>.
Replaces 20 lines of code by one, and if you can do that a few times then
more of us might be inclined to look at the code and help you with it.

In fact that immediately seems to show a flaw: if $to=$from and both are
strings, then substring-after($to, $from) is "", and substring-after("",
"/") is "", and contains("", "/") is false, so the condition reduces
further
to:

<xsl:variable name="samePath" select="$to=$from"/>

Michael Kay
http://www.saxonica.com/


> <xsl:template name="relativeUrl"> > <xsl:param name="from"/> > <xsl:param name="to"/> > <xsl:variable name="samePath"> > <xsl:choose> > <!--<xsl:when test="starts-with($to,$from)">--> > <xsl:when test="$to=$from"> > <xsl:choose> > <xsl:when > test="contains(substring-after(substring-after($to,$from),'/'),'/')"> > <xsl:value-of select="false()"/> ^^^^^^^^^ > </xsl:when> > <xsl:otherwise> > <xsl:value-of select="true()"/> ^^^^^^^^ > </xsl:otherwise> > </xsl:choose> > </xsl:when> > <xsl:otherwise> > <xsl:value-of select="false()"/> ^^^^^^^^^ > </xsl:otherwise> > </xsl:choose> > </xsl:variable> > <xsl:choose> > <xsl:when test="$samePath='false'"> ^^^^^^^^^^^^^^^^^^^ If you change that last xsl:when to:

> <xsl:when test="not($samePath)">

uou should be all set. For the example you provided, I get:

<html>
   <head>
      <meta http-equiv="Content-Type" content="text/html;
charset=utf-8">

      <title>Getting relative paths</title>
   </head>

<body>/web_cabinet/folder1/folder2/folder3<br>/web_cabinet/fol
der1/folder2/linkingToDocument.doc<br></body>
</html>

Cheers,

...sam

Current Thread