<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" version="5.0" encoding="UTF-8"/>

  <xsl:template name="EncodeUrl">
    <xsl:param name="str"/>

    <!-- We support only a characters to be escaped that come from a subset of the ASCII character set. We do not support the ranges 0-31 and 127-159. -->
    <!-- This variable is needed to get the codepoint (character code) of the characters to be escaped -->
    <xsl:variable name="asciiSubset"> !"#$%&amp;'()*+,-./0123456789:;&lt;=&gt;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~</xsl:variable>

    <!-- https://de.wikipedia.org/wiki/URL-Encoding --> 
    <xsl:variable name="toBeEscaped"> :/?#[]@!$&amp;'()*+,;=</xsl:variable>

    <!-- Define the hex literals for the escaped output -->
    <xsl:variable name="hex" >0123456789ABCDEF</xsl:variable>


    <xsl:if test="$str">
      <!-- We check the first character in the string... -->
      <xsl:variable name="characterToCheck" select="substring($str,1,1)"/>
      <xsl:choose>
        <xsl:when test="not(contains($toBeEscaped,$characterToCheck))">
          <xsl:value-of select="$characterToCheck"/>
        </xsl:when>
        <xsl:otherwise>
          <xsl:variable name="codepointOfCharacterToBeEscaped">
            <xsl:choose>
              <xsl:when test="contains($asciiSubset,$characterToCheck)">
                <xsl:value-of select="string-length(substring-before($asciiSubset,$characterToCheck)) + 32"/>
              </xsl:when>
              <xsl:otherwise>
                <!-- Unsupported character to be escaped. Use a "?" instead. "?" is codepoint 63 in ASCII -->
                <xsl:text>63</xsl:text>
              </xsl:otherwise>
            </xsl:choose>
          </xsl:variable>
        <xsl:variable name="hex-digit1" select="substring($hex,floor($codepointOfCharacterToBeEscaped div 16) + 1,1)"/>
        <xsl:variable name="hex-digit2" select="substring($hex,$codepointOfCharacterToBeEscaped mod 16 + 1,1)"/>
        <!-- Output the escaped character: "%" plus two hex digits -->
        <xsl:value-of select="concat('%',$hex-digit1,$hex-digit2)"/>
        </xsl:otherwise>
      </xsl:choose>
      <xsl:if test="string-length($str) &gt; 1">
        <!-- ... and call the template recursively until all characters in the string are checked -->
        <xsl:call-template name="EncodeUrl">
          <xsl:with-param name="str" select="substring($str,2)"/>
        </xsl:call-template>
      </xsl:if>
    </xsl:if>
  </xsl:template>

</xsl:stylesheet>
