tags:

views:

61

answers:

2

I have some XMLs that contain character hex codes, e.g. it like this:

<char hex="AB"/>

Now I want to xslt transform for display in the browser:

<xsl:value-of select="concat('&amp;#x', /char/@hex, ';', '')"/>

However, the output in the browser is &amp;#xAB; and not as I expected &#xAB; so the browser does not display the character for that code (which would be "«") but only the literal string "&#xAB;"

How can I get the xsl not to escape the ampersand?

A: 

I think your problem is larger than just the escaping, but how about the disable-output-escaping attribute?

<xsl:value-of disable-output-escaping="yes" select="concat('&amp;#x', /char/@hex, ';', '')"/>
MvanGeest
I have tried that, already, but it does not affect the output in any way. I am testing in firefox, btw.
tomhh
+1  A: 

This can be accomplished if you set the output method to text.

This transformation:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;
 <xsl:output method="text"/>

 <xsl:template match="char">
  <xsl:value-of select="concat('&amp;#x', /char/@hex, ';', '')"/>
 </xsl:template>
</xsl:stylesheet>

When applied on the provided XML document:

<char hex="AB"/>

produces the wanted result:

&#xAB;

Of course, with the text output method one needs to produce the individual characters of starting and ending tags (<xsl:copy>, <xsl:copy-of>, <xsl:element> and literal result elements do not produce any tags in this output method), but with some patience, everything is possible.

One could also use DOE (Disable Output Escaping), but this "feature" is not mandatory in the XSLT Spec. and some XSLT processors (including, I think, the one used by FF) don't implement DOE.

Probably the best solution (not using method="text") is the following:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:my="my:my" exclude-result-prefixes="my"
>
 <xsl:output omit-xml-declaration="yes" indent="yes" encoding="us-ascii"/>

 <my:hex>
  <code start="8">&#x80;&#x81;&#x82;&#x83;&#x84;&#x85;&#x86;&#x87;&#x88;&#x89;&#x8A;&#x8B;&#x8C;&#x8D;&#x8E;&#x8F;</code>
  <code start="9">&#x90;&#x91;&#x92;&#x93;&#x94;&#x95;&#x96;&#x97;&#x98;&#x99;&#x9A;&#x9B;&#x9C;&#x9D;&#x9E;&#x9F;</code>
  <code start="A">&#xA0;&#xA1;&#xA2;&#xA3;&#xA4;&#xA5;&#xA6;&#xA7;&#xA8;&#xA9;&#xAA;&#xAB;&#xAC;&#xAD;&#xAE;&#xAF;</code>
  <code start="B">&#xB0;&#xB1;&#xB2;&#xB3;&#xB4;&#xB5;&#xB6;&#xB7;&#xB8;&#xB9;&#xBA;&#xBB;&#xBC;&#xBD;&#xBE;&#xBF;</code>
  <code start="C">&#xC0;&#xC1;&#xC2;&#xC3;&#xC4;&#xC5;&#xC6;&#xC7;&#xC8;&#xC9;&#xCA;&#xCB;&#xCC;&#xCD;&#xCE;&#xCF;</code>
  <code start="D">&#xD0;&#xD1;&#xD2;&#xD3;&#xD4;&#xD5;&#xD6;&#xD7;&#xD8;&#xD9;&#xDA;&#xDB;&#xDC;&#xDD;&#xDE;&#xDF;</code>
  <code start="E">&#xE0;&#xE1;&#xE2;&#xE3;&#xE4;&#xE5;&#xE6;&#xE7;&#xE8;&#xE9;&#xEA;&#xEB;&#xEC;&#xED;&#xEE;&#xEF;</code>
  <code start="F">&#xF0;&#xF1;&#xF2;&#xF3;&#xF4;&#xF5;&#xF6;&#xF7;&#xF8;&#xF9;&#xFA;&#xFB;&#xFC;&#xFD;&#xFE;&#xFF;</code>
 </my:hex>

 <xsl:variable name="vHex" select="document('')/*/my:hex/*"/>

 <xsl:template match="char">
  <xsl:variable name="vchar1" select="substring(@hex,1,1)"/>
  <xsl:variable name="vchar2" select="substring(@hex,2,1)"/>

  <xsl:variable name="voffset">
   <xsl:choose>
     <xsl:when test="number($vchar2)">
        <xsl:value-of select="$vchar2"/>
     </xsl:when>
     <xsl:otherwise>
       <xsl:value-of select="count($vHex[@start = $vchar2]/preceding-sibling::*)+9"/>
     </xsl:otherwise>
   </xsl:choose>
  </xsl:variable>

  <xsl:value-of select="substring($vHex[@start=$vchar1], $voffset, 1)"/>
 </xsl:template>
</xsl:stylesheet>

When this transformation is applied on the provided XML document:

<char hex="AB"/>

the wanted result is produced:

&#171;

This assumes that the values of the hex attribute are hexadecimals in the range x80 to xFF. If it is necessary to have values in a wider range, such as x00 to XFF, more code elements need to be accordingly added to the my:hex element

Dimitre Novatchev