Gimmacus
Gimmacus

Reputation: 53

Why doesn't my SVG display when I try to use the XSLT output method "html"?

Apologies if this is a simple question as I'm fairly novice at XSLT. I'm having an issue where the SVG image I'm generating in XSLT won't display if my output method is set to html. If I open the desired xml file, transform it, and view it in browser (IE v11), the whole document loads with exception to the SVG image itself. In IE, if I right click the document and select "view source" I can see the SVG information sitting there, right where its expected to be.

If I set the output method to xml and open in IE, the SVG images do appear but the document structure isn't there (but to reiterate: the goal is to output in html as it's used in other processes further down the line)

Below is a snippet of a small, simple testing XSLT and the post transformation xml seen from "view source" (leaving out unrelated stuff). I'm trying to get this working on a small scale before I tackle the larger picture.

Also to note, the svg:text tag does display the text mentioned, although it seems more like a simple text entry than part of an image.

For those familiar with it, the majority of functionality comes from RenderX's XSLT barcode generator.

XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
  xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">

  <xsl:import href="code128.xsl"/>

  <xsl:output method='html' media-type="image/svg" encoding='UTF-8' indent='yes'/>

  <xsl:template match="/">
    <html lang="en">
      <head>
        <title>SVG bar code examples</title>
      </head>
      <body>
        <h1>SVG bar code examples</h1>
        <ul>
          <xsl:apply-templates select="//barcode"/>
        </ul>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="barcode">
    <li>
      <xsl:call-template name="barcode-code128">
      .
      <!--Parameters here-->
      .
      </xsl:call-template>
    </li>
  </xsl:template>
</xsl:stylesheet>

Post Transformation XML:

<?xml version="1.0" encoding="utf-8"?>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:svg="http://www.w3.org/2000/svg">
  <head>
    <title>SVG bar code examples</title>
  </head>
  <body>
    <h1>SVG bar code examples</h1>
    <ul>
      <li>
        <svg:svg width="29.494444444444443mm" height="12.7mm" viewBox="0 0 10618 4572">
          <svg:path d="M 686 686 l 0 2286 138 0 0 -2286 z m ..."(truncated due to length)>
          <svg:text x="6068" y="4420" text-anchor="middle" font-family=...
        </svg:svg>
      </li>
      .
      <!--More SVG images here-->
      .
    </ul>
  </body>
</html>

Upvotes: 0

Views: 416

Answers (1)

Martin Honnen
Martin Honnen

Reputation: 167461

If you want to use the output method html then you should use HTML syntax and neither HTML 4 nor HTML5 or what is simply called HTML now supports namespaces, in particular not prefixed element names. So for your SVG elements to be recognized in text/html you need simply svg, path and text as the element names without any prefix, the only allowed "namespace" declaration would be xmlns="http://www.w3.org/2000/svg" on the svg element.

I am also not sure about IE's SVG support, perhaps it is only enabled in standards compliant rendering mode, meaning, for method="html" it is recommended to have <xsl:output method="html" indent="yes" version="5" doctype-system="about:legacy-doctype"/>, as that doctype-system is supposed to set older browsers distinguishing between quirks mode and standard compliant mode to the latter mode.

If your used library creates prefixed elements then you would need to run them through an additional transformation step to strip the namespace prefix which, in a single transformation, is in XSLT 1 only possible using a proprietary extension function to convert a result tree fragment into a node-set:

  <xsl:template match="barcode">
    <li>
      <xsl:variable name="barcode-rtf">
      <xsl:call-template name="barcode-code128">
      .
      <!--Parameters here-->
      .
      </xsl:call-template>
      </xsl:variable>
      <xsl:apply-templates select="msxml:node-set($barcode-rtf)/node()" xmlns:msxml="urn:schemas-microsoft-com:xslt" mode="strip-svg-prefix"/>
    </li>
  </xsl:template>


  <xsl:template match="@* | node()" mode="strip-svg-prefix">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" mode="strip-svg-prefix"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="svg:*" mode="strip-svg-prefix" xmlns:svg="http://www.w3.org/2000/svg">
    <xsl:element name="{local-name()}" namespace="http://www.w3.org/2000/svg">
      <xsl:apply-templates select="@* | node()" mode="strip-svg-prefix"/>
    </xsl:copy>
  </xsl:template>

Note that, for text/html and HTML 4 or HTML5 as the transformation target with method="html", I would recommend to use no namespace at all for the HTML elements, i.e. to remove the XHTML namespace declaration you have. Otherwise serialization of empty elements might not give the proper HTML syntax.

Upvotes: 1

Related Questions