Search code examples
xsltcolorsconsolexml-parsingansi-escape

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


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?


Solution

  • 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.