# MathML Format XML in Lua

I have successfully loaded XML in LuaLaTeX. But how to load MathML. Any Lua Modules are available?

My LaTeX file:

\documentclass{article}
\usepackage{luacode}
\begin{luacode*}
xml = require('luaxml-mod-xml')
handler = require('luaxml-mod-handler')
\end{luacode*}
\begin{document}
\begin{luacode*}
sample = [[
<?xml version="1.0" encoding="utf-8"?>
<art>
<title>Scattering of flexural waves an electric current</title>
<para>Smart testing structures are components <math display="inline" overflow="scroll"><mrow><mi>G</mi><mo>&#x3d;</mo><mrow><mo stretchy="false">(</mo><mi>V</mi><mo>,</mo><mi>E</mi><mo stretchy="false">)</mo></mrow></mrow>[/itex] used in engineering applications that are capable of sensing or reacting to their environment in a predictable and desired manner. In addition to carrying mechanical loads, smart structures may alleviate vibration, reduce acoustic noise, change their mechanical properties as required or monitor their own condition.</para>
</art>
]]
XMLIn = handler.simpleTreeHandler()
x = xml.xmlParser(XMLIn)
x:parse(sample)
tex.sprint(XMLIn.root["art"]["title"])
tex.sprint(XMLIn.root["art"]["para"])
\end{luacode*}
\end{document}

• ConTeXt supports MathML, in case LuaLaTeX doesn't make the trick for you – user193767 Jun 8 at 17:10

The LuaXML library provides more high level library to process XML, luaxml-domobject. It can create DOM structure similar to HTML DOM in JavaScript.

I've created a simple library that can process XML you provided. It doesn't support full MathML, but it isn't hard to add support for additional elements. Here is the full code, process_xml.lua:

kpse.set_program_name "luatex"
local domobject = require "luaxml-domobject"

-- we need to define different actions for XML elements. The default action is
-- to just process child elements and return the result
local function default_action(element)
return process_children(element)
end

-- use template string to place the processed children
local function simple_content(s)
return function(element)
local content = process_children(element)
return string.format(s, content)
end
end

local function math_action(element)
local content = process_children(element)
local display = element:get_attribute("display") or "inline"
local template = "$%s$"
if display == "block" then template = "\n\$\n%s\n\$\n" end
return string.format(template, content)
end

local mathvariant_templates = {
normal = "\\mathrm{%s}",
identifier = "\\operatorname{%s}" -- this needs amsmath package
-- there are lot more, see https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mi
}

local function mi_action(element)
local content = process_children(element)
-- how should be <mi> rendered is based on the length.
-- one character should be rendered in italic, two and more characters
-- act like identifier like \sin
local implicit_mathvariant = utf8.len(content) > 1 and "identifier" or "italic"
-- the rendering can be also based on the mathvariant attribute
local mathvariant = element:get_attribute("mathvariant") or implicit_mathvariant
local template = mathvariant_templates[mathvariant] or "%s"
return string.format(template, content)

end

local function get_child_element(element, count)
-- return specified child element
local i = 0
for _, el in ipairs(element:get_children()) do
-- count elements
if el:is_element() then
-- return the desired numbered element
i = i + 1
if i == count then return el end
end
end
end

local function frac_action(element)
-- <mfrac> should have two children, we need to process them separatelly
local numerator = process_children(get_child_element(element, 1))
local denominator = process_children(get_child_element(element, 2))
return string.format("\\frac{%s}{%s}", numerator, denominator)
end

-- actions for particular elements
local actions = {
title = simple_content("\\section{%s}\n"),
para = simple_content("%s\n\\par"),
math = math_action,
mi = mi_action,
mfrac = frac_action, -- example of element that needs to process the children separatelly
-- here you can add more elements, like <mo> etc.
}

-- convert Unicode characters to TeX sequences
local unicodes = {
[960] = "\\pi{}"
}

local function process_text(text)
local t = {}
-- process all Unicode characters and find if they should be replaced
for _, char in utf8.codes(text) do
-- construct new string with replacements or original char
t[#t+1] = unicodes[char] or utf8.char(char)
end
return table.concat(t)
end

function process_children(element)
-- accumulate text from children elements
local t = {}
-- sometimes we may get text node
if type(element) ~= "table" then return element end
for i, elem in ipairs(element:get_children()) do
if elem:is_text() then
-- concat text
t[#t+1] = process_text(elem:get_text())
elseif elem:is_element() then
-- recursivelly process child elements
t[#t+1] = process_tree(elem)
end
end
return table.concat(t)
end

function process_tree(element)
-- find specific action for the element, or use the default action
local element_name = element:get_element_name()
local action = actions[element_name] or default_action
return action(element)
end

function parse_xml(content)
-- parse XML string and process it
local dom = domobject.parse(content)
-- start processing of DOM from the root element
-- return string with TeX content
return process_tree(dom:root_node())
end

function print_tex(content)
-- we need to replace "\n" characters with calls to tex.sprint
for s in content:gmatch("([^\n]*)") do
tex.sprint(s)
end
end

local M = {
parse_xml = parse_xml,
print_tex = print_tex
}

return M


It provides two main functions, parse_xml, which converts XML string to TeX string, and print_tex, which will print the TeX string to the document. You cannot use tex.sprint directly, because characters for newlines are not handled correctly.

You can configure three tables:

mathvariant_templates - this table provides configuration for <mi> elements mathvariant attributes. It should contain templates for string.format function. This is the default:

local mathvariant_templates = {
normal = "\\mathrm{%s}",
identifier = "\\operatorname{%s}" -- this needs amsmath package
-- there are lot more, see https://developer.mozilla.org/en-US/docs/Web/MathML/Element/mi
}


unicodes - Unicode codepoints of characters that should be replaced with LaTeX macros. XML entites will be replaced by Unicode by LuaXML, so you should place things like \pi etc. here. This is the default:

-- convert Unicode characters to TeX sequences
local unicodes = {
[960] = "\\pi{}"
}


The most important configuration is actions. This should handle elements. All contents of element are proceeded by default, so you need to configure only elements that you want to take a special action.

I've added few helper functions:

simple_content takes string.format template and replaces %s character with content of element's children.

More advanced functions like math_action or mi_action can decide what to do by analyzing of the content or element attributes.

Some elements take fixed number of child elements, like <mfrac>, which should have two children. We want to transfrom this to \frac macro, which takes two arguments. In this case, we need to process the two child elements separately. The frac_action function handles this. You will need similar functions for some other MathML elements that I didn't implement.

This is the default content of actions:

-- actions for particular elements
local actions = {
title = simple_content("\\section{%s}\n"),
para = simple_content("%s\n\\par"),
math = math_action,
mi = mi_action,
mfrac = frac_action, -- example of element that needs to process the children separatelly
-- here you can add more elements, like <mo> etc.
}


Here is a sample TeX file:

\documentclass{article}
\usepackage{amsmath}
\usepackage{luacode}
\begin{document}
\begin{luacode*}
local process_xml = require "process_xml"
sample = [[
<?xml version="1.0" encoding="utf-8"?>
<art>
<title>Scattering of flexural waves an electric current</title>
<para>Smart testing structures are components <math display="inline" overflow="scroll"><mrow><mi>G</mi><mo>&#x3d;</mo><mrow><mo stretchy="false">(</mo><mi>V</mi><mo>,</mo><mi>E</mi><mo stretchy="false">)</mo></mrow></mrow>[/itex] used in engineering applications that are capable of sensing or reacting to their environment in a predictable and desired manner. In addition to carrying mechanical loads, smart structures may alleviate vibration, reduce acoustic noise, change their mechanical properties as required or monitor their own condition.</para>
<para>
More examples: $<mi>sin</mi><mi>x</mi>$ or Pi: $<mi>&pi;</mi>$
</para>
<math display="block">
<mfrac><mi>a</mi><mi>b</mi></mfrac>
[/itex]
</art>
]]
process_xml.print_tex(process_xml.parse_xml(sample))
\end{luacode*}
\end{document}


It is rendered in this way:

• It's possible to load ConTeXT modules in Lua?. ConTeXT command \usemodule[mathml] – Balaji Jun 9 at 14:58
• @Balaji I don't have any experience with Context modules, but it shouldn't be problem. You will only need to provide Context commands in the templates. LaTeX commands are used in my example, which cannot work in Context. – michal.h21 Jun 9 at 19:09
• @Balaji I don't know anything about ConTeXt modules unfortunately. You may try to ask on ConTeXt mailing list, it is quite active. – michal.h21 Jun 11 at 10:53
• How to actions when using rece-date element in Lua? I have tried rece%-date and it's not working. Please advise or can i post separate question? – Balaji Jul 12 at 7:52
• @Balaji I am afraid that I don't understand what you mean be rece-date. Is it some custom XML element? – michal.h21 Jul 13 at 13:49