A CALS Table Viewer for Visual Studio Code

June 23, 2022

Phil Fearon

CALS Tables (see ‘What are CALS Tables?’, below) are not easy to understand by looking at their XML source. At DeltaXML we have lots of CALS tables in our regression tests which we need to quickly visualise, especially if we need to understand exactly what went wrong in a failing test. These tables are embedded in a variety of source formats: DocBook, DITA, S1000D etc., and will often have DeltaXML change markup included in the table. We needed a quick way of visualising CALS tables from our test suite and so I used my ‘free sprint' time to write an XSLT-driven Visual Studio Code extension to do just that. We found it sped up our testing reviews significantly and we share it here in the hope that you will also find it a useful approach to viewing tables.
VSCode screenshot
VS Code screenshot of CALS Table Viewer in ‘File (append)’ mode

What are CALS Tables?

The CALS table model is a standard way of representing tabular information in XML. Originally developed for SGML, the XML standard is now published by OASIS [ OASIS - Specs/Documents - Table Models ]. The purpose of the CALS table model is to facilitate table interchange between different tools with a standard way of representing and rendering tables in XML. The CALS table model is included in many other XML standards such as DocBook, DITA, S1000D and JATS.

Background: CALS Table Research Project

When working with our research team at DeltaXML a while back, I was routinely working with sets of XML files containing CALS tables. These files comprised: inputs for tests, the expected results for tests and the actual results from tests.

Our research team quickly accumulated test resources comprising a few hundred files. Input files typically contain a single CALS table. The result file is a ‘diff’ of two (or more) input files, holding the CALS table plus annotations describing differences between the inputs.

To work effectively with these files, we needed to render the XML as regular tables with colour highlighting describing the differences. For this, we developed XSLT to render CALS tables in the XML as HTML that could be opened in any browser.

Requirement: An XSLT-Driven File Viewer

From the CALS Table project, we now had XSLT that could render CALS tables in our XML files as HTML, but how could we flexibly render our XML files just at the moment we needed to? Moreover, we often needed to view several XML files at the same time, this could be a whole directory of files, or just a handful of related files. Related files might, for example, be different comparison results using the same inputs but achieved with different comparator settings.

So, our team needed a file explorer with a CALS table preview, but with extra features so we could efficiently preview more than one file at a time. There was also an aspiration that such a tool could also be useful for our customers. Perhaps to help assess how effective our new CALS table comparison feature fairs was when working with their customer-specific input files.

A ‘Free-Sprint’ Proposal

At DeltaXML, developers follow the Scrum Agile methodology, working in two-week sprints. Every six sprints we have a five-day ‘free sprint’, where we present the work we have done on the fifth day. My proposal for the free-sprint was to develop a solution for our CALS table research ‘file explorer problem’.

I decided to develop this solution as a Visual Studio Code extension that could be completed within the allowed four days. I chose Visual Studio Code as this is a popular free editor and I’m familiar with the extension API and publishing mechanism.

Free-sprints give us the opportunity to explore new technologies or explore new ways of combining existing technologies. The knowledge gained in a free-sprint helps drive future research and development. In this case the idea was to assess how Saxonica’s SaxonJS XSLT processor and Visual Studio Code could work together seamlessly to solve general XML visualisation problems.

Implementation: An XSLT-Driven Renderer for VS Code WebView

I’ve outlined here how this project was implemented, more detail can be found in the source code on the project’s Github Repository:

The VS Code WebView

Visual Studio Code provides a ‘WebView’ feature, accessed via its extension API. The WebView is effectively a Chrome browser environment with features to interface the WebView with the VS Code ‘host’ in a secure way.

When a WebView is first created by VS code, the HTML and all JavaScript required for the WebView must be loaded. SaxonJS is an XSLT 3.0 processor, coded as a JavaScript library and along with JavaScript and NodeJS APIs.

Note that, in this case, the JavaScript API is preferred to the NodeJS API as it provides potential for dynamic rendering and avoids the need for the end-user to install any other libraries like NodeJS (SaxonJS is deployed inside the extension).

When initialised, the WebView loads the SaxonJS library, a small JavaScript file, main.js and the compiled XSLT in the form of a ‘SEF’ JSON file.

The main.js script listens for ‘update’ JSON messages from VS Code and converts them into transform calls on the SaxonJS API. The XSLT is compiled as part of the extension build using SaxonJS’s NodeJS command-line interface.

TypeScript code running within the VS Code extension host is responsible for initialising the WebView and sending/receiving messages to and from the WebView.

Using SaxonJS Interactive extensions for XSLT

SaxonJS provides extensions to XSLT that give extra integration with the host browser environment. The XSLT used in this project exploits these extensions in two ways:

  1. The xsl:result-document instruction can use a special href attribute value to identify just a specific element in the HTML that is updated. The method attribute controls whether content is replaced or appended to.
  2. The JavaScript scrollIntoView function is invoked from within the XSLT so the WebView scrolls to the right position to show appended content.

Web Security

A ‘Content Security Policy’ is declared in the loaded HTML to prevent any scripts embedded within XML from being run unintentionally. VS Code also prevents even the pre-existing JavaScript from accessing any file resources other than those declared (file contents is passed in the ‘update’ JSON message to the WebView).

VSCode install screenshot
VS Code Screenshot of the extension’s installation page

Using the VS Code Extension

This project has now been published, complete with some extra ‘polishing’ added to the original free-sprint work. The extension is available for installation from the Visual Studio Code MarketPlace here. This adds to DeltaXML’s other VS Code extensions.

The CALS Table Viewer extension is simple to use: Once the extension has been installed, the following commands are available in the Command Palette (⇧⌘P):

  • CALS Viewer: File (replace) - view always shows a rendering for the currently selected
  • CALS Viewer: File (append) - rendering of each selected file is appended to the view
  • CALS Viewer: Directory - all files in the same directory as the selected are rendered in the view

When multiple files are shown in the view, a filename header is shown for each file in the view. If files are not well-formed XML, a message to that effect is shown.

UsingCALS Tables with DeltaV2 markup samples

To help try out this extension, some samples files are included in the cals-tables-samples directory of the project repository.


The main goal of this modest, limited-scope project is now complete. The CALS Table Viewer is now ready to help (while our CALS Table comparator is developed further) maintain our growing test suite comprising XML files with embedded CALS Tables.

This project however, had a secondary goal: to provide a foundation for a more general purpose XSLT-driven file explorer in Visual Studio Code. Hopefully, this goal has also been met, but proof for this awaits further related applications being developed on this platform in the future.

DeltaXML invite you to try out this tool and contact us if you have any questions or suggestions.