Is there a way to send colour commands within an <xsl:message> to the console (wt.exe) from Saxon XSLT?

56 Views Asked by At

I'm trying to add contextual colour to my <xsl:message> output when processing using a typical CMD/Bat file to launch the XSLT3.0 stylesheet in MS Windows.

After lots of failed attempts I discovered this tutorial that does change the colours of the cmd echo after a reg edit to Terminal

 [36mThis is blue[0m

I then tried to use the code above in a simple <xsl:message> and got the following error.

SXXP0003: Error reported by XML parser: An invalid XML character (Unicode: 0x1b) was found
  in the element content of the document.
org.xml.sax.SAXParseException; systemId: file:/C:/Temp/idr_migration/10year_Archive_Migration/xslt3_xml_to_josn.xsl; lineNumber: 49; columnNumber: 23; An invalid XML character (Unicode: 0x1b) was found in the element content of the document

Is there some special way to use a character map to convert this character so the XSLT will run and serialise the output to alert the CMD/Terminal to print the message in the desired colour?

Is this even possible to send colour codes within the <xsl:message> or are their other options to dictate the colour to the console?

2

There are 2 best solutions below

0
Martin Honnen On

Some Saxon user has achieved this for the VS Code XSLT extension (he is the author of that extension), the project is on Github https://github.com/pgfearo/alt-saxon-xslt-cli.

I have forked that project and used the branch for Saxon 12, built it using Maven, then, instead of running net.sf.saxon.Transform, I can run com.deltaxml.saxon.perf.AltTransform, ensuring that Saxon 12 and its libraries and the target\classes of the built Maven project are on the classpath, to run code like e.g.

<?xml version="1.1" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    expand-text="yes"
    exclude-result-prefixes="#all"
    version="3.0">
    
    <xsl:param name="color-map" as="map(xs:string, xs:string)"
        select="map { 'red' : '31m',
        'blue' : '34m',
        'black' : '30m',
        'green' : '32m',
        'yellow' : '33m',
        'magenta' : '35m',
        'cyan' : '36m'
        }"/>
    
    <xsl:output method="text"/>
    
    <xsl:template match="red | blue | black | green | yellow | magenta | cyan"><xsl:message>&#27;[{$color-map(local-name())}{.}&#27;[39;49m</xsl:message>&#27;[{$color-map(local-name())}{.}&#27;[39;49m</xsl:template>
    
</xsl:stylesheet>

on some sample input like e.g.

<?xml version="1.0" encoding="UTF-8"?>
<root><red>This is red text.</red>This is standard text.<blue>This is blue text.</blue></root>

to get coloured output (for both the text output of the stylesheet (mainly as I had a stylesheet doing that) as well as for the xsl:message output):

enter image description here

So basically the control codes work with output method text for the result document or for xsl:message with that specialized message listener of Phil's project that simply strips any markup and outputs the text content of the message.

0
Michael Kay On

The ASCII control character x1B (ESC) is not a legal character in XML 1.0, so it can't appear literally in your stylesheet under XML 1.0. If you have an XML 1.1 parser, you can write it as &#x1B; - you will need to add an XML declaration with version="1.1" in the stylesheet header, and to enable XML 1.1 with a configuration option in Saxon.

I don't think that disable-output-escaping is likely to solve the problem - at any rate, I've never tried it. Ditto for character maps.

You should be able to generate the character in a string (and therefore in a message) by using the function codepoints-to-string(27), but unfortunately messages are serialized using the XML serializer which will try to convert this to &#x1B;.

I think my instinct would probably be to write a processing instruction such as <?ESC?> into the message, and then intercept it and format it in a MessageListener. Whatever approach you choose, I think you're probably going to have to write a bit of Java customisation code.