3

I came across a very tricky problem today. I am parsing an XML document using XSLT 1.0. The XML provides me the the HEX color codes and then some manipulation instructions on the luminance and shade of the color. I need to generate a final color value (preferably in HEX or RGB values but HSL will also do).

Now to apply those manipulations I need to convert my HEX color values into HSL. It would be really great if it can be done directly form the XSL otherwise I might have re-parse the output of the XSL and do the conversion from Javascript (I would like to avoid this round-about way coz its not very efficient). In either case I need a formula for the conversion. I came across this conversion formula but it seems too complicated for XSLT and anyways its an RGB to HSL conversion formula.

Can anyone help me with this conversion?

Thanks in advance!

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Surender Thakran
  • 3,958
  • 11
  • 47
  • 81
  • possible duplicate of [How do you get the hue of a #xxxxxx colour?](http://stackoverflow.com/questions/3732046/how-do-you-get-the-hue-of-a-xxxxxx-colour) – Teemu Nov 13 '13 at 06:58
  • @Teemu thanx, i will have a look at it – Surender Thakran Nov 13 '13 at 07:01
  • @Teemu the code in the link is in javascript though most of it can be written in XSLT but some parts like `parseInt()` for numbers with base 16 is sadly not supported in `XSLT 1.0`. I am trying to avoid javascript, any idea how i can do without? – Surender Thakran Nov 13 '13 at 07:12
  • 2
    At start you could remove the [javascript] tag from the post ; ). – Teemu Nov 13 '13 at 07:21

1 Answers1

2

The formula looks straightforward to me; why do you think it's "too complicated for XSLT"?

It looks as if your initial problem is that you don't know how to translate hex numbers into decimals, in XSLT 1.0. Here is a simple template to do that; it accepts a two-digit hex number and returns a decimal equivalent.

<!--* Given a two-digit hex string, return the equivalent number in decimal. *-->
<xsl:template name="hex_to_dec">
  <xsl:param name="raw-hex" select="'00'"/>

  <!--* a list of hex digits, in numerical order *-->
  <xsl:variable name="hex-digits" select="'0123456789ABCDEF'"/>

  <!--* strip space and uppercase a-f *-->
  <xsl:variable name="xy" 
    select="normalize-space(translate($raw-hex,'abcdef','ABCDEF'))"/>

  <xsl:choose>
    <xsl:when test="translate($xy,$hex-digits,'') != ''">
      <xsl:message><xsl:value-of select="$raw-hex"
        /> is not a legal hexadecimal string</xsl:message>
    </xsl:when>
    <xsl:when test="string-length($xy) &lt; 2">
      <xsl:message>Hex string too short</xsl:message>
    </xsl:when>
    <xsl:when test="string-length($xy) &gt; 2">
      <xsl:message>Hex string too long</xsl:message>
    </xsl:when>
    <xsl:otherwise>
      <xsl:variable name="X" select="substring($xy,1,1)"/>
      <xsl:variable name="Y" select="substring($xy,2,1)"/>
      <xsl:variable name="Xval" 
        select="string-length(substring-before($hex-digits,$X))"/>
      <xsl:variable name="Yval" 
        select="string-length(substring-before($hex-digits,$Y))"/>
      <xsl:value-of select="16 * $Xval + $Yval"/>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

If I were you, I'd first write a template named rgb_to_hsl to accept three decimal numbers between 0 255 as parameters R, G, and B, and calculate an HSL string. Then I'd write a second template to accept an RGB hex string, parse out the hex values for red, green, and blue, convert them to decimals using the template given above, and then call rgb_to_hsl.

C. M. Sperberg-McQueen
  • 24,596
  • 5
  • 38
  • 65