VS Code syntax highlighting for XML containing javascript

Viewed 381

Edit - Solution:

I took some inspiration from @Tomalak solution. However, instead of using XSLT I used the VS Code replace regex expressions to comment out my XML code:

<!-- comment out xml tags : ^(\s*(\]\]>)?<\/?\w*>(<!\[CDATA\[)?)\s*$ --> 
<!-- comment out xml tags : //$1 --> 
<!-- uncomment xml tags   : ^\/\/(\s*(\]\]>)?<\/?\w*>(<!\[CDATA\[)?)\s*$ --> 
<!-- uncomment xml tags   : $1 --> 

Using $1 will give you the capture group. I'm just capturing all XML tags and adding the // characters to make them a comment.

From there I just set the syntax highlighting of the file to JavaScript and everything worked flawlessly.

I only need to do this once in a while, so this quick hack will work fine for me. However a more sophisticated solution such as an XSLT template might be better for more active projects.

Problem

I have an XML file containing javascript (Due to constraints of the platform we are using.) My code looks like this:

<JS>
  <MY_FUNCTION><![CDATA[
// comment here
let my_function = () => console.log("Hello World");
  ]]></MY_FUNCTION>
  <LESS_THAN><![CDATA[
let less_than = (a,b) => a < b;
  ]]></LESS_THAN>
  <GREATER_THAN><![CDATA[
let greater_than = (a,b) => a > b;
  ]]></GREATER_THAN>
</JS>

Being that my file is XML I'm not getting syntax highlighting for the javascript. So my code is just grey, similar to how comments look.

Is there an extension that could highlight my code? I'd also be willing to modify the highlighting rules if that would help me.

1 Answers

You could turn the problem around. This XSLT template transforms your XML to JS code

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

    <xsl:template match="*[normalize-space(text()[1])]">
        <xsl:value-of select="concat('//xml:&lt;', name(), '&gt;&lt;![CDATA[')" />
        <xsl:apply-templates select="node() | *" />
        <xsl:value-of select="concat('//xml:]]&gt;&lt;/', name(), '&gt;')" />
    </xsl:template>
    
    <xsl:template match="*">
        <xsl:value-of select="concat('//xml:&lt;', name(), '&gt;')" />
        <xsl:apply-templates select="node() | *" />
        <xsl:value-of select="concat('//xml:&lt;/', name(), '&gt;')" />
    </xsl:template>
</xsl:stylesheet>

produces this:

//xml:<JS>
  //xml:<MY_FUNCTION><![CDATA[
// comment here
let my_function = () => console.log("Hello World");
  //xml:]]></MY_FUNCTION>
  //xml:<LESS_THAN><![CDATA[
let less_than = (a,b) => a < b;
  //xml:]]></LESS_THAN>
  //xml:<GREATER_THAN><![CDATA[
let greater_than = (a,b) => a > b;
  //xml:]]></GREATER_THAN>
//xml:</JS>

Now syntax highlighting can work according to JS rules.

Using XSLT is not strictly necessary, you could probably get away with a half-way clever regex replace, something like ^(\s*)(<|\]\]>) replaced with \1//xml:\2, assuming that XML tags always are on their own lines.

You can convert it all back to XML by removing the //xml: with a simple search and replace operation, as long as you leave the //xml: comments intact.

Doing that would put us back to:

<JS>
  <MY_FUNCTION><![CDATA[
// comment here
let my_function = () => console.log("Hello World");
  ]]></MY_FUNCTION>
  <LESS_THAN><![CDATA[
let less_than = (a,b) => a < b;
  ]]></LESS_THAN>
  <GREATER_THAN><![CDATA[
let greater_than = (a,b) => a > b;
  ]]></GREATER_THAN>
</JS>
Related