Subject: Re: [xsl] XSLT 2 Function To Calculate Relative Paths? From: "James A. Robinson" <jim.robinson@xxxxxxxxxxxx> Date: Mon, 10 Mar 2008 09:05:09 -0700 |
> Does anyone have code lying about or can anyone point me to a > description of the algorithm for calculating the relative path from one > fully-qualified file to another? I know I've figured this out in the > past but I remember it being hard for my addled brain to work out the > details. A search of this list via MarkMail didn't reveal any past > discussion in an XSLT 2 context (where the task should be much easier > given functions and string tokenization). Probably this isn't as fully tested as you want, but something I wrote awhile ago. It assumes both paths are under the same base uri. If I were rewriting it, I'd do the work necessary to break the URI up into its components and properly remove dot segments from the path before applying they rest of the logic. <xd:doc> <xd:short>Return the relativized path leading from source to target.</xd:short> <xd:param name="source">The source path (e.g., base-uri()).</xd:param> <xd:param name="target">The target path.</xd:param> </xd:doc> <xsl:function name="sass:relativize" as="xs:anyURI"> <xsl:param name="source" as="xs:string" /> <xsl:param name="target" as="xs:string" /> <!-- Fully qualified source and target to source-uri and target-uri. --> <xsl:variable name="target-uri" select="resolve-uri($target)" /> <xsl:variable name="source-uri" select="resolve-uri($source)" /> <!-- Now we collapse consecutive slashes and strip trailing filenames from both to compute $a (source) and $b (target). We then split $a on '/' and walk through the sequence, comparing each part to the corresponding component in $b, concatenating the results with '/'. Result $c is a string representing the complete set of path components shared between the beginning of $a and the beginning of $b. --> <xsl:variable name="a" select="tokenize( replace( replace($source-uri, '//+', '/'), '[^/]+$', ''), '/')" /> <xsl:variable name="b" select="tokenize( replace( replace($target-uri, '//+', '/'), '[^/]+$', ''), '/')" /> <xsl:variable name="c" select="string-join( for $i in 1 to count($a) return (if ($a[$i] = $b[$i]) then $a[$i] else ()), '/')" /> <xsl:choose> <!-- if $c is empty, $a and $b do not share a common base, and we cannot return a relative path from the source to the target. In that case we just return the resolved target-uri. --> <xsl:when test="$c eq ''"> <xsl:sequence select="$target-uri" /> </xsl:when> <xsl:otherwise> <!-- Given the sequence $a and the string $c, we join $a using '/' and extract the substring remaining after the prefix $c is removed. We then replace all path components with '..', resulting in the steps up the directory path which must be made to reach the target from the source. This path is named $steps. --> <xsl:variable name="steps" select="replace(replace( substring-after(string-join($a, '/'), $c), '^/', ''), '[^/]+', '..')" /> <!-- Resolving $steps against $source-uri gives us $common-path, the fully qualified path shared between $source-uri and $target-uri. Stripping $common-path from $target-uri and prepending $steps will leave us with $final-path, the relative path from $source-uri to $target-uri. If the result is empty, the destination is './' --> <xsl:variable name="common-path" select="replace(resolve-uri($steps, $source-uri), '[^/]+$', '')" /> <xsl:variable name="final-path" select="replace(concat($steps, substring-after($target-uri, $common-path)), '^/', '')" /> <xsl:sequence select="xs:anyURI(if ($final-path eq '') then './' else $final-path)" /> </xsl:otherwise> </xsl:choose> </xsl:function> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - James A. Robinson jim.robinson@xxxxxxxxxxxx Stanford University HighWire Press http://highwire.stanford.edu/ +1 650 7237294 (Work) +1 650 7259335 (Fax)
Current Thread |
---|
|
<- Previous | Index | Next -> |
---|---|---|
Re: [xsl] XSLT 2 Function To Calcul, Tony Graham | Thread | Re: [xsl] XSLT 2 Function To Calcul, Eliot Kimber |
Re: [xsl] XSLT 2 Function To Calcul, Tony Graham | Date | Re: [xsl] Execute Stylesheet, Stefan Krause |
Month |