我已经成功加载了 XML LuaLaTeX
。但是如何加载MathML
。任何Lua 模块有空吗?
我的 LaTeX 文件:
\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>=</mo><mrow><mo stretchy="false">(</mo><mi>V</mi><mo>,</mo><mi>E</mi><mo stretchy="false">)</mo></mrow></mrow></math> 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}
答案1
该LuaXML
库提供了更多高级库来处理 XML,luaxml-domobject
它可以在 JavaScript 中创建类似于 HTML DOM 的 DOM 结构。
我创建了一个简单的库,可以处理您提供的 XML。它不支持完整的 MathML,但添加对其他元素的支持并不难。以下是完整代码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
它提供了两个主要函数,parse_xml
,将 XML 字符串转换为 TeX 字符串,以及print_tex
,将 TeX 字符串打印到文档中。您不能tex.sprint
直接使用,因为换行符无法正确处理。
您可以配置三个表:
mathvariant_templates
- 该表提供以下配置<mi>
元素mathvariant
属性。它应该包含函数模板string.format
。这是默认的:
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
- 应使用 LaTeX 宏替换的字符的 Unicode 代码点。LuaXML 将使用 Unicode 替换 XML 实体,因此您应该在此处放置 \pi 等内容。这是默认设置:
-- convert Unicode characters to TeX sequences
local unicodes = {
[960] = "\\pi{}"
}
最重要的配置是actions
。这将处理元素。默认情况下,元素的所有内容都会被处理,因此您只需配置要采取特殊操作的元素。
我添加了一些辅助函数:
simple_content
采用string.format
模板并%s
用元素子的内容替换字符。
更高级的功能如math_action
或mi_action
可以通过分析内容或元素属性来决定做什么。
有些元素有固定数量的子元素,例如<mfrac>
,它应该有两个子元素。我们希望将其转换为\frac
宏,它需要两个参数。在这种情况下,我们需要分别处理这两个子元素。函数frac_action
处理这个问题。对于我未实现的其他一些 MathML 元素,您将需要类似的函数。
这是的默认内容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.
}
以下是 TeX 文件示例:
\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>=</mo><mrow><mo stretchy="false">(</mo><mi>V</mi><mo>,</mo><mi>E</mi><mo stretchy="false">)</mo></mrow></mrow></math> 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: <math>
<mi>sin</mi><mi>x</mi>
</math> or Pi: <math><mi>π</mi></math>
</para>
<math display="block">
<mfrac><mi>a</mi><mi>b</mi></mfrac>
</math>
</art>
]]
process_xml.print_tex(process_xml.parse_xml(sample))
\end{luacode*}
\end{document}
它的渲染方式如下: