xsl-list
[Top] [All Lists]

Re: auto-hyperlinker (how to search/replace)?

2003-05-29 02:49:16
Hi Terence,

Is it possible to write some XSL code which will search some text()
for a URL pattern and replace it with a hyperlinked version of
itself.

Yes, but it's not particularly straight-forward. Creating a
"hyperlink" named template that takes a string and returns text nodes
and elements -- the elements being hyperlinks:

<xsl:template name="hyperlink">
  <xsl:param name="string" select="string()" />
  ...
</xsl:template>

The template needs to search for the first thing that looks like a
URL, so the string 'http://' will do nicely. If the string doesn't
contain the string 'http://' then it can just be output as-is:

<xsl:template name="hyperlink">
  <xsl:param name="string" select="string()" />
  <xsl:choose>
    <xsl:when test="contains($string, 'http://')">
      ...
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$string" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Anything before the 'http://', if it occurs, can just be output as a
text node:

<xsl:template name="hyperlink">
  <xsl:param name="string" select="string()" />
  <xsl:choose>
    <xsl:when test="contains($string, 'http://')">
      <xsl:value-of select="substring-before($string, 'http://')" />
      ...
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$string" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

The URL itself needs to be identified: taking the substring from the
'http://' to the next space will probably work:

<xsl:template name="hyperlink">
  <xsl:param name="string" select="string()" />
  <xsl:choose>
    <xsl:when test="contains($string, 'http://')">
      <xsl:value-of select="substring-before($string, 'http://')" />
      <xsl:variable name="rest"
                    select="substring-after($string, 'http://')" />
      <xsl:variable name="url"
        select="concat('http://', substring-before($rest, ' '))" />
      ...
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$string" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Then you can make the link around that URL:

<xsl:template name="hyperlink">
  <xsl:param name="string" select="string()" />
  <xsl:choose>
    <xsl:when test="contains($string, 'http://')">
      <xsl:value-of select="substring-before($string, 'http://')" />
      <xsl:variable name="rest"
                    select="substring-after($string, 'http://')" />
      <xsl:variable name="url"
        select="concat('http://', substring-before($rest, ' '))" />
      <a href="{$url}">
        <xsl:value-of select="$url" />
      </a>
      ...
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$string" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

Finally, you need to move on to the rest of the string, after the URL,
and call the template (recursively) on that piece of the string, in
case there are any more URLs within it:

<xsl:template name="hyperlink">
  <xsl:param name="string" select="string()" />
  <xsl:choose>
    <xsl:when test="contains($string, 'http://')">
      <xsl:value-of select="substring-before($string, 'http://')" />
      <xsl:variable name="rest"
                    select="substring-after($string, 'http://')" />
      <xsl:variable name="url"
        select="concat('http://', substring-before($rest, ' '))" />
      <a href="{$url}">
        <xsl:value-of select="$url" />
      </a>
      <xsl:call-template name="hyperlink">
        <xsl:with-param name="string"
                        select="substring-after($rest, $url)" />
      </xsl:call-template>
    </xsl:when>
    <xsl:otherwise>
      <xsl:value-of select="$string" />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

XSLT 2.0 makes this process a lot easier: you can use
<xsl:analyze-string> with regular expressions to do this kind of
string processing. In XSLT 2.0, the template would look more like:

<xsl:template name="hyperlink">
  <xsl:param name="string" select="string(.)" />
  <xsl:analyze-string select="$string"
                      regex="http://[^ ]+">
    <xsl:matching-substring>
      <a href="{.}">
        <xsl:value-of select="." />
      </a>
    </xsl:matching-substring>
    <xsl:non-matching-substring>
      <xsl:value-of select="." />
    </xsl:non-matching-substring>
  </xsl:analyze-string>
</xsl:template>

and of course the regex for matching URLs could be a lot more
sophisticated.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



<Prev in Thread] Current Thread [Next in Thread>