Dynamically replace href attribute using Diazo/XSL

My intention is to make all anchor tags with an href containing
https://externalsite.com be replaced with a redirect url
http://mysite.com?redirect_url=https://externalsite.com.

So we'd get mappings like this:

https://externalsite.com --> http://mysite.com?redirect_url=http://externalsite.com
https://externalsite.com/blah --> http://mysite.com?redirect_url=http://externalsite.com/blah
https://externalsite.com/ab/c --> http://mysite.com?redirect_url=http://externalsite.com/blah/ab/c

I'm using code similar to this to dynamically replace the href attribute of urls on my site.

 <xsl:template match="a/@href[starts-with(., 'https://externalsite.com')]">
 <xsl:attribute name="href">http://mysite.com?redirect_url=<xsl:value-of select="." />
  </xsl:attribute> 
</xsl:template> 

It works beautifully when the href in question is part of the content but when the href in question is part of the template the rule is not activated. Is there a way to achieve this for urls in the template. This is especially important as I don't always have control over the source template.

To get it to work on the template I've come up with this, which comes close:

<replace css:theme="a[href^='https://externalsite.com']" method="raw">
      <a><xsl:attribute name="href">http://redirect_to.com?original_url=<xsl:value-of select="./@href" />
             </xsl:attribute>
             <xsl:value-of select="./a/text()" />replaced here
      </a>
  </replace>

The problem is that none of the select statements do anything, the select="./@href" isn't retrieving the href of the anchor tag in my template, in fact it doesn't seem to retrieve anything. The same with select="./a/text()".

1 Like

Indeed it does not work. When you use replace (or any rule) on the theme, the context is empty, because the template is not processed by an XSLT sheet, it is turned into and XSLT sheet.

For instance, if your theme is:
<li><a href="http://plone.com">Plone</a></li>

And you replace the a like you did, then Diazo will produce an XSL sheet like this:
<li><a><xsl:attribute name="href">http://redirect_to.com?original_url=<xsl:value-of select="./@href" /> </xsl:attribute> <xsl:value-of select="./a/text()" />replaced here </a></li>

As you can see, the original a element has disappear and has been replaced with some xsl stuff where . only represent the currently processed DOM element, not your original a element.

So it really cannot work.

I can imagine 2 workarounds:

  • change the links manually in your theme (the thelme is static, why don't you write directly the proper link there?)
  • do it in Javascript.

Eric

1 Like

It should also be possible (but probably complicated) to do it with lxml and some kind of transform.
(I only mention this because there was a GSOC project with using lxml for safe transform,... maybe this is part of Plone 5 already?)

There is a 'built in rewrite' ( in lxml.html.clean , I think... maybe something like this :smile:https://github.com/espenmn/medialog.lxml/blob/master/medialog/lxml/views.py#L149

1 Like

We're using JS to do it now. Perhaps I'm being too old school shopping for a JS free way. I may end up finding a way to just hardcode the links in the theme and only relying on it for content otherwise.

I might finally have my answer to: http://stackoverflow.com/questions/13316690/how-to-compute-an-href-value-with-diazo-rules

Not. Possible.