HOWTO: Modify Virtuoso default /sparql endpoint Form page using XSLT

HOWTO: Modify Virtuoso default /sparql endpoint Form page using XSLT

Overview

This document serves as a quick primer in using XSLT to re-style/modify/customize the Virtuoso default /sparql endpoint Form page:

The steps are as follow:

  1. Upload the replacement XSLT to a web (Virtuoso WebDAV) or file system (vsp folder) or other accessible location.

  2. Use the Virtuoso registry_set() function to register the replacement XSLT file with the special sparql_endpoint_xsl registry key as follows:

     registry_set('sparql_endpoint_xsl','http://localhost:8889/DAV/home/dba/sparql_endpoint.xslt');
    
  3. Reload the Virtuoso /sparql endpoint to see the effects of the change.

Note: you may have to run xslt_stale('http://localhost:8889/DAV/home/dba/sparql_endpoint.xslt'); (or restart the server) to force an HTTP cache refresh to see the effects of any changes made to the XSLT file.

The registry_remove() function can be used to remove the sparql_endpoint_xsl registry setting and revert back to the default built-in /sparql endpoint Form page Virtuoso ships with as follows:

registry_remove('sparql_endpoint_xsl');

The XSLT file can also be placed on the file system, in a directory that is included in the dirsallowed INI setting (such as the vsp folder), and specified with a file: scheme URI as follows:

registry_set('sparql_endpoint_xsl','file:///sparql_endpoint.xslt')

Sample XSLT

Below is sample source for sparql_endpoint.xslt which replaces the <h1> tag text Virtuoso SPARQL Query Editor of the /sparql endpoint Form page with the text Something Else ... to show how this can be done:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:fn2="http://www.w3.org/2004/07/xpath-functions" 
xmlns:xhtml="http://www.w3.org/1999/xhtml" 
version="1.0" exclude-result-prefixes="xsl fn2 xhtml">

  <xsl:output method="xhtml" 
doctype-public="-//W3C//DTD XHTML+RDFa 1.0//EN" 
doctype-system="http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd" 
indent="yes"/>

  <xsl:template match="/">
    <xsl:apply-templates mode="copy"/>
  </xsl:template>

  <!-- intercept first heading -->
  <xsl:template match="//h1[1]" mode="copy">
    <h1>Something Else...</h1>
  </xsl:template>

  <!-- couple of templates for implementing a passthroguh -->
  <xsl:template match="*" mode="copy">
    <xsl:element name="{local-name(.)}">
      <xsl:apply-templates select="@*" mode="copyattr"/>
      <xsl:apply-templates mode="copy"/>
    </xsl:element>
  </xsl:template>

  <xsl:template match="comment()" mode="copy" priority="10">
    <xsl:copy-of select="."/>
  </xsl:template>

  <xsl:template match="@*" mode="copyattr">
    <xsl:attribute name="{local-name(.)}">
      <xsl:value-of select="."/>
    </xsl:attribute>
  </xsl:template>

</xsl:stylesheet>

For which the resultant form page with the <h1> tag change would be:

Work-through

  • The fundamental paradigm with the XSLT is whether to pass-through or intercept the incoming element stream.
  • The last two templates match all HTML elements and attributes, recreating elements and attributes of the same names and values; this acts as a fallback.
  • The intercept template identifies the first heading h1 element and emits its own content instead.
  • Note the use of mode="copy" throughout, both throwing and matching templates.

Possible Ideas

To inject styles or javascript in the header, you can add a template like:

<xsl:template match="head" mode="copy">
  <xsl:apply-templates mode="copy" />
  <link rel="stylesheet" href="mystyle.css" />
  <script type="text/javascript">
    function irksome() {
      alert("annoying, isn't it?");
    };
  </script>
</xsl:template>

To invoke the new JS from the bottom of the HTML body:

<xsl:template match="body" mode="copy">
  <xsl:apply-templates mode="copy" />
  <script type="text/javascript">
     irksome();
  </script>
</xsl:template>

Explanations

In both cases we intercept the head or body element respectively, let the passthrough copy all the child elements, and finally, at the end, emit our own new code. This forms the basis for incremental development above the existing SPARQL endpoint appearance.