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

Subject: Re: [xsl] Overflow on building relative paths for one case only
From: Cynthia.Arangua@xxxxxxxxxxxxxx
Date: Tue, 15 Jan 2008 12:49:34 -0600
Thank you both for your time and suggestions.  I have learned from my
mistakes.
-----"Sam Byland" <shbyland@xxxxxxxxxxx> wrote: -----


To: <xsl-list@xxxxxxxxxxxxxxxxxxxxxx>
From: "Sam Byland" <shbyland@xxxxxxxxxxx>
Date: 01/12/2008 01:18PM
Subject: Re: [xsl] Overflow on building relative paths for one case only

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