3

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

mwe.tex

\documentclass{article}

\begin{document}

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

Here is a number $326$.
\end{document}

and

mwe.cfg

% https://tex.stackexchange.com/questions/20218/how-to-make-htlatex-split-large-html-file-into-sub-documents
\Preamble{xhtml,mathml,html5}
% https://tex.stackexchange.com/questions/68916/convert-latex-to-mathjax-html/68962
\Configure{@HEAD}{\HCode{<script type="text/javascript"\Hnewline
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML"\Hnewline
></script>\Hnewline}}
\Configure{@HEAD}{\HCode{<style type="text/css">\Hnewline
  .MathJax_MathML {text-indent: 0;}\Hnewline
</style>\Hnewline}}
% arial font
\Css{body{font-family: Arial, Helvetica, sans-serif; font-size: 1.0em;}}
\begin{document}
\EndPreamble

and the following command

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

gives the following output:

mwe.html

<!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" 
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML" 
></script> 
<style type="text/css"> 
.MathJax_MathML {text-indent: 0;} 
</style> 
</head><body 
>
<!--l. 5--><p class="noindent" >Here is a function <!--l. 5--><math 
 xmlns="http://www.w3.org/1998/Math/MathML"  
display="inline" ><mi 
>f</mi><mrow ><mo 
class="MathClass-open">(</mo><mrow><mi 
>x</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 
 xmlns="http://www.w3.org/1998/Math/MathML"  
display="inline" ><mn>3</mn><mn>2</mn><mn>6</mn></math>.
</p> 
</body> 
</html>

The most important part of the output is

<mn>1</mn><mn>5</mn>

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

<mn>15</mn>

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. – David Carlisle Jan 31 '18 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 Jan 31 '18 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 Jan 31 '18 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. – David Carlisle Jan 31 '18 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 Jan 31 '18 at 20:03
4

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:

\textit{Příliš}

becomes:

<span 
class="ecti-1000">P</span><span 
class="ecti-1000">ř</span><span 
class="ecti-1000">í</span><span 
class="ecti-1000">li</span><span 
class="ecti-1000">š</span>

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 = {
  span=true,
  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.
  obj:traverse_elements(function(el)
    local get_name = function(curr) 
      return string.lower(curr:get_element_name())
    end
    local get_class = function(next_el)
      return next_el:get_attribute("class")
    end
    local is_span = function(next_el)
      return charclases[get_name(next_el)]
      -- return get_name(next_el) == "span"
    end

    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
      end
    end
    -- 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
            el:add_child_node(child)
          end
          -- remove the next element
          next_el:remove_node()
        end
        -- use the saved element as a next object
        next_el = real_next
      end
    end

  end)

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


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:

\documentclass{article}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}
\usepackage{siunitx}

\begin{document}

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}
\end{document}

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. – Ulrike Fischer Feb 1 '18 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 Feb 1 '18 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. – Ulrike Fischer Feb 1 '18 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. – Ulrike Fischer Feb 1 '18 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 Feb 1 '18 at 20:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.