How can I convert all relative paths (href's and src's) to absolute ones using the resolve-uri() function?
The situation is I have some xhtml that contains href's links and image src's that may or may not be absolute. Now for only the ones that are relative given a bace url how can I use xslt to transform all those relative links to absolute ones? I know I should use the resolve-uri() function somehow but I have no idea how I would do this. A sample would help me allot.
Hi Kenneth Looking at your part of that post, thanks but that doesn’t help me. Also I can already imagine doing it via a .Net control but I really would like to do this with XSLT. There is some xslt in the post that looks along the correct lines but I am not competent with xslt. I would love an example..
The XHTML that I want to format the links on is not from my site but from another. For example take the following XHTML taken from http://umbraco.org/ imagine it is in a XSLT parameter/variable:
Here's how I've done it before in xslt. The idea is to do a pattern search/replace. If the href doesn't start with href="http" (that is, if it starts with href="/") then I know I need to specify it. Same would go for img src= tags.
In the xslt, you'd have a separate template that you'd call by name. In my example I'm using the current page's bodyText property, but you could just as easily use a macro parameter instead.
@Dirk De Grave You may be right but as mentioned I am not competent with xslt so without an example I am quite lost..
@Douglas You are so close I can smell it! However all the tags are getting stripped from my xhtml. You see the variable is a nodeset not text. If I use text it works but I want to keep it as a nodeset and output as xml.. I have tried various permutations of copy-of value-of and disable-output-escaping but my tags still disappear. Here is what I have so far:
You're right... you'll end up converting your nodeset to text during the conversion. You'll then need to convert it back to a node-set when you're done. This is sometimes a bit tricky and can take a bit of trial and error to get just right.
The basic idea is to take the output of your variable ($content) and turn it back into a nodeset. There's the built-in <xsl:value-of select="msxsl:node-set($content)" /> that should do it, or at least get you close.
One option is the use the Replace function like this: umbraco.library:Replace($someText, 'href="/', 'href="http://www.somedomain.com') or based on Doug's reply you could transform the X(HT)ML like this:
This is an issue that I have been checking and I think it is a bug in Umbraco.
You can set the option <useDomainPrefixes>true</useDomainPrefixes> in the config file umbracosettings.config
to true. Then you have to add the domain name/hostname to all pages on level 2, like this:
Homepage > add hostname www.domain.com
* Page1 > add hostname www.domain.com/page1 without the aspx
* Page2 > add hostname www.domain.com/page2 without the aspx
Now your niceurl will work and give you an absolute url because it will search for the domain names up to level 2. I have this working on our installation using umbraco 4 and we are trying to change the method that causes this behavior wich is niceurldo in the library.
@Douglas & Kenneth Thanks for your help I have learned ALLOT over the last few nights (and there is allot more to learn), and your pointers where part of that. I finally have a solution I am happy with although not quite finished.. BTW I was not under pressure on this just wanted to learn something.
My solution was to make a c# function that emulates the behaviour of the XSLT 2.0 resolve-uri() function. I guess we will have to wait a few more years for MS to support this.
FYI (and for others) below is my XSLT & C#. I know I should match the node names AND the attributes to prevent issues but the below is not finished yet. I would like to award you both the solution but in the end Kenneth kicked my in the right direction so karma to you. Next time Douglas ?
Alec
P.S. Would appreciate feedback (code review etc)
C#
public static string resolveUri(string baseUrl, string relstr) { Uri uriout; Uri uribace = new Uri(baseUrl); if (Uri.TryCreate(uribace, relstr, out uriout)) { return uriout.ToString(); } else { return ""; } } private static bool TryCreateCleanUri(Uri baseUrl, string relstr, out Uri result) { if (!Uri.TryCreate(baseUrl, relstr, out result)) { return false; } else { return true; } }
XSLT
<xsl:template match="/"> <!--call the template for our XHTML document--> <xsl:apply-templates select="$nodesetVariable/*"/> </xsl:template>
<!--Identity Template: xsl:copy with recursion. This is cool it recursively call itself and all other templates copying every node: Find out more here http://www.xmlplease.com/xsltidentity-->; <xsl:template match="@*|node()"> <xsl:copy> <xsl:apply-templates select="@*|node()"/> </xsl:copy> </xsl:template>
<!--now if a href attribute is found in any node in the Identity Template we do something with it here--> <xsl:template match="@href"> <!--no chage to the atribute name--> <xsl:attribute name="href"> <!--test if this is a relitive link--> <!--only http as we could have https--> <xsl:if test="starts-with(., 'http') and $resolveLinks = 'true'"> <xsl:value-of select="." /> </xsl:if> <!--Call our resolveUri function. This is an xslt extension that comes with the package it uses c# to emulate the resolve-Uri() that is part of XSLT 2.0--> <!--I was advised to do a replace by first changing the nodeset to text but I wanted to keep this as a nodeset and I also wanted to nicely resolve relative paths--> <!--that climb the uri tree e.g. /../../../somefile.html. Note the '.' means use the value that exists--> <xsl:value-of select="parser.html2xml2:resolveUri($url, .)"/> </xsl:attribute> </xsl:template>
@Dirk Thanks for your suggestion too. Yes and no. I wanted to resolve things like /../../page.html also. Whilst bolting this to a url would work I was not happy with it and wanted to navigate the url.
How can I convert all relative paths (href's and src's) to absolute ones using the resolve-uri() function?
The situation is I have some xhtml that contains href's links and image src's that may or may not be absolute. Now for only the ones that are relative given a bace url how can I use xslt to transform all those relative links to absolute ones? I know I should use the resolve-uri() function somehow but I have no idea how I would do this. A sample would help me allot.
Thanks in advance.
Alec
See related post: http://our.umbraco.org/forum/developers/xslt/2932-How-to-get-the-full-url-of-a-node?p=1
Hi Kenneth
Looking at your part of that post, thanks but that doesn’t help me. Also I can already imagine doing it via a .Net control but I really would like to do this with XSLT. There is some xslt in the post that looks along the correct lines but I am not competent with xslt. I would love an example..
The XHTML that I want to format the links on is not from my site but from another. For example take the following XHTML taken from http://umbraco.org/ imagine it is in a XSLT parameter/variable:
<ul id="naviList">
<li><a href="/tour" title="Tour">Tour</a></li>
<li><a href="/products" title="Products">Products</a></li>
<li><a href="/videos" title="Videos">Videos</a></li>
<li><a href="/documentation" title="Documentation">Documentation</a></li>
<li><a href="/training" title="Training">Training</a></li>
<li><a href="/solution-providers" title="Solution Providers">Solution Providers</a></li>
<li><a href="http://www.google.com" title="google">Go To Google</a></li>
</ul>
Now imagine I want to resolve the absolute URL’s of the relative paths given the known url: http://umbraco.org/ so my output would be like this:
<ul id="naviList">
<li><a href="http://umbraco.org/tour" title="Tour">Tour</a></li>
<li><a href=" http://umbraco.org/products" title="Products">Products</a></li>
<li><a href=" http://umbraco.org/videos" title="Videos">Videos</a></li>
<li><a href=" http://umbraco.org/documentation" title="Documentation">Documentation</a></li>
<li><a href=" http://umbraco.org/training" title="Training">Training</a></li>
<li><a href=" http://umbraco.org/solution-providers" title="Solution Providers">Solution Providers</a></li>
<li><a href="http://www.google.com" title="google">Go To Google</a></li>
</ul>
Alec
Here's how I've done it before in xslt. The idea is to do a pattern search/replace. If the href doesn't start with href="http" (that is, if it starts with href="/") then I know I need to specify it. Same would go for img src= tags.
In the xslt, you'd have a separate template that you'd call by name. In my example I'm using the current page's bodyText property, but you could just as easily use a macro parameter instead.
cheers,
doug.
Hi Alec,
Can't you just use the starts-with xslt function to check whether you're dealing with a relative or absolute url path?
Hope this helps.
Regards,
/Dirk
@Dirk De Grave
You may be right but as mentioned I am not competent with xslt so without an example I am quite lost..
@Douglas
You are so close I can smell it! However all the tags are getting stripped from my xhtml. You see the variable is a nodeset not text. If I use text it works but I want to keep it as a nodeset and output as xml.. I have tried various permutations of copy-of value-of and disable-output-escaping but my tags still disappear. Here is what I have so far:
You're right... you'll end up converting your nodeset to text during the conversion. You'll then need to convert it back to a node-set when you're done. This is sometimes a bit tricky and can take a bit of trial and error to get just right.
The basic idea is to take the output of your variable ($content) and turn it back into a nodeset. There's the built-in <xsl:value-of select="msxsl:node-set($content)" /> that should do it, or at least get you close.
cheers,
doug.
One option is the use the Replace function like this: umbraco.library:Replace($someText, 'href="/', 'href="http://www.somedomain.com') or based on Doug's reply you could transform the X(HT)ML like this:
erh ... starts-with that is *blush*
Here you go, Kenneth's just given you a starts-with example. thanks kenny!
Hi,
This is an issue that I have been checking and I think it is a bug in Umbraco.
You can set the option <useDomainPrefixes>true</useDomainPrefixes> in the config file umbracosettings.config
to true. Then you have to add the domain name/hostname to all pages on level 2, like this:
Homepage > add hostname www.domain.com
* Page1 > add hostname www.domain.com/page1 without the aspx
* Page2 > add hostname www.domain.com/page2 without the aspx
Now your niceurl will work and give you an absolute url because it will search for the domain names up to level 2. I have this working on our installation using umbraco 4 and we are trying to change the method that causes this behavior wich is niceurldo in the library.
This is really a bug in Umbraco.
thx, Len.
mhh, maybe this is not what you need ....
@Douglas & Kenneth
Thanks for your help I have learned ALLOT over the last few nights (and there is allot more to learn), and your pointers where part of that. I finally have a solution I am happy with although not quite finished.. BTW I was not under pressure on this just wanted to learn something.
My solution was to make a c# function that emulates the behaviour of the XSLT 2.0 resolve-uri() function. I guess we will have to wait a few more years for MS to support this.
FYI (and for others) below is my XSLT & C#. I know I should match the node names AND the attributes to prevent issues but the below is not finished yet. I would like to award you both the solution but in the end Kenneth kicked my in the right direction so karma to you. Next time Douglas ?
Alec
P.S. Would appreciate feedback (code review etc)
C#
XSLT
@Dirk
Thanks for your suggestion too. Yes and no. I wanted to resolve things like /../../page.html also. Whilst bolting this to a url would work I was not happy with it and wanted to navigate the url.
Alec
is working on a reply...