I'm using htlatex to produce screen-readable (https://www.nvaccess.org/) MathML. Using the following file




Here is a function $f(x)=15$.

Here is a number $326$.



% https://tex.stackexchange.com/questions/20218/how-to-make-htlatex-split-large-html-file-into-sub-documents
% https://tex.stackexchange.com/questions/68916/convert-latex-to-mathjax-html/68962
\Configure{@HEAD}{\HCode{<script type="text/javascript"\Hnewline
\Configure{@HEAD}{\HCode{<style type="text/css">\Hnewline
  .MathJax_MathML {text-indent: 0;}\Hnewline
% arial font
\Css{body{font-family: Arial, Helvetica, sans-serif; font-size: 1.0em;}}

and the following command

htlatex.exe mwe.tex "mwe.cfg, charset=utf-8" " -cunihtf -utf8"

gives the following output:


<!DOCTYPE html> 
<html lang="en-US" xml:lang="en-US" > 
<head> <title></title> 
<meta  charset="utf-8" /> 
<meta name="generator" content="TeX4ht (http://www.tug.org/tex4ht/)" /> 
<link rel="stylesheet" type="text/css" href="mwe.css" /> 
<script type="text/javascript" 
<style type="text/css"> 
.MathJax_MathML {text-indent: 0;} 
<!--l. 5--><p class="noindent" >Here is a function <!--l. 5--><math 
display="inline" ><mi 
>f</mi><mrow ><mo 
class="MathClass-close">)</mo></mrow> <mo 
class="MathClass-rel">=</mo> <mn>1</mn><mn>5</mn></math>.
</p><!--l. 7--><p class="indent" >   Here is a number <!--l. 7--><math 
display="inline" ><mn>3</mn><mn>2</mn><mn>6</mn></math>.

The most important part of the output is


When read with NVDA (and the MathPlayer plugin https://www.dessci.com/en/products/mathplayer/ installed) the file is read as:

Here is a function f of x equals one five dot. Here is a number three two six.

This is not optimal; if I tweak the html so that it has


then the output is read as I would like:

Here is a function f of x equals fifteen dot.

How can I tweak the call to htlatex so that the MathML outputs <mn>15</mn> instead of <mn>1</mn><mn>5</mn>?

  • 2
    if configuring tex4ht proves tricky you could run the output through sed -i -e 's@</mn><mn>@@g' to merge them before serving the html. Commented Jan 31, 2018 at 14:38
  • @DavidCarlisle yes, indeed, post processing (using sed or perl) is my back up, but I wondered if a 'native' solution is available
    – cmhughes
    Commented Jan 31, 2018 at 14:46
  • I am afraid that there is no native solution. I need to dive into tex4ht sources and hope to find something. But I suspect that this error is caused by a bug in tex4ht command, which is known and no one found a fix yet.
    – michal.h21
    Commented Jan 31, 2018 at 17:28
  • an alternative to post processing would be to use (any) markup such as \num{123} for multiple-digit numbers, then you could set a tex4ht config for \num that did the right thing. Commented Jan 31, 2018 at 19:58
  • Yes, indeed, I can see that could work for some use cases, but for my current batch, the sed/perl option looks like it will be best
    – cmhughes
    Commented Jan 31, 2018 at 20:03

1 Answer 1


Edit 2:

The updated LuaXML library is on CTAN and in TL, so it is no longer necessary to update it manually. I also added mechanism for filters that modify the DOM to make4ht. Basic DOM filters can be requested using common_domfilters extension in the development version of make4ht:

 make4ht -uc mwe.cfg -f html5+common_domfilters mwe.tex

Edit 1:

We found that tex4ht contains postprocessing script that handles exactly the numbers in MathML. It can be requested using:

htlatex.exe mwe.tex "mwe,charset=utf-8" " -cunihtf -utf8" " -cxhtmml"

if you want to use htlatex. make4ht equivalent is:

make4ht -uc mwe.cfg mwe.tex "" "" "-cxhtmml"

It have some issues, because it produces invalid HTML5, because it saves end tags for void elements such as <meta> or <link> and it converts utf8 characters to HTML entites. But it proves that original tex4ht author, Eitan Gurari knew about this issue and his solution was to use a post-processing. So I will add some Lua filters for common HTML problems fixing to an upcoming make4ht release.

Original answer:

This issue is caused by a bug in the tex4ht DVI processor. It can add some markup for text that use different font than the main font used in the document. Because of this, it can support such cases:

hello {\bfseries world}

The previous code cannot be supported on the TeX macro level, the markup must be added by the DVI processor. This is the result:

Hello <span class='ecbx-1000'>world</span>

The CSS file contains instruction to render <span class='ecbx-1000'> as a bold text. The issue is that if it contains for example some accented letters, it will create span elements for each accented letter:




Because a similar mechanism is used for rendering of the math numbers, you get the separated numbers. All of these issues should be fixed in the sources of tex4ht DVI processor, but I don!t think that it will happen any time soon.

As a workaround, it is possible to use make4ht build file. It is a Lua script that drives the modern tex4ht compilation process. The development version of the LuaXML library (it is not on CTAN yet) provides nice DOM object, which can be used for cleanup of the HTML file.

Save the following code as mybuild.mk4:

local filter = require "make4ht-filter"
local dom    = require "luaxml-domobject"

-- elements which can be joined
local charclases = {
  mn = true

local function dom_process(s)
  local obj = dom.parse(s)
  -- join adjanced span and similar elements inserted by 
  -- tex4ht to just one object.
    local get_name = function(curr) 
      return string.lower(curr:get_element_name())
    local get_class = function(next_el)
      return next_el:get_attribute("class")
    local is_span = function(next_el)
      return charclases[get_name(next_el)]
      -- return get_name(next_el) == "span"

    local function get_next(curr, class)
      local next_el = curr:get_next_node()
      if next_el and next_el:is_element() and is_span(next_el) then
        return next_el
    -- loop over all elements and test if the current element is in a list of
    -- processed elements (charclasses)
    if is_span(el) then
      local next_el = get_next(el)
      -- loop over the following elements and test whether they are of the same type
      -- as the current one
      while  next_el do
        -- save the next element because we will remove it later
        local real_next = get_next(next_el)
        if get_name(el) == get_name(next_el) and get_class(el) == get_class(next_el) then
          -- it the following element match, copy it's children to the current element
          for _, child in ipairs(next_el:get_children()) do
          -- remove the next element
        -- use the saved element as a next object
        next_el = real_next


  -- serialize the DOM object back to HTML
  return obj:serialize()

local process = filter {dom_process}
Make:match("html$", process)

The document can be compiled using

make4ht -uc mwe.cfg -e mybuild.mk4 mwe.tex

A slightly expanded example:



Here is a function $f(x)=15$.

Here is a number $326$. Longer text: $\mbox{hello}$

\textit{Příliš žluťoučký}

Hello {\bfseries world}

Produces the following HTML:

<!-- l. 8 --><p class='noindent'>Here is a function <!-- l. 8 --><math xmlns='http://www.w3.org/1998/Math/MathML' display='inline'><mi>f</mi><mo class='MathClass-open'>(</mo><mi>x</mi><mo class='MathClass-close'>)</mo> <mo class='MathClass-rel'>=</mo> <mn>15</mn></math>.
</p><!-- l. 10 --><p class='indent'>   Here is a number <!-- l. 10 --><math xmlns='http://www.w3.org/1998/Math/MathML' display='inline'><mn>326</mn></math>.
Longer text: <!-- l. 10 --><math xmlns='http://www.w3.org/1998/Math/MathML' display='inline'><mstyle class='mbox'><mtext>hello</mtext></mstyle></math>
</p><!-- l. 12 --><p class='indent'>   <span class='ecti-1000'>Příliš</span> <span class='ecti-1000'>žluťoučký</span>
</p><!-- l. 14 --><p class='indent'>   Hello <span class='ecbx-1000'>world</span> </p> 
  • I'm not so sure if I would call it a bug in the dvi processor. When inputenc is loaded and so the non-ascii are active then the dvi contains some sort of grouping around the chars ('t4ht@[, imho added in this case by the accent configuration in unicode.4ht), and in the case of math the configuration is geared towards single symbols -- which is quite logical with the exception of numbers. Commented Feb 1, 2018 at 10:15
  • @UlrikeFischer the numbers are tied together in the DVI file. the configuration for numbers is this: \Configure{MathClass}{7}{*}{}{} {0123456789}. It inserts some template to the DVI file, which is then used for the numbers. So I guess that it must be fixed somewhere in the DVI processor, but I have no idea where :/
    – michal.h21
    Commented Feb 1, 2018 at 16:45
  • Yes the number are tied together in the dvi. But if you do $xyz=134$ then xyz is tied together too and then splitted up with <mi>x</mi>. For xyz this is the wanted and expected behaviour! You want that the postprocessor handles them as single symbols. How should it know that numbers are different? Every digit is an individual token here, there is no assignment involve that looks forwards for other digits. Commented Feb 1, 2018 at 17:38
  • That's why I asked in the chat if you know how to get the correct result if the number is marked up e.g. as \num{123,45}. If yes one could perhaps make the numbers active in math and add the markup automatically. Commented Feb 1, 2018 at 17:54
  • @UlrikeFischer it is possible to create command similar to this: \newcommand\mynum[1]{\PauseMathClass\HCode{<mn>}#1\HCode{</mn>}\EndPauseMathClass}. It disables the DVI processing code and inserts the <mn> element directly.
    – michal.h21
    Commented Feb 1, 2018 at 20:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .