Search code examples
xmlxsltdocbook

DocBook 5, add (MathML) namespace to HTML output?


I'm typing a book with some math formulas written in MathML. The book has a "main" XML file which includes all the chapter files like this:

<?xml version="1.0" encoding="utf-8"?>
<book xmlns="http://docbook.org/ns/docbook"
      xmlns:xi="http://www.w3.org/2001/XInclude"
      version="5.1"
      xml:lang="en">
  <title>Some title</title>
  <xi:include href="intro.xml"/>
</book>

And intro.xml goes as

<?xml version="1.0" encoding="utf-8"?>
<chapter xml:id="ch-intro" xmlns:m="http://www.w3.org/1998/Math/MathML">
  <title>Introduction</title>
  <para>Some text
  <inlineequation>
    <m:math><m:msqrt><m:mi>a</m:mi></m:msqrt></m:math>
  </inlineequation>
  Some other text.
  </para>
</chapter>

This produces something like

<p>Some text
<m:math xmlns:m="http://www.w3.org/1998/Math/MathML">
  <m:msqrt><m:mi>a</m:mi></m:msqrt>
</m:math>
Some other text.</p>

I have a customization layer XSLT on top of the HTML XSLT from Docbook-XSL to load MathJax:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:m="http://www.w3.org/1998/Math/MathML"
                version="1.0">
  <xsl:import href="docbook-xsl-nons-snapshot/html/docbook.xsl"/>
  <!-- Add MathJax <script> tags to document <head> -->
  <xsl:template name="user.head.content">
    <script type="text/javascript" async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=MML_CHTML"></script>
  </xsl:template>
</xsl:stylesheet>

And this works in the sense that it does add the <script> tag to <head>, but MathJax doesn’t render the formula, because it doesn’t work when the MathML namespace is on <math> itself. The namespace needs to go to <html>.

So my question is, how should I write the XSLT customization layer to add xmlns:m="http://www.w3.org/1998/Math/MathML" to the generated <html> tag?


Solution

  • What happens if you override the template below by putting it into your main stylesheet module:

    <xsl:template match="*" mode="process.root">
      <xsl:variable name="doc" select="self::*"/>
    
      <xsl:call-template name="user.preroot"/>
      <xsl:call-template name="root.messages"/>
    
      <html>
        <xsl:call-template name="root.attributes"/>
        <head>
          <xsl:call-template name="system.head.content">
            <xsl:with-param name="node" select="$doc"/>
          </xsl:call-template>
          <xsl:call-template name="head.content">
            <xsl:with-param name="node" select="$doc"/>
          </xsl:call-template>
          <xsl:call-template name="user.head.content">
            <xsl:with-param name="node" select="$doc"/>
          </xsl:call-template>
        </head>
        <body>
          <xsl:call-template name="body.attributes"/>
          <xsl:call-template name="user.header.content">
            <xsl:with-param name="node" select="$doc"/>
          </xsl:call-template>
          <xsl:apply-templates select="."/>
          <xsl:call-template name="user.footer.content">
            <xsl:with-param name="node" select="$doc"/>
          </xsl:call-template>
        </body>
      </html>
      <xsl:value-of select="$html.append"/>
    
      <!-- Generate any css files only once, not once per chunk -->
      <xsl:call-template name="generate.css.files"/>
    </xsl:template>
    

    Given that that module has the MathML namespace declaration I would expect that the generated root element has it too.