Search code examples
xmlxsltxslt-1.0xsl-fodocbook-5

How to change both foreground and background color for an inline element?


I'm trying to change both the foreground and background color of an inline element. The docbook snippet is this:

<command role=" f00 b01 ">Lorem Ipsum</command>

The XSL part in my customization layer is this:

[...]
<xsl:template match='db:command[contains(@role, " f00 ")]'>
<fo:inline color='#000000'><xsl:apply-templates/></fo:inline>
</xsl:template>
<xsl:template match='db:command[contains(@role, " b00 ")]'>
<fo:inline background-color='#000000'><xsl:apply-templates/></fo:inline>
</xsl:template>
[255 x 6 more lines, for each fXX and bXX where X is a hex digit
  and the colors are the 256 xterm RGB color specs.]

This only changes either the background color or the foreground color, depending on which template is last.

How can I apply both foreground and background when the role value is f00 b01? Note: it is not an option to make a third test like contains " f00 b01 " since there are 256 colors to chose from and specifying all combinations makes the number of templates explode.

Note: edited to match more closely the actual file contents

The mapping of xterm colors to rgb colors is as follows. From color 16 on they can be computed with a little perl script (snippet taken from xterm distruibution):

# colors 16-231 are a 6x6x6 color cube
for ($red = 0; $red < 6; $red++) {
    for ($green = 0; $green < 6; $green++) {
        for ($blue = 0; $blue < 6; $blue++) {
            $code = 16 + ($red * 36) + ($green * 6) + $blue;
            printf($line1, $code);
            printf($line2, $code);
            printf($line3,
                   ($red ? ($red * 40 + 55) : 0),
                   ($green ? ($green * 40 + 55) : 0),
                   ($blue ? ($blue * 40 + 55) : 0));
        }
    }
}

# colors 232-255 are a grayscale ramp, intentionally leaving out
# black and white
$code=232;
for ($gray = 0; $gray < 24; $gray++) {
    $level = ($gray * 10) + 8;
    $code = 232 + $gray;
    printf($line1, $code);
    printf($line2, $code);
    printf($line3,
           $level, $level, $level);
}

Result:

00 #000000  80 #af00d7 
01 #cd0000  81 #af00ff 
02 #00cd00  82 #af5f00 
03 #cdcd00  83 #af5f5f 
04 #0000ee  84 #af5f87 
05 #cd00cd  85 #af5faf 
06 #00cdcd  86 #af5fd7 
07 #e5e5e5  87 #af5fff 
08 #7f7f7f  88 #af8700 
09 #ff0000  89 #af875f 
0a #00ff00  8a #af8787 
0b #ffff00  8b #af87af 
0c #5c5cff  8c #af87d7 
0d #ff00ff  8d #af87ff 
0e #00ffff  8e #afaf00 
0f #ffffff  8f #afaf5f 
10 #000000  90 #afaf87 
11 #00005f  91 #afafaf 
12 #000087  92 #afafd7 
13 #0000af  93 #afafff 
14 #0000d7  94 #afd700 
15 #0000ff  95 #afd75f 
16 #005f00  96 #afd787 
17 #005f5f  97 #afd7af 
18 #005f87  98 #afd7d7 
19 #005faf  99 #afd7ff 
1a #005fd7  9a #afff00 
1b #005fff  9b #afff5f 
1c #008700  9c #afff87 
1d #00875f  9d #afffaf 
1e #008787  9e #afffd7 
1f #0087af  9f #afffff 
20 #0087d7  a0 #d70000 
21 #0087ff  a1 #d7005f 
22 #00af00  a2 #d70087 
23 #00af5f  a3 #d700af 
24 #00af87  a4 #d700d7 
25 #00afaf  a5 #d700ff 
26 #00afd7  a6 #d75f00 
27 #00afff  a7 #d75f5f 
28 #00d700  a8 #d75f87 
29 #00d75f  a9 #d75faf 
2a #00d787  aa #d75fd7 
2b #00d7af  ab #d75fff 
2c #00d7d7  ac #d78700 
2d #00d7ff  ad #d7875f 
2e #00ff00  ae #d78787 
2f #00ff5f  af #d787af 
30 #00ff87  b0 #d787d7 
31 #00ffaf  b1 #d787ff 
32 #00ffd7  b2 #d7af00 
33 #00ffff  b3 #d7af5f 
34 #5f0000  b4 #d7af87 
35 #5f005f  b5 #d7afaf 
36 #5f0087  b6 #d7afd7 
37 #5f00af  b7 #d7afff 
38 #5f00d7  b8 #d7d700 
39 #5f00ff  b9 #d7d75f 
3a #5f5f00  ba #d7d787 
3b #5f5f5f  bb #d7d7af 
3c #5f5f87  bc #d7d7d7 
3d #5f5faf  bd #d7d7ff 
3e #5f5fd7  be #d7ff00 
3f #5f5fff  bf #d7ff5f 
40 #5f8700  c0 #d7ff87 
41 #5f875f  c1 #d7ffaf 
42 #5f8787  c2 #d7ffd7 
43 #5f87af  c3 #d7ffff 
44 #5f87d7  c4 #ff0000 
45 #5f87ff  c5 #ff005f 
46 #5faf00  c6 #ff0087 
47 #5faf5f  c7 #ff00af 
48 #5faf87  c8 #ff00d7 
49 #5fafaf  c9 #ff00ff 
4a #5fafd7  ca #ff5f00 
4b #5fafff  cb #ff5f5f 
4c #5fd700  cc #ff5f87 
4d #5fd75f  cd #ff5faf 
4e #5fd787  ce #ff5fd7 
4f #5fd7af  cf #ff5fff 
50 #5fd7d7  d0 #ff8700 
51 #5fd7ff  d1 #ff875f 
52 #5fff00  d2 #ff8787 
53 #5fff5f  d3 #ff87af 
54 #5fff87  d4 #ff87d7 
55 #5fffaf  d5 #ff87ff 
56 #5fffd7  d6 #ffaf00 
57 #5fffff  d7 #ffaf5f 
58 #870000  d8 #ffaf87 
59 #87005f  d9 #ffafaf 
5a #870087  da #ffafd7 
5b #8700af  db #ffafff 
5c #8700d7  dc #ffd700 
5d #8700ff  dd #ffd75f 
5e #875f00  de #ffd787 
5f #875f5f  df #ffd7af 
60 #875f87  e0 #ffd7d7 
61 #875faf  e1 #ffd7ff 
62 #875fd7  e2 #ffff00 
63 #875fff  e3 #ffff5f 
64 #878700  e4 #ffff87 
65 #87875f  e5 #ffffaf 
66 #878787  e6 #ffffd7 
67 #8787af  e7 #ffffff 
68 #8787d7  e8 #080808 
69 #8787ff  e9 #121212 
6a #87af00  ea #1c1c1c 
6b #87af5f  eb #262626 
6c #87af87  ec #303030 
6d #87afaf  ed #3a3a3a 
6e #87afd7  ee #444444 
6f #87afff  ef #4e4e4e 
70 #87d700  f0 #585858 
71 #87d75f  f1 #626262 
72 #87d787  f2 #6c6c6c 
73 #87d7af  f3 #767676 
74 #87d7d7  f4 #808080 
75 #87d7ff  f5 #8a8a8a 
76 #87ff00  f6 #949494 
77 #87ff5f  f7 #9e9e9e 
78 #87ff87  f8 #a8a8a8 
79 #87ffaf  f9 #b2b2b2 
7a #87ffd7  fa #bcbcbc 
7b #87ffff  fb #c6c6c6 
7c #af0000  fc #d0d0d0 
7d #af005f  fd #dadada 
7e #af0087  fe #e4e4e4 
7f #af00af  ff #eeeeee 

Solution

  • First and foremost: if you are the author of the source document, you should use a separate attribute for each ... well, attribute - and save yourself the pain of extracting the individual values using awkward string manipulations. That's what XML is all about.

    Next, the idea of using 2 x 256 templates is absurd. You only need to extract the two hex digit codes signifying the xterm color and translate them to a #rrggb format.

    The extraction process (which wouldn't required at all if the attributes were separated) is not that difficult, nevertheless. Given:

    <command role=" f00 b01 ">Lorem Ipsum</command>
    

    you can use:

    <xsl:template match="command">
        <xsl:variable name="fg" select="substring-before(substring-after(@role, ' f'), ' ')" />
        <xsl:variable name="bg" select="substring-before(substring-after(@role, ' b'), ' ')" />
        <!--  -->
    </xsl:template>
    

    Now you only need to translate the extracted xterm codes to rgb. You didn't say how these codes were derived in the first place. I suspect this could be reverse-calculated, but if that's not possible or not convenient, use an external XML document (or an internal variable) to look it up.


    Here's an example of a lookup from an internal variable:

    <xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:exsl="http://exslt.org/common"
    extension-element-prefixes="exsl">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
    
    <xsl:template match="command">
        <xsl:variable name="fg" select="substring-before(substring-after(@role, ' f'), ' ')" />
        <xsl:variable name="bg" select="substring-before(substring-after(@role, ' b'), ' ')" />
    
        <xsl:variable name="color-set" select="exsl:node-set($colors)/color" />
    
        <xsl:variable name="color" select="$color-set[@code=$fg]" />
        <xsl:variable name="background-color" select="$color-set[@code=$bg]" />
        <!--  -->   
    </xsl:template>
    
    <xsl:variable name="colors">
        <color code="00">#000000</color>
        <color code="01">#cd0000</color>
        <color code="02">#00cd00</color>
        <color code="03">#cdcd00</color>
        <color code="04">#0000ee</color>
        <color code="05">#cd00cd</color>
        <color code="06">#00cdcd</color>
        <color code="07">#e5e5e5</color>
        <color code="08">#7f7f7f</color>
        <color code="09">#ff0000</color>
        <color code="0a">#00ff00</color>
        <color code="0b">#ffff00</color>
        <color code="0c">#5c5cff</color>
        <color code="0d">#ff00ff</color>
        <color code="0e">#00ffff</color>
        <color code="0f">#ffffff</color>
        <color code="10">#000000</color>
        <color code="11">#00005f</color>
        <color code="12">#000087</color>
        <color code="13">#0000af</color>
        <color code="14">#0000d7</color>
        <color code="15">#0000ff</color>
        <color code="16">#005f00</color>
        <color code="17">#005f5f</color>
        <color code="18">#005f87</color>
        <color code="19">#005faf</color>
        <color code="1a">#005fd7</color>
        <color code="1b">#005fff</color>
        <color code="1c">#008700</color>
        <color code="1d">#00875f</color>
        <color code="1e">#008787</color>
        <color code="1f">#0087af</color>
        <color code="20">#0087d7</color>
        <color code="21">#0087ff</color>
        <color code="22">#00af00</color>
        <color code="23">#00af5f</color>
        <color code="24">#00af87</color>
        <color code="25">#00afaf</color>
        <color code="26">#00afd7</color>
        <color code="27">#00afff</color>
        <color code="28">#00d700</color>
        <color code="29">#00d75f</color>
        <color code="2a">#00d787</color>
        <color code="2b">#00d7af</color>
        <color code="2c">#00d7d7</color>
        <color code="2d">#00d7ff</color>
        <color code="2e">#00ff00</color>
        <color code="2f">#00ff5f</color>
        <color code="30">#00ff87</color>
        <color code="31">#00ffaf</color>
        <color code="32">#00ffd7</color>
        <color code="33">#00ffff</color>
        <color code="34">#5f0000</color>
        <color code="35">#5f005f</color>
        <color code="36">#5f0087</color>
        <color code="37">#5f00af</color>
        <color code="38">#5f00d7</color>
        <color code="39">#5f00ff</color>
        <color code="3a">#5f5f00</color>
        <color code="3b">#5f5f5f</color>
        <color code="3c">#5f5f87</color>
        <color code="3d">#5f5faf</color>
        <color code="3e">#5f5fd7</color>
        <color code="3f">#5f5fff</color>
        <color code="40">#5f8700</color>
        <color code="41">#5f875f</color>
        <color code="42">#5f8787</color>
        <color code="43">#5f87af</color>
        <color code="44">#5f87d7</color>
        <color code="45">#5f87ff</color>
        <color code="46">#5faf00</color>
        <color code="47">#5faf5f</color>
        <color code="48">#5faf87</color>
        <color code="49">#5fafaf</color>
        <color code="4a">#5fafd7</color>
        <color code="4b">#5fafff</color>
        <color code="4c">#5fd700</color>
        <color code="4d">#5fd75f</color>
        <color code="4e">#5fd787</color>
        <color code="4f">#5fd7af</color>
        <color code="50">#5fd7d7</color>
        <color code="51">#5fd7ff</color>
        <color code="52">#5fff00</color>
        <color code="53">#5fff5f</color>
        <color code="54">#5fff87</color>
        <color code="55">#5fffaf</color>
        <color code="56">#5fffd7</color>
        <color code="57">#5fffff</color>
        <color code="58">#870000</color>
        <color code="59">#87005f</color>
        <color code="5a">#870087</color>
        <color code="5b">#8700af</color>
        <color code="5c">#8700d7</color>
        <color code="5d">#8700ff</color>
        <color code="5e">#875f00</color>
        <color code="5f">#875f5f</color>
        <color code="60">#875f87</color>
        <color code="61">#875faf</color>
        <color code="62">#875fd7</color>
        <color code="63">#875fff</color>
        <color code="64">#878700</color>
        <color code="65">#87875f</color>
        <color code="66">#878787</color>
        <color code="67">#8787af</color>
        <color code="68">#8787d7</color>
        <color code="69">#8787ff</color>
        <color code="6a">#87af00</color>
        <color code="6b">#87af5f</color>
        <color code="6c">#87af87</color>
        <color code="6d">#87afaf</color>
        <color code="6e">#87afd7</color>
        <color code="6f">#87afff</color>
        <color code="70">#87d700</color>
        <color code="71">#87d75f</color>
        <color code="72">#87d787</color>
        <color code="73">#87d7af</color>
        <color code="74">#87d7d7</color>
        <color code="75">#87d7ff</color>
        <color code="76">#87ff00</color>
        <color code="77">#87ff5f</color>
        <color code="78">#87ff87</color>
        <color code="79">#87ffaf</color>
        <color code="7a">#87ffd7</color>
        <color code="7b">#87ffff</color>
        <color code="7c">#af0000</color>
        <color code="7d">#af005f</color>
        <color code="7e">#af0087</color>
        <color code="7f">#af00af</color>
        <color code="80">#af00d7</color>
        <color code="81">#af00ff</color>
        <color code="82">#af5f00</color>
        <color code="83">#af5f5f</color>
        <color code="84">#af5f87</color>
        <color code="85">#af5faf</color>
        <color code="86">#af5fd7</color>
        <color code="87">#af5fff</color>
        <color code="88">#af8700</color>
        <color code="89">#af875f</color>
        <color code="8a">#af8787</color>
        <color code="8b">#af87af</color>
        <color code="8c">#af87d7</color>
        <color code="8d">#af87ff</color>
        <color code="8e">#afaf00</color>
        <color code="8f">#afaf5f</color>
        <color code="90">#afaf87</color>
        <color code="91">#afafaf</color>
        <color code="92">#afafd7</color>
        <color code="93">#afafff</color>
        <color code="94">#afd700</color>
        <color code="95">#afd75f</color>
        <color code="96">#afd787</color>
        <color code="97">#afd7af</color>
        <color code="98">#afd7d7</color>
        <color code="99">#afd7ff</color>
        <color code="9a">#afff00</color>
        <color code="9b">#afff5f</color>
        <color code="9c">#afff87</color>
        <color code="9d">#afffaf</color>
        <color code="9e">#afffd7</color>
        <color code="9f">#afffff</color>
        <color code="a0">#d70000</color>
        <color code="a1">#d7005f</color>
        <color code="a2">#d70087</color>
        <color code="a3">#d700af</color>
        <color code="a4">#d700d7</color>
        <color code="a5">#d700ff</color>
        <color code="a6">#d75f00</color>
        <color code="a7">#d75f5f</color>
        <color code="a8">#d75f87</color>
        <color code="a9">#d75faf</color>
        <color code="aa">#d75fd7</color>
        <color code="ab">#d75fff</color>
        <color code="ac">#d78700</color>
        <color code="ad">#d7875f</color>
        <color code="ae">#d78787</color>
        <color code="af">#d787af</color>
        <color code="b0">#d787d7</color>
        <color code="b1">#d787ff</color>
        <color code="b2">#d7af00</color>
        <color code="b3">#d7af5f</color>
        <color code="b4">#d7af87</color>
        <color code="b5">#d7afaf</color>
        <color code="b6">#d7afd7</color>
        <color code="b7">#d7afff</color>
        <color code="b8">#d7d700</color>
        <color code="b9">#d7d75f</color>
        <color code="ba">#d7d787</color>
        <color code="bb">#d7d7af</color>
        <color code="bc">#d7d7d7</color>
        <color code="bd">#d7d7ff</color>
        <color code="be">#d7ff00</color>
        <color code="bf">#d7ff5f</color>
        <color code="c0">#d7ff87</color>
        <color code="c1">#d7ffaf</color>
        <color code="c2">#d7ffd7</color>
        <color code="c3">#d7ffff</color>
        <color code="c4">#ff0000</color>
        <color code="c5">#ff005f</color>
        <color code="c6">#ff0087</color>
        <color code="c7">#ff00af</color>
        <color code="c8">#ff00d7</color>
        <color code="c9">#ff00ff</color>
        <color code="ca">#ff5f00</color>
        <color code="cb">#ff5f5f</color>
        <color code="cc">#ff5f87</color>
        <color code="cd">#ff5faf</color>
        <color code="ce">#ff5fd7</color>
        <color code="cf">#ff5fff</color>
        <color code="d0">#ff8700</color>
        <color code="d1">#ff875f</color>
        <color code="d2">#ff8787</color>
        <color code="d3">#ff87af</color>
        <color code="d4">#ff87d7</color>
        <color code="d5">#ff87ff</color>
        <color code="d6">#ffaf00</color>
        <color code="d7">#ffaf5f</color>
        <color code="d8">#ffaf87</color>
        <color code="d9">#ffafaf</color>
        <color code="da">#ffafd7</color>
        <color code="db">#ffafff</color>
        <color code="dc">#ffd700</color>
        <color code="dd">#ffd75f</color>
        <color code="de">#ffd787</color>
        <color code="df">#ffd7af</color>
        <color code="e0">#ffd7d7</color>
        <color code="e1">#ffd7ff</color>
        <color code="e2">#ffff00</color>
        <color code="e3">#ffff5f</color>
        <color code="e4">#ffff87</color>
        <color code="e5">#ffffaf</color>
        <color code="e6">#ffffd7</color>
        <color code="e7">#ffffff</color>
        <color code="e8">#080808</color>
        <color code="e9">#121212</color>
        <color code="ea">#1c1c1c</color>
        <color code="eb">#262626</color>
        <color code="ec">#303030</color>
        <color code="ed">#3a3a3a</color>
        <color code="ee">#444444</color>
        <color code="ef">#4e4e4e</color>
        <color code="f0">#585858</color>
        <color code="f1">#626262</color>
        <color code="f2">#6c6c6c</color>
        <color code="f3">#767676</color>
        <color code="f4">#808080</color>
        <color code="f5">#8a8a8a</color>
        <color code="f6">#949494</color>
        <color code="f7">#9e9e9e</color>
        <color code="f8">#a8a8a8</color>
        <color code="f9">#b2b2b2</color>
        <color code="fa">#bcbcbc</color>
        <color code="fb">#c6c6c6</color>
        <color code="fc">#d0d0d0</color>
        <color code="fd">#dadada</color>
        <color code="fe">#e4e4e4</color>
        <color code="ff">#eeeeee</color>
    </xsl:variable>
    
    </xsl:stylesheet>