summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/luaxml
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/luatex/generic/luaxml
Initial commit
Diffstat (limited to 'macros/luatex/generic/luaxml')
-rw-r--r--macros/luatex/generic/luaxml/README37
-rw-r--r--macros/luatex/generic/luaxml/luaxml-cssquery.lua276
-rw-r--r--macros/luatex/generic/luaxml/luaxml-domobject.lua529
-rw-r--r--macros/luatex/generic/luaxml/luaxml-entities.lua37
-rw-r--r--macros/luatex/generic/luaxml/luaxml-mod-handler.lua359
-rw-r--r--macros/luatex/generic/luaxml/luaxml-mod-xml.lua565
-rw-r--r--macros/luatex/generic/luaxml/luaxml-namedentities.lua2233
-rw-r--r--macros/luatex/generic/luaxml/luaxml-parse-query.lua46
-rw-r--r--macros/luatex/generic/luaxml/luaxml-pretty.lua89
-rw-r--r--macros/luatex/generic/luaxml/luaxml-stack.lua67
-rw-r--r--macros/luatex/generic/luaxml/luaxml-testxml.lua147
-rw-r--r--macros/luatex/generic/luaxml/luaxml.pdfbin0 -> 98455 bytes
-rw-r--r--macros/luatex/generic/luaxml/luaxml.tex749
13 files changed, 5134 insertions, 0 deletions
diff --git a/macros/luatex/generic/luaxml/README b/macros/luatex/generic/luaxml/README
new file mode 100644
index 0000000000..317a60671f
--- /dev/null
+++ b/macros/luatex/generic/luaxml/README
@@ -0,0 +1,37 @@
+Introduction
+============
+
+LuaXML is pure lua library for reading and serializing of the XML files. Current release is aimed mainly as support
+for the odsfile package. The documentation was created by automatic conversion of original documentation in the source code.
+In this version, some files not useful for luaTeX were droped.
+
+
+Install
+=======
+
+LuaXML is installed in TeX distributions, so you don't need to install it yourself. If you want to try the development version,
+then clone this repository and run
+
+ make install
+
+Please note that you will need [LDoc](http://stevedonovan.github.io/ldoc/manual/doc.md.html#Processing_Single_Modules) and
+[dkjson](http://dkolf.de/src/dkjson-lua.fsl/home) Lua modules installed on your system.
+
+License:
+========
+
+This code is freely distributable under the terms of the Lua license
+ (http://www.lua.org/copyright.html)
+
+
+Author
+------
+Michal Hoftich
+Email: michal.h21@gmail.com
+Version: v0.1h, 2018-12-18
+
+Original authors: Paul Chakravarti and Manoel Campos (http://manoelcampos.com)
+
+If you are interested in the process of development you may observe
+
+ https://github.com/michal-h21/LuaXML
diff --git a/macros/luatex/generic/luaxml/luaxml-cssquery.lua b/macros/luatex/generic/luaxml/luaxml-cssquery.lua
new file mode 100644
index 0000000000..d353a310c4
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml-cssquery.lua
@@ -0,0 +1,276 @@
+--- CSS query module for LuaXML
+-- @module luaxml-cssquery
+-- @author Michal Hoftich <michal.h21@gmail.com
+local parse_query = require("luaxml-parse-query")
+
+-- the string.explode function is provided by LuaTeX
+-- this is alternative for stock Lua
+-- source: http://lua-users.org/wiki/SplitJoin
+local function string_split(str, sep)
+ local sep, fields = sep or ":", {}
+ local pattern = string.format("([^%s]+)", sep)
+ str:gsub(pattern, function(c) fields[#fields+1] = c end)
+ return fields
+end
+
+string.explode = string.explode or string_split
+
+--- CssQuery constructor
+-- @function cssquery
+-- @return CssQuery object
+local function cssquery()
+ --- @type CssQuery
+ local CssQuery = {}
+ CssQuery.__index = CssQuery
+ CssQuery.__debug = false
+ CssQuery.querylist = {}
+
+ function CssQuery.debug(self)
+ self.__debug = true
+ end
+
+ function CssQuery:debug_print(text)
+ if self.__debug then
+ print("[CSS Object]: " .. text)
+ end
+ end
+ --- Calculate CSS specificity of the query
+ -- @param query table created by CssQuery:prepare_selector() function
+ -- @return integer speficity value
+ function CssQuery:calculate_specificity(query)
+ local query = query or {}
+ local specificity = 0
+ for _, item in ipairs(query.query or {}) do
+ for key, value in pairs(item) do
+ if key == "id" then
+ specificity = specificity + 100
+ elseif key == "tag" then
+ specificity = specificity + 1
+ else
+ specificity = specificity + 10
+ end
+ end
+ end
+ return specificity
+ end
+
+ -- save element position in the current siblings list
+ local function make_nth(curr_el)
+ local pos = 0
+ local el_pos = 0
+ -- get current node list
+ local siblings = curr_el:get_siblings()
+ if siblings then
+ for _, other_el in ipairs(siblings) do
+ -- number the elements
+ if other_el:is_element() then
+ pos = pos + 1
+ other_el.nth = pos
+ -- save the current element position
+ if other_el == curr_el then
+ el_pos = pos
+ end
+ end
+ end
+ else
+ return false
+ end
+ return el_pos
+ end
+
+ local function test_first_child(el, nth)
+ local el_pos = el.nth or make_nth(el)
+ return el_pos == 1
+ end
+
+ -- test element for nth-child selector
+ local function test_nth_child(el, nth)
+ local el_pos = el.nth or make_nth(el)
+ -- we support only the nth-child(number) form
+ return el_pos == tonumber(nth)
+ end
+
+ --- Test prepared querylist
+ -- @param domobj DOM element to test
+ -- @param querylist [optional] List of queries to test
+ -- @return table with CSS queries, which match the selected DOM element
+ function CssQuery:match_querylist(domobj, querylist)
+ local matches = {}
+ -- querylist can be explicit, saved queries can be used otherwise
+ local querylist = querylist or self.querylist
+
+ local function test_part(key, value, el)
+ -- print("testing", key, value, el:get_element_name())
+ if key == "tag" then
+ return el:get_element_name() == value
+ elseif key == "id" then
+ local id = el:get_attribute "id"
+ return id and id == value
+ elseif key == "class" then
+ local class = el:get_attribute "class"
+ if not class then return false end
+ local c = {}
+ for part in class:gmatch "([^%s]+)" do
+ c[part] = true
+ end
+ return c[value] == true
+ elseif key == "nth-child" then
+ return test_nth_child(el, value)
+ elseif key == "first-child" then
+ return test_first_child(el, value)
+ end
+ -- TODO: Add more cases
+ -- just return true for not supported selectors
+ return true
+ end
+
+ local function test_object(query, el)
+ -- test one object in CSS selector
+ local matched = {}
+ for key, value in pairs(query) do
+ matched[#matched+1] = test_part(key, value, el)
+ end
+ if #matched == 0 then return false end
+ for k, v in ipairs(matched) do
+ if v ~= true then return false end
+ end
+ return true
+ end
+
+ local function match_query(query, el)
+ local query = query or {}
+ local object = table.remove(query) -- get current object from the query stack
+ if not object then return true end -- if the query stack is empty, then we can be sure that it matched previous items
+ if not el:is_element() then return false end -- if there is object to test, but current node isn't element, test failed
+ local result = test_object(object, el)
+ if result then
+ return match_query(query, el:get_parent())
+ end
+ return false
+ end
+ for _,element in ipairs(querylist) do
+ local query = {}
+ for k,v in ipairs(element.query) do query[k] = v end
+ if #query > 0 then -- don't try to match empty query
+ local result = match_query(query, domobj)
+ if result then matches[#matches+1] = element end
+ end
+ end
+ return matches
+ end
+
+ --- Get elements that match the selector
+ -- @return table with DOM_Object elements
+ function CssQuery:get_selector_path(
+ domobj, -- DOM_Object
+ selectorlist -- querylist table created using CssQuery:prepare_selector
+ )
+ local nodelist = {}
+ domobj:traverse_elements(function(el)
+ local matches = self:match_querylist(el, selectorlist)
+ self:debug_print("Matching " .. el:get_element_name() .." "..#matches)
+ if #matches > 0 then nodelist[#nodelist+1] = el
+ end
+ end)
+ return nodelist
+ end
+
+ --- Parse CSS selector to a query table.
+ -- XML namespaces can be supported using
+ -- namespace|element syntax
+ -- @return table querylist
+ function CssQuery:prepare_selector(
+ selector -- string CSS selector query
+ )
+ local querylist = {}
+ local function parse_selector(item)
+ local query = {}
+ -- for i = #item, 1, -1 do
+ -- local part = item[i]
+ for _, part in ipairs(item) do
+ local t = {}
+ for _, atom in ipairs(part) do
+ local key = atom[1]
+ local value = atom[2]
+ -- support for XML namespaces in selectors
+ -- the namespace should be added using "|"
+ -- like namespace|element
+ if key=="tag" then
+ -- LuaXML doesn't support namespaces, so it is necessary
+ -- to match namespace:element
+ value=value:gsub("|", ":")
+ end
+ t[key] = value
+ end
+ query[#query + 1] = t
+ end
+ return query
+ end
+ -- for item in selector:gmatch("([^%s]+)") do
+ -- elements[#elements+1] = parse_selector(item)
+ -- end
+ local parts = parse_query.parse_query(selector) or {}
+ -- several selectors may be separated using ",", we must process them separately
+ local sources = selector:explode(",")
+ for i, part in ipairs(parts) do
+ querylist[#querylist+1] = {query = parse_selector(part), source = sources[i]}
+ end
+ return querylist
+ end
+
+ --- Add selector to CSS object list of selectors,
+ -- func is called when the selector matches a DOM object
+ -- params is table which will be passed to the func
+ -- @return integer number of elements in the prepared selector
+ function CssQuery:add_selector(
+ selector, -- CSS selector string
+ func, -- function which will be executed on matched elements
+ params -- table with parameters for the function
+ )
+ local selector_list = self:prepare_selector(selector)
+ for k, query in ipairs(selector_list) do
+ query.specificity = self:calculate_specificity(query)
+ query.func = func
+ query.params = params
+ table.insert(self.querylist, query)
+ end
+ self:sort_querylist()
+ return #selector_list
+ end
+
+ --- Sort selectors according to their specificity
+ -- It is called automatically when the selector is added
+ -- @return querylist table
+ function CssQuery:sort_querylist(
+ querylist -- [optional] querylist table
+ )
+ local querylist = querylist or self.querylist
+ table.sort(self.querylist, function(a,b)
+ return a.specificity > b.specificity
+ end)
+ return querylist
+ end
+
+ --- It tests list of queries agaings a DOM element and executes the
+ --- coresponding function that is saved for the matched query.
+ -- @return nothing
+ function CssQuery:apply_querylist(
+ domobj, -- DOM element
+ querylist -- querylist table
+ )
+ for _, query in ipairs(querylist) do
+ -- use default empty function which will pass to another match
+ local func = query.func or function() return true end
+ local params = query.params or {}
+ local status = func(domobj, params)
+ -- break the execution when the function return false
+ if status == false then
+ break
+ end
+ end
+ end
+
+ return setmetatable({}, CssQuery)
+end
+
+return cssquery
diff --git a/macros/luatex/generic/luaxml/luaxml-domobject.lua b/macros/luatex/generic/luaxml/luaxml-domobject.lua
new file mode 100644
index 0000000000..a410885e04
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml-domobject.lua
@@ -0,0 +1,529 @@
+--- DOM module for LuaXML
+-- @module luaxml-domobject
+-- @author Michal Hoftich <michal.h21@gmail.com
+local dom = {}
+local xml = require("luaxml-mod-xml")
+local handler = require("luaxml-mod-handler")
+local css_query = require("luaxml-cssquery")
+
+
+local void = {area = true, base = true, br = true, col = true, hr = true, img = true, input = true, link = true, meta = true, param = true}
+
+local escapes = {
+ [">"] = "&gt;",
+ ["<"] = "&lt;",
+ ["&"] = "&amp;",
+ ['"'] = "&quot;",
+ ["'"] = "&#39;",
+ ["`"] = "&#x60;"
+}
+
+local function escape(search, text)
+ return text:gsub(search, function(ch)
+ return escapes[ch] or ""
+ end)
+end
+
+local function escape_element(text)
+ return escape("([<>&])", text)
+end
+
+local function escape_attr(text)
+ return escape("([<>&\"'`])", text)
+end
+
+local actions = {
+ TEXT = {text = "%s"},
+ COMMENT = {start = "<!-- ", text = "%s", stop = " -->"},
+ ELEMENT = {start = "<%s%s>", stop = "</%s>", void = "<%s%s />"},
+ DECL = {start = "<?%s %s?>"},
+ PI = {start = "<?%s %s?>"},
+ DTD = {start = "<!DOCTYPE ", text = "%s" , stop=">"},
+ CDATA = {start = "<![CDATA[", text = "%s", stop ="]]>"}
+
+}
+
+--- It serializes the DOM object back to the XML.
+-- This function is mainly used for internal purposes, it is better to
+-- use the `DOM_Object:serialize()`.
+-- @param parser DOM object
+-- @param current Element which should be serialized
+-- @param level
+-- @param output
+-- @return table Table with XML strings. It can be concenated using table.concat() function to get XML string corresponding to the DOM_Object.
+local function serialize_dom(parser, current,level, output)
+ local output = output or {}
+ local function get_action(typ, action)
+ local ac = actions[typ] or {}
+ local format = ac[action] or ""
+ return format
+ end
+ local function insert(format, ...)
+ table.insert(output, string.format(format, ...))
+ end
+ local function prepare_attributes(attr)
+ local t = {}
+ local attr = attr or {}
+ for k, v in pairs(attr) do
+ t[#t+1] = string.format("%s='%s'", k, escape_attr(v))
+ end
+ if #t == 0 then return "" end
+ -- add space before attributes
+ return " " .. table.concat(t, " ")
+ end
+ local function start(typ, el, attr)
+ local format = get_action(typ, "start")
+ insert(format, el, prepare_attributes(attr))
+ end
+ local function text(typ, text)
+ local format = get_action(typ, "text")
+ insert(format, escape_element(text))
+ end
+ local function stop(typ, el)
+ local format = get_action(typ, "stop")
+ insert(format,el)
+ end
+ local level = level or 0
+ local spaces = string.rep(" ",level)
+ local root= current or parser._handler.root
+ local name = root._name or "unnamed"
+ local xtype = root._type or "untyped"
+ local text_content = root._text or ""
+ local attributes = root._attr or {}
+ -- if xtype == "TEXT" then
+ -- print(spaces .."TEXT : " .. root._text)
+ -- elseif xtype == "COMMENT" then
+ -- print(spaces .. "Comment : ".. root._text)
+ -- else
+ -- print(spaces .. xtype .. " : " .. name)
+ -- end
+ -- for k, v in pairs(attributes) do
+ -- print(spaces .. " ".. k.."="..v)
+ -- end
+ if xtype == "DTD" then
+ text_content = string.format('%s %s "%s" "%s"', name, attributes["_type"] or "", attributes._name, attributes._uri )
+ -- remove unused fields
+ text_content = text_content:gsub('"nil"','')
+ text_content = text_content:gsub('%s*$','')
+ attributes = {}
+ elseif xtype == "ELEMENT" and void[name] and #current._children < 1 then
+ local format = get_action(xtype, "void")
+ insert(format, name, prepare_attributes(attributes))
+ return output
+ elseif xtype == "PI" then
+ -- it contains spurious _text attribute
+ attributes["_text"] = nil
+ elseif xtype == "DECL" and name =="xml" then
+ -- the xml declaration attributes must be in a correct order
+ insert("<?xml version='%s' encoding='%s' ?>", attributes.version, attributes.encoding)
+ return output
+ end
+
+ start(xtype, name, attributes)
+ text(xtype,text_content)
+ local children = root._children or {}
+ for _, child in ipairs(children) do
+ output = serialize_dom(parser,child, level + 1, output)
+ end
+ stop(xtype, name)
+ return output
+end
+
+--- XML parsing function
+-- Parse the XML text and create the DOM object.
+-- @return DOM_Object
+local parse = function(
+ xmltext --- String to be parsed
+ )
+ local domHandler = handler.domHandler()
+ --- @type DOM_Object
+ local DOM_Object = xml.xmlParser(domHandler)
+ -- preserve whitespace
+ DOM_Object.options.stripWS = nil
+ DOM_Object:parse(xmltext)
+ DOM_Object.current = DOM_Object._handler.root
+ DOM_Object.__index = DOM_Object
+ DOM_Object.css_query = css_query()
+
+ local function save_methods(element)
+ setmetatable(element,DOM_Object)
+ local children = element._children or {}
+ for _, x in ipairs(children) do
+ save_methods(x)
+ end
+ end
+ local parser = setmetatable({}, DOM_Object)
+
+ --- Returns root element of the DOM_Object
+ -- @return DOM_Object
+ function DOM_Object:root_node()
+ return self._handler.root
+ end
+
+
+ --- Get current node type
+ -- @param el [optional] node to get the type of
+ function DOM_Object:get_node_type(
+ el --- [optional] element to test
+ )
+ local el = el or self
+ return el._type
+ end
+
+ --- Test if the current node is an element.
+ -- You can pass different element as parameter
+ -- @return boolean
+ function DOM_Object:is_element(
+ el --- [optional] element to test
+ )
+ local el = el or self
+ return self:get_node_type(el) == "ELEMENT" -- @bool
+ end
+
+
+ --- Test if current node is text
+ -- @return boolean
+ function DOM_Object:is_text(
+ el --- [optional] element to test
+ )
+ local el = el or self
+ return self:get_node_type(el) == "TEXT"
+ end
+
+ local lower = string.lower
+
+ --- Return name of the current element
+ -- @return string
+ function DOM_Object:get_element_name(
+ el --- [optional] element to test
+ )
+ local el = el or self
+ return el._name or "unnamed"
+ end
+
+ --- Get value of an attribute
+ -- @return string
+ function DOM_Object:get_attribute(
+ name --- Attribute name
+ )
+ local el = self
+ if self:is_element(el) then
+ local attr = el._attr or {}
+ return attr[name]
+ end
+ end
+
+ --- Set value of an attribute
+ -- @return boolean
+ function DOM_Object:set_attribute(
+ name --- Attribute name
+ , value --- Value to be set
+ )
+ local el = self
+ if self:is_element(el) then
+ el._attr[name] = value
+ return true
+ end
+ end
+
+
+ --- Serialize the current node back to XML
+ -- @return string
+ function DOM_Object:serialize(
+ current --- [optional] element to be serialized
+ )
+ local current = current
+ -- if no current element is added and self is not plain parser object
+ -- (_type is then nil), use the current object as serialized root
+ if not current and self._type then
+ current = self
+ end
+ return table.concat(serialize_dom(self, current))
+ end
+
+ --- Get text content from the node and all of it's children
+ -- @return string
+ function DOM_Object:get_text(
+ current --- [optional] element which should be converted to text
+ )
+ local current = current or self
+ local text = {}
+ if current:is_text() then return current._text or "" end
+ for _, el in ipairs(current:get_children()) do
+ if el:is_text() then
+ text[#text+1] = el._text or ""
+ elseif el:is_element() then
+ text[#text+1] = el:get_text()
+ end
+ end
+ return table.concat(text)
+ end
+
+
+
+ --- Retrieve elements from the given path.
+ -- The path is list of elements separated by space,
+ -- starting from the top element of the current element
+ -- @return table of elements which match the path
+ function DOM_Object:get_path(
+ path --- path to be traversed
+ , current --- [optional] element which should be traversed. Default element is the root element of the DOM_Object
+ )
+ local function traverse_path(path_elements, current, t)
+ local t = t or {}
+ if #path_elements == 0 then
+ -- for _, x in ipairs(current._children or {}) do
+ -- table.insert(t,x)
+ -- end
+ table.insert(t,current)
+ return t
+ end
+ local current_path = table.remove(path_elements, 1)
+ for _, x in ipairs(self:get_children(current)) do
+ if self:is_element(x) then
+ local name = string.lower(self:get_element_name(x))
+ if name == current_path then
+ t = traverse_path(path_elements, x, t)
+ end
+ end
+ end
+ return t
+ end
+ local current = current or self:root_node() -- self._handler.root
+ local path_elements = {}
+ local path = string.lower(path)
+ for el in path:gmatch("([^%s]+)") do table.insert(path_elements, el) end
+ return traverse_path(path_elements, current)
+ end
+
+ --- Select elements chidlren using CSS selector syntax
+ -- @return table with elements matching the selector.
+ function DOM_Object:query_selector(
+ selector --- String using the CSS selector syntax
+ )
+ local css_query = self.css_query
+ local css_parts = css_query:prepare_selector(selector)
+ return css_query:get_selector_path(self, css_parts)
+ end
+
+ --- Get table with children of the current element
+ -- @return table with children of the selected element
+ function DOM_Object:get_children(
+ el --- [optional] element to be selected
+ )
+ local el = el or self
+ local children = el._children or {}
+ return children
+ end
+
+ --- Get the parent element
+ -- @return DOM_Object parent element
+ function DOM_Object:get_parent(
+ el --- [optional] element to be selected
+ )
+ local el = el or self
+ return el._parent
+ end
+
+ --- Execute function on the current element and all it's children elements.
+ -- The traversing of child elements of a given node can be disabled when the executed
+ -- function returns false.
+ -- @return nothing
+ function DOM_Object:traverse_elements(
+ fn, --- function which will be executed on the current element and all it's children
+ current --- [optional] element to be selected
+ )
+ local current = current or self --
+ -- Following situation may happen when this method is called directly on the parsed object
+ if not current:get_node_type() then
+ current = self:root_node()
+ end
+ local status = true
+ if self:is_element(current) or self:get_node_type(current) == "ROOT"then
+ local status = fn(current)
+ -- don't traverse child nodes when the user function return false
+ if status ~= false then
+ for _, child in ipairs(self:get_children(current)) do
+ self:traverse_elements(fn, child)
+ end
+ end
+ end
+ end
+
+ --- Execute function on list of elements returned by DOM_Object:get_path()
+ function DOM_Object:traverse_node_list(
+ nodelist --- table with nodes selected by DOM_Object:get_path()
+ , fn --- function to be executed
+ )
+ local nodelist = nodelist or {}
+ for _, node in ipairs(nodelist) do
+ for _, element in ipairs(node._children) do
+ fn(element)
+ end
+ end
+ end
+
+ --- Replace the current node with new one
+ -- @return boolean, message
+ function DOM_Object:replace_node(
+ new --- element which should replace the current element
+ )
+ local old = self
+ local parent = self:get_parent(old)
+ local id,msg = self:find_element_pos( old)
+ if id then
+ parent._children[id] = new
+ return true
+ end
+ return false, msg
+ end
+
+ --- Add child node to the current node
+ function DOM_Object:add_child_node(
+ child, --- element to be inserted as a current node child
+ position --- [optional] position at which should the node be inserted
+ )
+ local parent = self
+ child._parent = parent
+ if position then
+ table.insert(parent._children, position, child)
+ else
+ table.insert(parent._children, child)
+ end
+ end
+
+
+ --- Create copy of the current node
+ -- @return DOM_Object element
+ function DOM_Object:copy_node(
+ element --- [optional] element to be copied
+ )
+ local element = element or self
+ local t = {}
+ for k, v in pairs(element) do
+ if type(v) == "table" and k~="_parent" then
+ t[k] = self:copy_node(v)
+ else
+ t[k] = v
+ end
+ end
+ save_methods(t)
+ return t
+ end
+
+
+ --- Create a new element
+ -- @return DOM_Object element
+ function DOM_Object:create_element(
+ name, -- New tag name
+ attributes, -- Table with attributes
+ parent -- [optional] element which should be saved as the element's parent
+ )
+ local parent = parent or self
+ local new = {}
+ new._type = "ELEMENT"
+ new._name = name
+ new._attr = attributes or {}
+ new._children = {}
+ new._parent = parent
+ save_methods(new)
+ return new
+ end
+
+ --- Create new text node
+ -- @return DOM_Object text object
+ function DOM_Object:create_text_node(
+ text, -- string
+ parent -- [optional] element which should be saved as the element's parent
+ )
+ local parent = parent or self
+ local new = {}
+ new._type = "TEXT"
+ new._parent = parent
+ new._text = text
+ save_methods(new)
+ return new
+ end
+
+ --- Delete current node
+ function DOM_Object:remove_node(
+ element -- [optional] element to be removed
+ )
+ local element = element or self
+ local parent = self:get_parent(element)
+ local pos = self:find_element_pos(element)
+ -- if pos then table.remove(parent._children, pos) end
+ if pos then
+ -- table.remove(parent._children, pos)
+ parent._children[pos] = setmetatable({_type = "removed"}, DOM_Object)
+ end
+ end
+
+ --- Find the element position in the current node list
+ -- @return integer position of the current element in the element table
+ function DOM_Object:find_element_pos(
+ el -- [optional] element which should be looked up
+ )
+ local el = el or self
+ local parent = self:get_parent(el)
+ if not self:is_element(parent) and self:get_node_type(parent) ~= "ROOT" then return nil, "The parent isn't element" end
+ for i, x in ipairs(parent._children) do
+ if x == el then return i end
+ end
+ return false, "Cannot find element"
+ end
+
+ --- Get node list which current node is part of
+ -- @return table with elements
+ function DOM_Object:get_siblings(
+ el -- [optional] element for which the sibling element list should be retrieved
+ )
+ local el = el or self
+ local parent = el:get_parent()
+ if parent:is_element() then
+ return parent:get_children()
+ end
+ end
+
+ --- Get sibling node of the current node
+ -- @param change Distance from the current node
+ -- @return DOM_Object node
+ function DOM_Object:get_sibling_node( change)
+ local el = self
+ local pos = el:find_element_pos()
+ local siblings = el:get_siblings()
+ if pos and siblings then
+ return siblings[pos + change]
+ end
+ end
+
+ --- Get next node
+ -- @return DOM_Object node
+ function DOM_Object:get_next_node(
+ el --- [optional] node to be used
+ )
+ local el = el or self
+ return el:get_sibling_node(1)
+ end
+
+ --- Get previous node
+ -- @return DOM_Object node
+ function DOM_Object:get_prev_node(
+ el -- [optional] node to be used
+ )
+ local el = el or self
+ return el:get_sibling_node(-1)
+ end
+
+
+ -- include the methods to all xml nodes
+ save_methods(parser._handler.root)
+ -- parser:
+ return parser
+end
+
+--- @export
+return {
+ parse = parse,
+ serialize_dom= serialize_dom
+}
diff --git a/macros/luatex/generic/luaxml/luaxml-entities.lua b/macros/luatex/generic/luaxml/luaxml-entities.lua
new file mode 100644
index 0000000000..dd7e6f7156
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml-entities.lua
@@ -0,0 +1,37 @@
+local M = {}
+local char = unicode and unicode.utf8.char or utf8.char
+local named_entities = require "luaxml-namedentities"
+local hexchartable = {}
+local decchartable = {}
+
+
+local function get_named_entity(name)
+ return named_entities[name]
+end
+
+function M.decode(s)
+ return s:gsub("&([#a-zA-Z0-9]+);?", function(m)
+ -- check if this is named entity first
+ local named = get_named_entity(m)
+ if named then return named end
+ -- check if it is numeric entity
+ local hex, charcode = m:match("#([xX]?)([a-fA-F0-9]+)")
+ -- if the entity is not numeric
+ if not charcode then return
+ "&" .. m .. ";"
+ end
+ local character
+ if hex~="" then
+ character = hexchartable[charcode] or char(tonumber(charcode,16))
+ hexchartable[charcode] = character
+ else
+ character = decchartable[charcode] or char(tonumber(charcode))
+ decchartable[charcode] = character
+ end
+ return character
+ end)
+end
+
+return M
+
+
diff --git a/macros/luatex/generic/luaxml/luaxml-mod-handler.lua b/macros/luatex/generic/luaxml/luaxml-mod-handler.lua
new file mode 100644
index 0000000000..5f12a92f71
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml-mod-handler.lua
@@ -0,0 +1,359 @@
+--..module(...,package.seeall)
+--
+-- Overview:
+-- =========
+-- Standard XML event handler(s) for XML parser module (xml.lua)
+--
+-- Features:
+-- =========
+-- printHandler - Generate XML event trace
+-- domHandler - Generate DOM-like node tree
+-- simpleTreeHandler - Generate 'simple' node tree
+-- simpleTeXhandler - SAX like handler with support for CSS selectros
+--
+-- API:
+-- ====
+-- Must be called as handler function from xmlParser
+-- and implement XML event callbacks (see xmlParser.lua
+-- for callback API definition)
+--
+-- printHandler:
+-- -------------
+--
+-- printHandler prints event trace for debugging
+--
+-- domHandler:
+-- -----------
+--
+-- domHandler generates a DOM-like node tree structure with
+-- a single ROOT node parent - each node is a table comprising
+-- fields below.
+--
+-- node = { _name = <Element Name>,
+-- _type = ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD,
+-- _attr = { Node attributes - see callback API },
+-- _parent = <Parent Node>
+-- _children = { List of child nodes - ROOT/NODE only }
+-- }
+--
+-- The dom structure is capable of representing any valid XML document
+--
+-- simpleTreeHandler
+-- -----------------
+--
+-- simpleTreeHandler is a simplified handler which attempts
+-- to generate a more 'natural' table based structure which
+-- supports many common XML formats.
+--
+-- The XML tree structure is mapped directly into a recursive
+-- table structure with node names as keys and child elements
+-- as either a table of values or directly as a string value
+-- for text. Where there is only a single child element this
+-- is inserted as a named key - if there are multiple
+-- elements these are inserted as a vector (in some cases it
+-- may be preferable to always insert elements as a vector
+-- which can be specified on a per element basis in the
+-- options). Attributes are inserted as a child element with
+-- a key of '_attr'.
+--
+-- Only Tag/Text & CDATA elements are processed - all others
+-- are ignored.
+--
+-- This format has some limitations - primarily
+--
+-- * Mixed-Content behaves unpredictably - the relationship
+-- between text elements and embedded tags is lost and
+-- multiple levels of mixed content does not work
+-- * If a leaf element has both a text element and attributes
+-- then the text must be accessed through a vector (to
+-- provide a container for the attribute)
+--
+-- In general however this format is relatively useful.
+--
+-- It is much easier to understand by running some test
+-- data through 'textxml.lua -simpletree' than to read this)
+--
+-- Options
+-- =======
+-- simpleTreeHandler.options.noReduce = { <tag> = bool,.. }
+--
+-- - Nodes not to reduce children vector even if only
+-- one child
+--
+-- domHandler.options.(comment|pi|dtd|decl)Node = bool
+--
+-- - Include/exclude given node types
+--
+-- Usage
+-- =====
+-- Pased as delegate in xmlParser constructor and called
+-- as callback by xmlParser:parse(xml) method.
+--
+-- See textxml.lua for examples
+-- License:
+-- ========
+--
+-- This code is freely distributable under the terms of the Lua license
+-- (<a href="http://www.lua.org/copyright.html">http://www.lua.org/copyright.html</a>)
+--
+-- History
+-- =======
+-- $Id: handler.lua,v 1.1.1.1 2001/11/28 06:11:33 paulc Exp $
+--
+-- $Log: handler.lua,v $
+-- Revision 1.1.1.1 2001/11/28 06:11:33 paulc
+-- Initial Import
+--@author Paul Chakravarti (paulc@passtheaardvark.com)<p/>
+
+
+---Handler to generate a string prepresentation of a table
+--Convenience function for printHandler (Does not support recursive tables).
+--@param t Table to be parsed
+--@returns Returns a string representation of table
+
+local M = {}
+local stack = require("luaxml-stack")
+local entities = require("luaxml-entities")
+
+local function showTable(t)
+ local sep = ''
+ local res = ''
+ if type(t) ~= 'table' then
+ return t
+ end
+ for k,v in pairs(t) do
+ if type(v) == 'table' then
+ v = showTable(v)
+ end
+ res = res .. sep .. string.format("%s=%s",k,v)
+ sep = ','
+ end
+ res = '{'..res..'}'
+ return res
+end
+
+
+M.showTable = showTable
+
+---Handler to generate a simple event trace
+local printHandler = function()
+ local obj = {}
+ obj.starttag = function(self,t,a,s,e)
+ io.write("Start : "..t.."\n")
+ if a then
+ for k,v in pairs(a) do
+ io.write(string.format(" + %s='%s'\n",k,v))
+ end
+ end
+ end
+ obj.endtag = function(self,t,s,e)
+ io.write("End : "..t.."\n")
+ end
+ obj.text = function(self,t,s,e)
+ io.write("Text : "..t.."\n")
+ end
+ obj.cdata = function(self,t,s,e)
+ io.write("CDATA : "..t.."\n")
+ end
+ obj.comment = function(self,t,s,e)
+ io.write("Comment : "..t.."\n")
+ end
+ obj.dtd = function(self,t,a,s,e)
+ io.write("DTD : "..t.."\n")
+ if a then
+ for k,v in pairs(a) do
+ io.write(string.format(" + %s='%s'\n",k,v))
+ end
+ end
+ end
+ obj.pi = function(self,t,a,s,e)
+ io.write("PI : "..t.."\n")
+ if a then
+ for k,v in pairs(a) do
+ io. write(string.format(" + %s='%s'\n",k,v))
+ end
+ end
+ end
+ obj.decl = function(self,t,a,s,e)
+ io.write("XML Decl : "..t.."\n")
+ if a then
+ for k,v in pairs(a) do
+ io.write(string.format(" + %s='%s'\n",k,v))
+ end
+ end
+ end
+ return obj
+end
+M.printHandler = printHandler
+---Handler to generate a lua table from a XML content string
+local function simpleTreeHandler()
+ local obj = {}
+
+ obj.root = {}
+ obj.stack = {obj.root;n=1}
+ obj.options = {noreduce = {}}
+
+ obj.reduce = function(self,node,key,parent)
+ -- Recursively remove redundant vectors for nodes
+ -- with single child elements
+ for k,v in pairs(node) do
+ if type(v) == 'table' then
+ self:reduce(v,k,node)
+ end
+ end
+ if #node == 1 and not self.options.noreduce[key] and
+ node._attr == nil then
+ parent[key] = node[1]
+ else
+ node.n = nil
+ end
+ end
+
+ obj.starttag = function(self,t,a)
+ local node = {}
+ if self.parseAttributes == true then
+ node._attr=a
+ end
+
+ local current = self.stack[#self.stack]
+ if current[t] then
+ table.insert(current[t],node)
+ else
+ current[t] = {node;n=1}
+ end
+ table.insert(self.stack,node)
+ end
+
+ obj.endtag = function(self,t,s)
+ local current = self.stack[#self.stack]
+ local prev = self.stack[#self.stack-1]
+ if not prev[t] then
+ error("XML Error - Unmatched Tag ["..s..":"..t.."]\n")
+ end
+ if prev == self.root then
+ -- Once parsing complete recursively reduce tree
+ self:reduce(prev,nil,nil)
+ end
+ table.remove(self.stack)
+ end
+
+ obj.text = function(self,t)
+ local current = self.stack[#self.stack]
+ table.insert(current,t)
+ end
+
+ obj.cdata = obj.text
+
+ return obj
+end
+
+M.simpleTreeHandler = simpleTreeHandler
+
+--- domHandler
+local function domHandler()
+ local obj = {}
+ local decode = entities.decode
+ obj.options = {commentNode=1,piNode=1,dtdNode=1,declNode=1}
+ obj.root = { _children = {n=0}, _type = "ROOT" }
+ obj.current = obj.root
+ obj.starttag = function(self,t,a)
+ local newattr
+ if a then
+ newattr = {}
+ for k,v in pairs(a) do
+ newattr[k] = decode(v)
+ end
+ end
+ local node = { _type = 'ELEMENT',
+ _name = t,
+ _attr = newattr,
+ _parent = self.current,
+ _children = {n=0} }
+ table.insert(self.current._children,node)
+ self.current = node
+ end
+ obj.endtag = function(self,t,s)
+ if t ~= self.current._name then
+ error("XML Error - Unmatched Tag ["..s..":"..t.."]\n")
+ end
+ self.current = self.current._parent
+ end
+ obj.text = function(self,t)
+ local node = { _type = "TEXT",
+ _parent = self.current,
+ _text = decode(t) }
+ table.insert(self.current._children,node)
+ end
+ obj.comment = function(self,t)
+ if self.options.commentNode then
+ local node = { _type = "COMMENT",
+ _parent = self.current,
+ _text = t }
+ table.insert(self.current._children,node)
+ end
+ end
+ obj.pi = function(self,t,a)
+ if self.options.piNode then
+ local node = { _type = "PI",
+ _name = t,
+ _attr = a,
+ _parent = self.current }
+ table.insert(self.current._children,node)
+ end
+ end
+ obj.decl = function(self,t,a)
+ if self.options.declNode then
+ local node = { _type = "DECL",
+ _name = t,
+ _attr = a,
+ _parent = self.current }
+ table.insert(self.current._children,node)
+ end
+ end
+ obj.dtd = function(self,t,a)
+ if self.options.dtdNode then
+ local node = { _type = "DTD",
+ _name = t,
+ _attr = a,
+ _parent = self.current }
+ table.insert(self.current._children,node)
+ end
+ end
+ obj.cdata = function(self,t)
+ local node = { _type = "CDATA",
+ _parent = self.current,
+ _text = decode(t) }
+ table.insert(self.current._children,node)
+ end
+ return obj
+end
+M.domHandler = domHandler
+
+--
+local simpleTeXhandler=function()
+ local obj={}
+ local _stack=stack.Stack:Create()
+ obj.starttag = function(self,t,a,s,e)
+ local tag = {t}
+ local getAtt = function(att)
+ if a[att] then
+ return att.."="..a[att]
+ end
+ return nil
+ end
+ if type(a) == "table" then
+ table.insert(tag,getAtt("id"))
+ table.insert(tag,getAtt("class"))
+ end
+ _stack:push("<"..table.concat(tag," ")..">")
+ io.write(_stack:join("").."\n")
+-- io.write("Start "..t.."\n" )
+ end
+ obj.endtag = function(self,t,s,e)
+ _stack:pop()
+ -- io.write("End : "..t.."\n")
+ end
+ return obj
+end
+M.simpleTeXhandler = simpleTeXhandler
+return M
diff --git a/macros/luatex/generic/luaxml/luaxml-mod-xml.lua b/macros/luatex/generic/luaxml/luaxml-mod-xml.lua
new file mode 100644
index 0000000000..2d99590105
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml-mod-xml.lua
@@ -0,0 +1,565 @@
+-- module(...,package.seeall)
+---
+-- Overview:
+-- =========
+--
+-- This module provides a non-validating XML stream parser in Lua.
+--
+-- Features:
+-- =========
+--
+-- * Tokenises well-formed XML (relatively robustly)
+-- * Flexible handler based event api (see below)
+-- * Parses all XML Infoset elements - ie.
+-- - Tags
+-- - Text
+-- - Comments
+-- - CDATA
+-- - XML Decl
+-- - Processing Instructions
+-- - DOCTYPE declarations
+-- * Provides limited well-formedness checking
+-- (checks for basic syntax & balanced tags only)
+-- * Flexible whitespace handling (selectable)
+-- * Entity Handling (selectable)
+--
+-- Limitations:
+-- ============
+--
+-- * Non-validating
+-- * No charset handling
+-- * No namespace support
+-- * Shallow well-formedness checking only (fails
+-- to detect most semantic errors)
+--
+-- API:
+-- ====
+--
+-- The parser provides a partially object-oriented API with
+-- functionality split into tokeniser and hanlder components.
+--
+-- The handler instance is passed to the tokeniser and receives
+-- callbacks for each XML element processed (if a suitable handler
+-- function is defined). The API is conceptually similar to the
+-- SAX API but implemented differently.
+--
+-- The following events are generated by the tokeniser
+--
+-- handler:start - Start Tag
+-- handler:end - End Tag
+-- handler:text - Text
+-- handler:decl - XML Declaration
+-- handler:pi - Processing Instruction
+-- handler:comment - Comment
+-- handler:dtd - DOCTYPE definition
+-- handler:cdata - CDATA
+--
+-- The function prototype for all the callback functions is
+--
+-- callback(val,attrs,start,end)
+--
+-- where attrs is a table and val/attrs are overloaded for
+-- specific callbacks - ie.
+--
+-- Callback val attrs (table)
+-- -------- --- -------------
+-- start name { attributes (name=val).. }
+-- end name nil
+-- text <text> nil
+-- cdata <text> nil
+-- decl "xml" { attributes (name=val).. }
+-- pi pi name { attributes (if present)..
+-- _text = <PI Text>
+-- }
+-- comment <text> nil
+-- dtd root element { _root = <Root Element>,
+-- _type = SYSTEM|PUBLIC,
+-- _name = <name>,
+-- _uri = <uri>,
+-- _internal = <internal dtd>
+-- }
+--
+-- (start & end provide the character positions of the start/end
+-- of the element)
+--
+-- XML data is passed to the parser instance through the 'parse'
+-- method (Nore: must be passed a single string currently)
+--
+-- Options
+-- =======
+--
+-- Parser options are controlled through the 'self.options' table.
+-- Available options are -
+--
+-- * stripWS
+--
+-- Strip non-significant whitespace (leading/trailing)
+-- and do not generate events for empty text elements
+--
+-- * expandEntities
+--
+-- Expand entities (standard entities + single char
+-- numeric entities only currently - could be extended
+-- at runtime if suitable DTD parser added elements
+-- to table (see obj._ENTITIES). May also be possible
+-- to expand multibyre entities for UTF-8 only
+--
+-- * errorHandler
+--
+-- Custom error handler function
+--
+-- NOTE: Boolean options must be set to 'nil' not '0'
+--
+-- Usage
+-- =====
+--
+-- Create a handler instance -
+--
+-- h = { start = function(t,a,s,e) .... end,
+-- end = function(t,a,s,e) .... end,
+-- text = function(t,a,s,e) .... end,
+-- cdata = text }
+--
+-- (or use predefined handler - see handler.lua)
+--
+-- Create parser instance -
+--
+-- p = xmlParser(h)
+--
+-- Set options -
+--
+-- p.options.xxxx = nil
+--
+-- Parse XML data -
+--
+-- xmlParser:parse("<?xml... ")
+-- License:
+-- ========
+--
+-- This code is freely distributable under the terms of the Lua license
+-- (http://www.lua.org/copyright.html)
+--
+-- History
+-- =======
+-- Fixed some errors in DTD matching
+-- Added functions serialize and xmlEscape
+-- by Michal Hoftich
+-- 2012/07/26
+--
+-- Added parameter parseAttributes (boolean) in xmlParser.parse method
+-- If true, tag attributtes are parsed. The default value is true.
+-- by Manoel Campos (http://manoelcampos.com)
+--
+-- $Id: xml.lua,v 1.1.1.1 2001/11/28 06:11:33 paulc Exp $
+--
+-- $Log: xml.lua,v $
+-- Revision 1.1.1.1 2001/11/28 06:11:33 paulc
+-- Initial Import
+--
+--@author Paul Chakravarti (paulc@passtheaardvark.com)<p/>
+
+local format= string.format
+---Parses a XML string
+--@param handler Handler object to be used to convert the XML string
+--to another formats. @see handler.lua
+local M={}
+local xmlParser = function(handler)
+ local obj = {}
+ -- Public attributes
+
+ obj.options = {
+ stripWS = 1,
+ expandEntities = 1,
+ errorHandler = function(err,pos)
+ error(format("%s [char=%d]\n",
+ err or "Parse Error",pos))
+ end,
+ }
+
+ -- Public methods
+
+ obj.parse = function(self, str, parseAttributes)
+ if parseAttributes == nil then
+ parseAttributes = true
+ end
+ self._handler.parseAttributes = parseAttributes
+
+ local match,endmatch,pos = 0,0,1
+ local text,endt1,endt2,tagstr,tagname,attrs,starttext,endtext
+ local errstart,errend,extstart,extend
+ while match do
+ -- Get next tag (first pass - fix exceptions below)
+ match,endmatch,text,endt1,tagstr,endt2 = string.find(str,self._XML,pos)
+ if not match then
+ if string.find(str,self._WS,pos) then
+ -- No more text - check document complete
+ if #self._stack ~= 0 then
+ self:_err(self._errstr.incompleteXmlErr,pos)
+ else
+ break
+ end
+ else
+ -- Unparsable text
+ self:_err(self._errstr.xmlErr,pos)
+ end
+ end
+ -- Handle leading text
+ starttext = match
+ endtext = match + string.len(text) - 1
+ match = match + string.len(text)
+ text = self:_parseEntities(self:_stripWS(text))
+ if text ~= "" and self._handler.text then
+ self._handler:text(text,nil,match,endtext)
+ end
+ -- Test for tag type
+ if string.find(string.sub(tagstr,1,5),"?xml%s") then
+ -- XML Declaration
+ match,endmatch,text = string.find(str,self._PI,pos)
+ if not match then
+ self:_err(self._errstr.declErr,pos)
+ end
+ if match ~= 1 then
+ -- Must be at start of doc if present
+ self:_err(self._errstr.declStartErr,pos)
+ end
+ tagname,attrs = self:_parseTag(text)
+ -- TODO: Check attributes are valid
+ -- Check for version (mandatory)
+ if attrs.version == nil then
+ self:_err(self._errstr.declAttrErr,pos)
+ end
+ if self._handler.decl then
+ self._handler:decl(tagname,attrs,match,endmatch)
+ end
+ elseif string.sub(tagstr,1,1) == "?" then
+ -- Processing Instruction
+ match,endmatch,text = string.find(str,self._PI,pos)
+ if not match then
+ self:_err(self._errstr.piErr,pos)
+ end
+ if self._handler.pi then
+ -- Parse PI attributes & text
+ tagname,attrs = self:_parseTag(text)
+ local pi = string.sub(text,string.len(tagname)+1)
+ if pi ~= "" then
+ if attrs then
+ attrs._text = pi
+ else
+ attrs = { _text = pi }
+ end
+ end
+ self._handler:pi(tagname,attrs,match,endmatch)
+ end
+ elseif string.sub(tagstr,1,3) == "!--" then
+ -- Comment
+ match,endmatch,text = string.find(str,self._COMMENT,pos)
+ if not match then
+ self:_err(self._errstr.commentErr,pos)
+ end
+ if self._handler.comment then
+ text = self:_parseEntities(self:_stripWS(text))
+ self._handler:comment(text,next,match,endmatch)
+ end
+ elseif string.sub(tagstr,1,8) == "!DOCTYPE" then
+ -- DTD
+ --match,endmatch,attrs = self:_parseDTD(string,pos)
+ match,endmatch,attrs = self:_parseDTD(str,pos)
+ if not match then
+ self:_err(self._errstr.dtdErr,pos)
+ end
+ if self._handler.dtd then
+ self._handler:dtd(attrs._root,attrs,match,endmatch)
+ end
+ elseif string.sub(tagstr,1,8) == "![CDATA[" then
+ -- CDATA
+ match,endmatch,text = string.find(str,self._CDATA,pos)
+ if not match then
+ self:_err(self._errstr.cdataErr,pos)
+ end
+ if self._handler.cdata then
+ self._handler:cdata(text,nil,match,endmatch)
+ end
+ else
+ -- Normal tag
+
+ -- Need theck for embedded '>' in attribute value and extend
+ -- match recursively if necessary eg. <tag attr="123>456">
+
+ while 1 do
+ errstart,errend = string.find(tagstr,self._ATTRERR1)
+ if errend == nil then
+ errstart,errend = string.find(tagstr,self._ATTRERR2)
+ if errend == nil then
+ break
+ end
+ end
+ local errorstring = tagstr:sub(errstart, errend)
+ -- it seems that it causes error if an attribute starts with `=`
+ if errorstring:match("^=") then break end
+
+ extstart,extend,endt2 = string.find(str,self._TAGEXT,endmatch+1)
+ if not extstart then break end
+
+ tagstr = tagstr .. string.sub(str,endmatch,extend-1)
+ if not match then
+ self:_err(self._errstr.xmlErr,pos)
+ end
+ endmatch = extend
+ end
+
+ -- Extract tagname/attrs
+
+ tagname,attrs = self:_parseTag(tagstr)
+
+ if (endt1=="/") then
+ -- End tag
+ if self._handler.endtag then
+ if attrs then
+ -- Shouldnt have any attributes in endtag
+ self:_err(format("%s (/%s)",
+ self._errstr.endTagErr,
+ tagname)
+ ,pos)
+ end
+ if table.remove(self._stack) ~= tagname then
+ self:_err(format("%s (/%s)",
+ self._errstr.unmatchedTagErr,
+ tagname)
+ ,pos)
+ end
+ self._handler:endtag(tagname,nil,match,endmatch)
+ end
+ else
+ -- Start Tag
+ table.insert(self._stack,tagname)
+ if self._handler.starttag then
+ self._handler:starttag(tagname,attrs,match,endmatch)
+ end
+ -- Self-Closing Tag
+ if (endt2=="/") then
+ table.remove(self._stack)
+ if self._handler.endtag then
+ self._handler:endtag(tagname,nil,match,endmatch)
+ end
+ end
+ end
+ end
+ pos = endmatch + 1
+ end
+ end
+
+ -- Private attrobures/functions
+
+ obj._handler = handler
+ obj._stack = {}
+
+ obj._XML = '^([^<]*)<(%/?)([^>]-)(%/?)>'
+ obj._ATTR1 = '([%w-:_]+)%s*=%s*"(.-)"'
+ obj._ATTR2 = '([%w-:_]+)%s*=%s*\'(.-)\''
+ obj._CDATA = '<%!%[CDATA%[(.-)%]%]>'
+ obj._PI = '<%?(.-)%?>'
+ obj._COMMENT = '<!%-%-(.-)%-%->'
+ obj._TAG = '^(.-)%s.*'
+ obj._LEADINGWS = '^%s+'
+ obj._TRAILINGWS = '%s+$'
+ obj._WS = '^%s*$'
+ local allowed_element_name_pattern = "[%w_%.%-]+"
+ obj._DTD1 = '<!DOCTYPE%s+(' .. allowed_element_name_pattern .. ')%s+(SYSTEM)%s+["\'](.-)["\']%s*(%b[])%s*>'
+ obj._DTD2 = '<!DOCTYPE%s+(' .. allowed_element_name_pattern .. ')%s+(PUBLIC)%s+["\'](.-)["\']%s+["\'](.-)["\']%s*(%b[])%s*>'
+ obj._DTD3 = '<!DOCTYPE%s+(' .. allowed_element_name_pattern .. ')%s*(%b[])%s*>'
+ obj._DTD4 = '<!DOCTYPE%s+(' .. allowed_element_name_pattern .. ')%s+(SYSTEM)%s+["\'](.-)["\']%s*>'
+ obj._DTD5 = '<!DOCTYPE%s+(' .. allowed_element_name_pattern .. ')%s+(PUBLIC)%s+["\'](.-)["\']%s+["\'](.-)["\']%s*>'
+ obj._DTD6 = '<!DOCTYPE%s+(' .. allowed_element_name_pattern .. ')%s*>'
+ --obj._DTD6 = "<!DOCTYPE%s+(.-)%s+(PUBLIC)%s+[\"'](.-)[\"']%s+[\"'](.-)[\"']%s*>"
+
+ obj._ATTRERR1 = '=%s*"[^"]*$'
+ obj._ATTRERR2 = '=%s*\'[^\']*$'
+ obj._TAGEXT = '(%/?)>'
+
+ obj._ENTITIES = { ["&lt;"] = "<",
+ ["&gt;"] = ">",
+ ["&amp;"] = "&",
+ ["&quot;"] = '"',
+ ["&apos;"] = "'",
+ ["&#(%d+);"] = function (x)
+ local d = tonumber(x)
+ if d >= 0 and d < 256 then
+ return string.char(d)
+ else
+ return "&#"..d..";"
+ end
+ end,
+ ["&#x(%x+);"] = function (x)
+ local d = tonumber(x,16)
+ if d >= 0 and d < 256 then
+ return string.char(d)
+ else
+ return "&#x"..x..";"
+ end
+ end,
+ }
+
+ obj._err = function(self,err,pos)
+ if self.options.errorHandler then
+ self.options.errorHandler(err,pos)
+ end
+ end
+
+ obj._errstr = { xmlErr = "Error Parsing XML",
+ declErr = "Error Parsing XMLDecl",
+ declStartErr = "XMLDecl not at start of document",
+ declAttrErr = "Invalid XMLDecl attributes",
+ piErr = "Error Parsing Processing Instruction",
+ commentErr = "Error Parsing Comment",
+ cdataErr = "Error Parsing CDATA",
+ dtdErr = "Error Parsing DTD",
+ endTagErr = "End Tag Attributes Invalid",
+ unmatchedTagErr = "Unbalanced Tag",
+ incompleteXmlErr = "Incomplete XML Document",
+ }
+
+ obj._stripWS = function(self,s)
+ if self.options.stripWS then
+ s = string.gsub(s,'^%s+','')
+ s = string.gsub(s,'%s+$','')
+ end
+ return s
+ end
+
+ obj._parseEntities = function(self,s)
+ if self.options.expandEntities then
+ --for k,v in self._ENTITIES do
+ for k,v in pairs(self._ENTITIES) do
+ --print (k, v)
+ s = string.gsub(s,k,v)
+ end
+ end
+ return s
+ end
+
+ obj._parseDTD = function(self,s,pos)
+ -- match,endmatch,root,type,name,uri,internal
+ --print(s.." : "..pos)
+ local m,e,r,t,n,u,i
+ m,e,r,t,n,u = string.find(s,self._DTD5,pos)
+ if m then
+ return m,e,{_root=r,_type=t,_name=n,_uri=u}
+ end
+ m,e,r,t,u,i = string.find(s,self._DTD1,pos)
+ if m then
+ return m,e,{_root=r,_type=t,_uri=u,_internal=i}
+ end
+ m,e,r,t,n,u,i = string.find(s,self._DTD2,pos)
+ if m then
+ return m,e,{_root=r,_type=t,_name=n,_uri=u,_internal=i}
+ end
+ m,e,r,i = string.find(s,self._DTD3,pos)
+ if m then
+ return m,e,{_root=r,_internal=i}
+ end
+ m,e,r,t,u = string.find(s,self._DTD4,pos)
+ if m then
+ return m,e,{_root=r,_type=t,_uri=u}
+ end
+ m,e,r = string.find(s, self._DTD6, pos)
+ if m then
+ return m,e, {_root=r }
+ end
+ return nil
+ end
+
+ obj._parseTag = function(self,s)
+ local attrs = {}
+ local tagname = string.gsub(s,self._TAG,'%1')
+ string.gsub(s,self._ATTR1,function (k,v)
+ attrs[string.lower(k)]=self:_parseEntities(v)
+ attrs._ = 1
+ end)
+ string.gsub(s,self._ATTR2,function (k,v)
+ attrs[string.lower(k)]=self:_parseEntities(v)
+ attrs._ = 1
+ end)
+ if attrs._ then
+ attrs._ = nil
+ else
+ attrs = nil
+ end
+ return tagname,attrs
+ end
+
+ return obj
+
+end
+M.xmlParser = xmlParser
+
+local function xmlEscape(s)
+ local t = {['"']="&quot;",["'"]="&apos;",["&"]="&amp;",["<"]="&lt;",[">"]="&gt;"}
+ return string.gsub(s,"([\"'<>&])",t)
+end
+
+M.xmlEscape = xmlEscape
+
+
+local function serialize(tb)
+local function getAttributes(k,v)
+ local i = ""
+ if(type(v["_attr"])=="table") then
+ -- texio.write_nl("attr")
+ for p,n in pairs(v["_attr"]) do
+ i = i ..' '.. p .. '="'..xmlEscape(n)..'"'
+ end
+ --table.remove(v,"_attr")
+ end
+ return i
+ end
+
+ local function printable(tb, level,currTag)
+ local r ={}
+ local currTag = currTag or ""
+ level = level or 0
+ local spaces = string.rep(' ', level*2)
+ for k,v in pairs(tb) do
+ if type(v) ~= "table" then
+ local ct = k
+ if type(k)=="number" then
+ ct = currTag
+ end
+ if ct == "" then
+ table.insert(r,spaces .. xmlEscape(v).."\n")
+ else
+ local i = getAttributes(k,v)
+ table.insert(r,spaces .. '<'..ct..i..'>'..xmlEscape(v)..'</'..ct..'>'.."\n")
+ end
+ else
+ if k == "_attr" then
+ --table.insert(r,printable(v, level))
+ else
+ if type(k)=="string" then
+ --currTag = k
+ if type(k)=="numeric" then
+ k = currTag
+ end
+ if #v > 1 then
+ table.insert(r,printable(v, level+1,k))
+ else
+ local i = getAttributes(k,v)
+ table.insert(r,spaces.."<"..k..i..">\n")
+ table.insert(r,printable(v, level+1,k))
+ table.insert(r,spaces.."</"..k..">\n")
+ end
+ else
+ local i = getAttributes(k,v)
+ table.insert(r,spaces .. "<"..currTag..i..">\n")
+ --level = level + 1
+ table.insert(r,printable(v, level+1))
+ table.insert(r,spaces .. "</"..currTag..">\n")
+ end
+ end
+ end
+ end
+ return table.concat(r,"")
+ end
+ return table.concat({'<?xml version="1.0" encoding="UTF-8"?>',printable(tb)},"\n")
+end
+M.serialize = serialize
+return M
diff --git a/macros/luatex/generic/luaxml/luaxml-namedentities.lua b/macros/luatex/generic/luaxml/luaxml-namedentities.lua
new file mode 100644
index 0000000000..5d68692914
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml-namedentities.lua
@@ -0,0 +1,2233 @@
+return {
+["HARDcy"]="Ъ",
+["capdot"]="⩀",
+["pound"]="£",
+["upuparrows"]="⇈",
+["RightFloor"]="⌋",
+["LeftUpTeeVector"]="⥠",
+["shcy"]="ш",
+["ac"]="∾",
+["Iacute"]="Í",
+["boxVl"]="╢",
+["prap"]="⪷",
+["ocirc"]="ô",
+["Rsh"]="↱",
+["Ncy"]="Н",
+["mdash"]="—",
+["lozf"]="⧫",
+["ETH"]="Ð",
+["rhov"]="ϱ",
+["dtri"]="▿",
+["shortparallel"]="∥",
+["DiacriticalDoubleAcute"]="˝",
+["Uring"]="Ů",
+["gap"]="⪆",
+["notinvb"]="⋷",
+["nsc"]="⊁",
+["zeta"]="ζ",
+["Ouml"]="Ö",
+["Sub"]="⋐",
+["Zdot"]="Ż",
+["ograve"]="ò",
+["block"]="█",
+["toea"]="⤨",
+["odash"]="⊝",
+["DownRightVector"]="⇁",
+["siml"]="⪝",
+["sharp"]="♯",
+["oline"]="‾",
+["Proportional"]="∝",
+["Lacute"]="Ĺ",
+["gtreqqless"]="⪌",
+["Im"]="ℑ",
+["blacktriangledown"]="▾",
+["ndash"]="–",
+["straightepsilon"]="ϵ",
+["bigodot"]="⨀",
+["npr"]="⊀",
+["iocy"]="ё",
+["lltri"]="◺",
+["Uuml"]="Ü",
+["srarr"]="→",
+["nvap"]="≍⃒",
+["nprec"]="⊀",
+["Rcy"]="Р",
+["DownArrowBar"]="⤓",
+["Ll"]="⋘",
+["forkv"]="⫙",
+["LongLeftArrow"]="⟵",
+["LeftUpVectorBar"]="⥘",
+["jsercy"]="ј",
+["thkap"]="≈",
+["gsime"]="⪎",
+["realine"]="ℛ",
+["nsupset"]="⊃⃒",
+["inodot"]="ı",
+["CircleDot"]="⊙",
+["qint"]="⨌",
+["nLeftarrow"]="⇍",
+["prnap"]="⪹",
+["caron"]="ˇ",
+["LessFullEqual"]="≦",
+["RightVectorBar"]="⥓",
+["kappa"]="κ",
+["Ascr"]="𝒜",
+["Emacr"]="Ē",
+["nsup"]="⊅",
+["simlE"]="⪟",
+["gamma"]="γ",
+["CircleTimes"]="⊗",
+["Aogon"]="Ą",
+["sstarf"]="⋆",
+["drbkarow"]="⤐",
+["ruluhar"]="⥨",
+["icirc"]="î",
+["Esim"]="⩳",
+["Longleftrightarrow"]="⟺",
+["SquareUnion"]="⊔",
+["Iacute"]="Í",
+["oplus"]="⊕",
+["VerticalSeparator"]="❘",
+["coprod"]="∐",
+["eDot"]="≑",
+["TScy"]="Ц",
+["Leftrightarrow"]="⇔",
+["Lcy"]="Л",
+["NotSucceedsSlantEqual"]="⋡",
+["Tstrok"]="Ŧ",
+["QUOT"]="\"",
+["curlyeqsucc"]="⋟",
+["lozenge"]="◊",
+["ltcir"]="⩹",
+["Lsh"]="↰",
+["ldsh"]="↲",
+["dcaron"]="ď",
+["scaron"]="š",
+["Racute"]="Ŕ",
+["nvgt"]=">⃒",
+["Cscr"]="𝒞",
+["rmoustache"]="⎱",
+["Ucy"]="У",
+["LessEqualGreater"]="⋚",
+["lsime"]="⪍",
+["Iuml"]="Ï",
+["zfr"]="𝔷",
+["LowerLeftArrow"]="↙",
+["ccaps"]="⩍",
+["smeparsl"]="⧤",
+["hellip"]="…",
+["rcaron"]="ř",
+["Dscr"]="𝒟",
+["clubs"]="♣",
+["Poincareplane"]="ℌ",
+["Vcy"]="В",
+["nles"]="⩽̸",
+["blank"]="␣",
+["order"]="ℴ",
+["ccups"]="⩌",
+["rbrkslu"]="⦐",
+["easter"]="⩮",
+["ltimes"]="⋉",
+["rBarr"]="⤏",
+["nlArr"]="⇍",
+["minusdu"]="⨪",
+["nhArr"]="⇎",
+["lg"]="≶",
+["LessGreater"]="≶",
+["lne"]="⪇",
+["NegativeThickSpace"]="​",
+["LessLess"]="⪡",
+["nsime"]="≄",
+["nltri"]="⋪",
+["boxvL"]="╡",
+["isin"]="∈",
+["UnderBrace"]="⏟",
+["el"]="⪙",
+["ntriangleleft"]="⋪",
+["lnsim"]="⋦",
+["Sacute"]="Ś",
+["Fscr"]="ℱ",
+["gbreve"]="ğ",
+["ohbar"]="⦵",
+["alefsym"]="ℵ",
+["nap"]="≉",
+["eqvparsl"]="⧥",
+["NegativeVeryThinSpace"]="​",
+["prod"]="∏",
+["ohm"]="Ω",
+["NotNestedGreaterGreater"]="⪢̸",
+["rtimes"]="⋊",
+["sigmav"]="ς",
+["check"]="✓",
+["reg"]="®",
+["Gscr"]="𝒢",
+["nLeftrightarrow"]="⇎",
+["triminus"]="⨺",
+["topfork"]="⫚",
+["Ugrave"]="Ù",
+["nleqslant"]="⩽̸",
+["Oacute"]="Ó",
+["NonBreakingSpace"]=" ",
+["eqcolon"]="≕",
+["lrcorner"]="⌟",
+["Ycy"]="Ы",
+["rarrtl"]="↣",
+["Udblac"]="Ű",
+["gl"]="≷",
+["rightarrow"]="→",
+["nprcue"]="⋠",
+["Hscr"]="ℋ",
+["rlhar"]="⇌",
+["trianglerighteq"]="⊵",
+["Uacute"]="Ú",
+["nexist"]="∄",
+["plusmn"]="±",
+["hardcy"]="ъ",
+["Zcy"]="З",
+["lbarr"]="⤌",
+["macr"]="¯",
+["prnsim"]="⋨",
+["NotTildeEqual"]="≄",
+["Iscr"]="ℐ",
+["Element"]="∈",
+["Subset"]="⋐",
+["supsetneq"]="⊋",
+["raemptyv"]="⦳",
+["Scy"]="С",
+["xmap"]="⟼",
+["ugrave"]="ù",
+["notnivc"]="⋽",
+["LessTilde"]="≲",
+["RightUpVectorBar"]="⥔",
+["epar"]="⋕",
+["otimes"]="⊗",
+["boxH"]="═",
+["angmsdae"]="⦬",
+["topcir"]="⫱",
+["shy"]="­",
+["Lstrok"]="Ł",
+["latail"]="⤙",
+["Tcy"]="Т",
+["sqcup"]="⊔",
+["sqsub"]="⊏",
+["sqcap"]="⊓",
+["angmsd"]="∡",
+["parallel"]="∥",
+["minus"]="−",
+["circ"]="ˆ",
+["alpha"]="α",
+["chcy"]="ч",
+["SucceedsEqual"]="⪰",
+["opar"]="⦷",
+["Cayleys"]="ℭ",
+["agrave"]="à",
+["imagpart"]="ℑ",
+["varsubsetneqq"]="⫋︀",
+["epsi"]="ε",
+["nVdash"]="⊮",
+["orarr"]="↻",
+["rfr"]="𝔯",
+["xuplus"]="⨄",
+["checkmark"]="✓",
+["rpargt"]="⦔",
+["ncup"]="⩂",
+["trisb"]="⧍",
+["npar"]="∦",
+["times"]="×",
+["nrightarrow"]="↛",
+["commat"]="@",
+["bigtriangleup"]="△",
+["Zcaron"]="Ž",
+["fpartint"]="⨍",
+["lnapprox"]="⪉",
+["utri"]="▵",
+["Hat"]="^",
+["rsquo"]="’",
+["wfr"]="𝔴",
+["LeftDoubleBracket"]="⟦",
+["Sc"]="⪼",
+["midast"]="*",
+["utdot"]="⋰",
+["lbrkslu"]="⦍",
+["Sqrt"]="√",
+["TripleDot"]="⃛",
+["oslash"]="ø",
+["rarrpl"]="⥅",
+["csupe"]="⫒",
+["gcy"]="г",
+["gtrdot"]="⋗",
+["xfr"]="𝔵",
+["cudarrl"]="⤸",
+["rarrb"]="⇥",
+["nRightarrow"]="⇏",
+["phi"]="φ",
+["fallingdotseq"]="≒",
+["rarrbfs"]="⤠",
+["rangle"]="⟩",
+["HorizontalLine"]="─",
+["propto"]="∝",
+["subsub"]="⫕",
+["flat"]="♭",
+["ograve"]="ò",
+["bne"]="=⃥",
+["Cedilla"]="¸",
+["DownLeftTeeVector"]="⥞",
+["sup"]="⊃",
+["profalar"]="⌮",
+["sime"]="≃",
+["And"]="⩓",
+["bsim"]="∽",
+["vfr"]="𝔳",
+["edot"]="ė",
+["scE"]="⪴",
+["ffllig"]="ffl",
+["spadesuit"]="♠",
+["gt"]=">",
+["Lt"]="≪",
+["angmsdad"]="⦫",
+["rightsquigarrow"]="↝",
+["larrbfs"]="⤟",
+["NJcy"]="Њ",
+["thicksim"]="∼",
+["gnsim"]="⋧",
+["bottom"]="⊥",
+["lmoustache"]="⎰",
+["NotPrecedesEqual"]="⪯̸",
+["bumpe"]="≏",
+["heartsuit"]="♥",
+["lt"]="<",
+["prop"]="∝",
+["DiacriticalAcute"]="´",
+["boxHu"]="╧",
+["RightUpDownVector"]="⥏",
+["ReverseElement"]="∋",
+["Dot"]="¨",
+["sqcups"]="⊔︀",
+["lvnE"]="≨︀",
+["subsetneq"]="⊊",
+["gdot"]="ġ",
+["lpar"]="(",
+["NotEqual"]="≠",
+["awint"]="⨑",
+["iiint"]="∭",
+["imath"]="ı",
+["gne"]="⪈",
+["operp"]="⦹",
+["nbumpe"]="≏̸",
+["doublebarwedge"]="⌆",
+["LJcy"]="Љ",
+["bbrk"]="⎵",
+["RightAngleBracket"]="⟩",
+["reg"]="®",
+["nvlArr"]="⤂",
+["xcup"]="⋃",
+["mapstoup"]="↥",
+["nlt"]="≮",
+["nsim"]="≁",
+["nsubE"]="⫅̸",
+["plus"]="+",
+["bigotimes"]="⨂",
+["jmath"]="ȷ",
+["equals"]="=",
+["khcy"]="х",
+["Upsilon"]="Υ",
+["rightrightarrows"]="⇉",
+["supe"]="⊇",
+["Egrave"]="È",
+["lbrksld"]="⦏",
+["sce"]="⪰",
+["HilbertSpace"]="ℋ",
+["ic"]="⁣",
+["niv"]="∋",
+["ccaron"]="č",
+["bigwedge"]="⋀",
+["olt"]="⧀",
+["ultri"]="◸",
+["ofr"]="𝔬",
+["exponentiale"]="ⅇ",
+["LeftCeiling"]="⌈",
+["UpEquilibrium"]="⥮",
+["vartriangleleft"]="⊲",
+["Supset"]="⋑",
+["aacute"]="á",
+["langle"]="⟨",
+["cuwed"]="⋏",
+["Ubreve"]="Ŭ",
+["fcy"]="ф",
+["lsim"]="≲",
+["vltri"]="⊲",
+["jfr"]="𝔧",
+["digamma"]="ϝ",
+["Eogon"]="Ę",
+["gnapprox"]="⪊",
+["Amacr"]="Ā",
+["ecirc"]="ê",
+["scnE"]="⪶",
+["thickapprox"]="≈",
+["ltdot"]="⋖",
+["malt"]="✠",
+["drcrop"]="⌌",
+["ifr"]="𝔦",
+["NotGreaterTilde"]="≵",
+["upharpoonright"]="↾",
+["wedge"]="∧",
+["notin"]="∉",
+["nrarr"]="↛",
+["LeftTeeArrow"]="↤",
+["cacute"]="ć",
+["dwangle"]="⦦",
+["frasl"]="⁄",
+["dzigrarr"]="⟿",
+["para"]="¶",
+["vnsup"]="⊃⃒",
+["spar"]="∥",
+["DotDot"]="⃜",
+["vnsub"]="⊂⃒",
+["suplarr"]="⥻",
+["preceq"]="⪯",
+["ffilig"]="ffi",
+["quot"]="\"",
+["nabla"]="∇",
+["weierp"]="℘",
+["searhk"]="⤥",
+["icy"]="и",
+["downdownarrows"]="⇊",
+["lang"]="⟨",
+["nleftrightarrow"]="↮",
+["hamilt"]="ℋ",
+["rpar"]=")",
+["iquest"]="¿",
+["bigstar"]="★",
+["biguplus"]="⨄",
+["dagger"]="†",
+["lrarr"]="⇆",
+["eacute"]="é",
+["gtdot"]="⋗",
+["jcy"]="й",
+["supdsub"]="⫘",
+["Prime"]="″",
+["intercal"]="⊺",
+["Aacute"]="Á",
+["prsim"]="≾",
+["nfr"]="𝔫",
+["ngeq"]="≱",
+["angmsdac"]="⦪",
+["DoubleLeftRightArrow"]="⇔",
+["Iogon"]="Į",
+["kappav"]="ϰ",
+["lsh"]="↰",
+["tfr"]="𝔱",
+["sect"]="§",
+["omega"]="ω",
+["gesles"]="⪔",
+["boxplus"]="⊞",
+["mfr"]="𝔪",
+["GreaterFullEqual"]="≧",
+["Exists"]="∃",
+["Acirc"]="Â",
+["nesim"]="≂̸",
+["gacute"]="ǵ",
+["dotplus"]="∔",
+["rrarr"]="⇉",
+["prnE"]="⪵",
+["qfr"]="𝔮",
+["triangleq"]="≜",
+["boxvH"]="╪",
+["dcy"]="д",
+["sup1"]="¹",
+["nequiv"]="≢",
+["longleftrightarrow"]="⟷",
+["Icirc"]="Î",
+["shchcy"]="щ",
+["raquo"]="»",
+["quest"]="?",
+["Euml"]="Ë",
+["leftthreetimes"]="⋋",
+["part"]="∂",
+["VeryThinSpace"]=" ",
+["Upsi"]="ϒ",
+["bprime"]="‵",
+["CenterDot"]="·",
+["Agrave"]="À",
+["NotHumpEqual"]="≏̸",
+["theta"]="θ",
+["Jcirc"]="Ĵ",
+["Ocirc"]="Ô",
+["rightharpoondown"]="⇁",
+["caps"]="∩︀",
+["DownLeftRightVector"]="⥐",
+["doteqdot"]="≑",
+["boxbox"]="⧉",
+["nvHarr"]="⤄",
+["timesd"]="⨰",
+["uharl"]="↿",
+["ouml"]="ö",
+["TSHcy"]="Ћ",
+["TRADE"]="™",
+["iecy"]="е",
+["Zeta"]="Ζ",
+["Scirc"]="Ŝ",
+["Lleftarrow"]="⇚",
+["bigoplus"]="⨁",
+["DoubleDownArrow"]="⇓",
+["nexists"]="∄",
+["lesdoto"]="⪁",
+["geq"]="≥",
+["nwnear"]="⤧",
+["Updownarrow"]="⇕",
+["andand"]="⩕",
+["nge"]="≱",
+["curvearrowleft"]="↶",
+["bkarow"]="⤍",
+["Ccaron"]="Č",
+["NegativeThinSpace"]="​",
+["nbump"]="≎̸",
+["ecir"]="≖",
+["imacr"]="ī",
+["Succeeds"]="≻",
+["supnE"]="⫌",
+["Auml"]="Ä",
+["rsh"]="↱",
+["approx"]="≈",
+["sdote"]="⩦",
+["SuchThat"]="∋",
+["Jsercy"]="Ј",
+["odsold"]="⦼",
+["Dcaron"]="Ď",
+["dfisht"]="⥿",
+["harrcir"]="⥈",
+["hArr"]="⇔",
+["leftrightarrow"]="↔",
+["geqslant"]="⩾",
+["boxDL"]="╗",
+["nsucceq"]="⪰̸",
+["leg"]="⋚",
+["parsl"]="⫽",
+["dd"]="ⅆ",
+["bump"]="≎",
+["GT"]=">",
+["DiacriticalGrave"]="`",
+["Ecaron"]="Ě",
+["cap"]="∩",
+["sext"]="✶",
+["LongRightArrow"]="⟶",
+["LeftDownVectorBar"]="⥙",
+["gg"]="≫",
+["dlcorn"]="⌞",
+["LeftVector"]="↼",
+["Gcirc"]="Ĝ",
+["LT"]="<",
+["ldquor"]="„",
+["subset"]="⊂",
+["tstrok"]="ŧ",
+["iacute"]="í",
+["Hcirc"]="Ĥ",
+["gtrapprox"]="⪆",
+["demptyv"]="⦱",
+["HumpDownHump"]="≎",
+["image"]="ℑ",
+["Icirc"]="Î",
+["boxHD"]="╦",
+["aogon"]="ą",
+["smid"]="∣",
+["uuml"]="ü",
+["lneq"]="⪇",
+["star"]="☆",
+["UpperRightArrow"]="↗",
+["larrpl"]="⤹",
+["backsimeq"]="⋍",
+["Itilde"]="Ĩ",
+["supne"]="⊋",
+["LeftDownTeeVector"]="⥡",
+["yicy"]="ї",
+["NotSucceeds"]="⊁",
+["KJcy"]="Ќ",
+["GreaterEqualLess"]="⋛",
+["nLt"]="≪⃒",
+["LeftRightArrow"]="↔",
+["Ubrcy"]="Ў",
+["LeftArrowRightArrow"]="⇆",
+["dArr"]="⇓",
+["epsilon"]="ε",
+["wr"]="≀",
+["percnt"]="%",
+["lesdot"]="⩿",
+["iiota"]="℩",
+["boxul"]="┘",
+["iquest"]="¿",
+["tbrk"]="⎴",
+["blacktriangle"]="▴",
+["real"]="ℜ",
+["origof"]="⊶",
+["yen"]="¥",
+["Intersection"]="⋂",
+["els"]="⪕",
+["cuesc"]="⋟",
+["mldr"]="…",
+["RightTee"]="⊢",
+["Gbreve"]="Ğ",
+["gimel"]="ℷ",
+["models"]="⊧",
+["uring"]="ů",
+["gtrsim"]="≳",
+["hairsp"]=" ",
+["iota"]="ι",
+["eacute"]="é",
+["diamond"]="⋄",
+["iuml"]="ï",
+["hybull"]="⁃",
+["Uarrocir"]="⥉",
+["lesdotor"]="⪃",
+["lceil"]="⌈",
+["lsquo"]="‘",
+["Uogon"]="Ų",
+["beta"]="β",
+["permil"]="‰",
+["measuredangle"]="∡",
+["eg"]="⪚",
+["CHcy"]="Ч",
+["bepsi"]="϶",
+["GreaterLess"]="≷",
+["Ucirc"]="Û",
+["ange"]="⦤",
+["Otimes"]="⨷",
+["simgE"]="⪠",
+["boxdl"]="┐",
+["vDash"]="⊨",
+["supedot"]="⫄",
+["xvee"]="⋁",
+["nisd"]="⋺",
+["oacute"]="ó",
+["llhard"]="⥫",
+["Rarrtl"]="⤖",
+["equest"]="≟",
+["abreve"]="ă",
+["rceil"]="⌉",
+["nle"]="≰",
+["frown"]="⌢",
+["Ocirc"]="Ô",
+["boxminus"]="⊟",
+["nvrArr"]="⤃",
+["TildeTilde"]="≈",
+["Congruent"]="≡",
+["Alpha"]="Α",
+["glE"]="⪒",
+["compfn"]="∘",
+["cularr"]="↶",
+["llcorner"]="⌞",
+["plusacir"]="⨣",
+["RightTeeArrow"]="↦",
+["supsub"]="⫔",
+["aring"]="å",
+["boxhd"]="┬",
+["boxvh"]="┼",
+["VerticalBar"]="∣",
+["AElig"]="Æ",
+["DiacriticalDot"]="˙",
+["pscr"]="𝓅",
+["triangleleft"]="◃",
+["supsetneqq"]="⫌",
+["trie"]="≜",
+["NotDoubleVerticalBar"]="∦",
+["RightUpTeeVector"]="⥜",
+["NotLessGreater"]="≸",
+["gopf"]="𝕘",
+["amalg"]="⨿",
+["nrtrie"]="⋭",
+["harrw"]="↭",
+["FilledVerySmallSquare"]="▪",
+["gtrarr"]="⥸",
+["DDotrahd"]="⤑",
+["UpArrowBar"]="⤒",
+["angle"]="∠",
+["gtquest"]="⩼",
+["Equilibrium"]="⇌",
+["qscr"]="𝓆",
+["RightArrow"]="→",
+["LongLeftRightArrow"]="⟷",
+["NotCongruent"]="≢",
+["target"]="⌖",
+["iexcl"]="¡",
+["vsupne"]="⊋︀",
+["dopf"]="𝕕",
+["RightTeeVector"]="⥛",
+["AElig"]="Æ",
+["lrm"]="‎",
+["boxUr"]="╙",
+["nscr"]="𝓃",
+["Phi"]="Φ",
+["erarr"]="⥱",
+["gesdot"]="⪀",
+["acE"]="∾̳",
+["iopf"]="𝕚",
+["NotSucceedsTilde"]="≿̸",
+["geqq"]="≧",
+["timesb"]="⊠",
+["nvdash"]="⊬",
+["fflig"]="ff",
+["Tilde"]="∼",
+["Ccirc"]="Ĉ",
+["boxDR"]="╔",
+["AMP"]="&",
+["Idot"]="İ",
+["Gcy"]="Г",
+["pluscir"]="⨢",
+["Longrightarrow"]="⟹",
+["UnderParenthesis"]="⏝",
+["sqsubseteq"]="⊑",
+["profsurf"]="⌓",
+["fopf"]="𝕗",
+["and"]="∧",
+["middot"]="·",
+["ltquest"]="⩻",
+["scpolint"]="⨓",
+["Rcaron"]="Ř",
+["DoubleLeftTee"]="⫤",
+["rangd"]="⦒",
+["crarr"]="↵",
+["Bcy"]="Б",
+["lscr"]="𝓁",
+["kopf"]="𝕜",
+["rharu"]="⇀",
+["map"]="↦",
+["LT"]="<",
+["Scaron"]="Š",
+["dscy"]="ѕ",
+["NegativeMediumSpace"]="​",
+["amp"]="&",
+["sfrown"]="⌢",
+["EmptySmallSquare"]="◻",
+["Acy"]="А",
+["cupcup"]="⩊",
+["Gdot"]="Ġ",
+["hopf"]="𝕙",
+["smtes"]="⪬︀",
+["lap"]="⪅",
+["boxV"]="║",
+["ltrie"]="⊴",
+["divide"]="÷",
+["larrb"]="⇤",
+["ijlig"]="ij",
+["Superset"]="⊃",
+["gtreqless"]="⋛",
+["Tcaron"]="Ť",
+["jscr"]="𝒿",
+["risingdotseq"]="≓",
+["DScy"]="Ѕ",
+["rdca"]="⤷",
+["emptyset"]="∅",
+["curvearrowright"]="↷",
+["nrarrw"]="↝̸",
+["angzarr"]="⍼",
+["frac35"]="⅗",
+["centerdot"]="·",
+["vsupnE"]="⫌︀",
+["Bumpeq"]="≎",
+["lnap"]="⪉",
+["gvertneqq"]="≩︀",
+["tcaron"]="ť",
+["Edot"]="Ė",
+["Union"]="⋃",
+["cupdot"]="⊍",
+["napE"]="⩰̸",
+["jopf"]="𝕛",
+["iff"]="⇔",
+["Aacute"]="Á",
+["NotTildeFullEqual"]="≇",
+["plussim"]="⨦",
+["Yacute"]="Ý",
+["Sup"]="⋑",
+["multimap"]="⊸",
+["nlE"]="≦̸",
+["aelig"]="æ",
+["ntgl"]="≹",
+["Dstrok"]="Đ",
+["frac14"]="¼",
+["minusd"]="∸",
+["Wedge"]="⋀",
+["Fcy"]="Ф",
+["xscr"]="𝓍",
+["igrave"]="ì",
+["ulcorn"]="⌜",
+["CapitalDifferentialD"]="ⅅ",
+["Star"]="⋆",
+["ExponentialE"]="ⅇ",
+["NotNestedLessLess"]="⪡̸",
+["Acirc"]="Â",
+["DoubleRightArrow"]="⇒",
+["radic"]="√",
+["twoheadleftarrow"]="↞",
+["Ecy"]="Э",
+["SquareSuperset"]="⊐",
+["leftleftarrows"]="⇇",
+["OElig"]="Œ",
+["Cacute"]="Ć",
+["bullet"]="•",
+["ngeqslant"]="⩾̸",
+["circlearrowright"]="↻",
+["CounterClockwiseContourIntegral"]="∳",
+["gnap"]="⪊",
+["Vdashl"]="⫦",
+["curlyeqprec"]="⋞",
+["gtlPar"]="⦕",
+["upsilon"]="υ",
+["aopf"]="𝕒",
+["prec"]="≺",
+["vscr"]="𝓋",
+["fjlig"]="fj",
+["colone"]="≔",
+["copy"]="©",
+["ordf"]="ª",
+["laquo"]="«",
+["bemptyv"]="⦰",
+["NotReverseElement"]="∌",
+["eogon"]="ę",
+["DoubleUpArrow"]="⇑",
+["Ecirc"]="Ê",
+["Rrightarrow"]="⇛",
+["Fouriertrf"]="ℱ",
+["wscr"]="𝓌",
+["lBarr"]="⤎",
+["plankv"]="ℏ",
+["Uacute"]="Ú",
+["cemptyv"]="⦲",
+["squarf"]="▪",
+["diamondsuit"]="♦",
+["rightharpoonup"]="⇀",
+["rtri"]="▹",
+["Jcy"]="Й",
+["copf"]="𝕔",
+["langd"]="⦑",
+["xlArr"]="⟸",
+["egrave"]="è",
+["Lcaron"]="Ľ",
+["range"]="⦥",
+["solbar"]="⌿",
+["veeeq"]="≚",
+["suphsol"]="⟉",
+["brvbar"]="¦",
+["Ecirc"]="Ê",
+["nmid"]="∤",
+["shortmid"]="∣",
+["hookleftarrow"]="↩",
+["GreaterEqual"]="≥",
+["Icy"]="И",
+["uscr"]="𝓊",
+["gel"]="⋛",
+["ocir"]="⊚",
+["dzcy"]="џ",
+["GT"]=">",
+["ordm"]="º",
+["chi"]="χ",
+["Implies"]="⇒",
+["Verbar"]="‖",
+["nsupseteqq"]="⫆̸",
+["Dcy"]="Д",
+["it"]="⁢",
+["Ncaron"]="Ň",
+["eopf"]="𝕖",
+["gtcir"]="⩺",
+["emsp13"]=" ",
+["nGt"]="≫⃒",
+["ges"]="⩾",
+["Dashv"]="⫤",
+["andslope"]="⩘",
+["bsolb"]="⧅",
+["sup1"]="¹",
+["bopf"]="𝕓",
+["iogon"]="į",
+["puncsp"]=" ",
+["sscr"]="𝓈",
+["SquareSupersetEqual"]="⊒",
+["neArr"]="⇗",
+["Ccedil"]="Ç",
+["mapstodown"]="↧",
+["aacute"]="á",
+["ForAll"]="∀",
+["lbbrk"]="❲",
+["leftrightarrows"]="⇆",
+["mDDot"]="∺",
+["sccue"]="≽",
+["otilde"]="õ",
+["NotSquareSuperset"]="⊐̸",
+["succapprox"]="⪸",
+["nrarrc"]="⤳̸",
+["wopf"]="𝕨",
+["nu"]="ν",
+["jcirc"]="ĵ",
+["rHar"]="⥤",
+["rdquo"]="”",
+["conint"]="∮",
+["ensp"]=" ",
+["les"]="⩽",
+["supseteq"]="⊇",
+["uparrow"]="↑",
+["Larr"]="↞",
+["breve"]="˘",
+["questeq"]="≟",
+["topf"]="𝕥",
+["Hfr"]="ℌ",
+["icirc"]="î",
+["sigmaf"]="ς",
+["nbsp"]=" ",
+["mho"]="℧",
+["dotsquare"]="⊡",
+["rarrsim"]="⥴",
+["strns"]="¯",
+["swArr"]="⇙",
+["leftrightharpoons"]="⇋",
+["THORN"]="Þ",
+["lsaquo"]="‹",
+["varnothing"]="∅",
+["Afr"]="𝔄",
+["Or"]="⩔",
+["subedot"]="⫃",
+["agrave"]="à",
+["fltns"]="▱",
+["apos"]="'",
+["Imacr"]="Ī",
+["Cap"]="⋒",
+["lbrace"]="{",
+["lrhar"]="⇋",
+["euml"]="ë",
+["scirc"]="ŝ",
+["NotPrecedes"]="⊀",
+["leftrightsquigarrow"]="↭",
+["female"]="♀",
+["urcrop"]="⌎",
+["Pr"]="⪻",
+["NotLessSlantEqual"]="⩽̸",
+["subsup"]="⫓",
+["GreaterTilde"]="≳",
+["timesbar"]="⨱",
+["Gg"]="⋙",
+["NotSquareSupersetEqual"]="⋣",
+["starf"]="★",
+["sdotb"]="⊡",
+["xlarr"]="⟵",
+["xharr"]="⟷",
+["NotHumpDownHump"]="≎̸",
+["andd"]="⩜",
+["nis"]="⋼",
+["esdot"]="≐",
+["ApplyFunction"]="⁡",
+["scnap"]="⪺",
+["Cup"]="⋓",
+["dollar"]="$",
+["ShortUpArrow"]="↑",
+["nsupseteq"]="⊉",
+["solb"]="⧄",
+["Lcedil"]="Ļ",
+["rharul"]="⥬",
+["xopf"]="𝕩",
+["mu"]="μ",
+["Ntilde"]="Ñ",
+["QUOT"]="\"",
+["varrho"]="ϱ",
+["zwj"]="‍",
+["trpezium"]="⏢",
+["dbkarow"]="⤏",
+["zscr"]="𝓏",
+["boxhU"]="╨",
+["circledcirc"]="⊚",
+["Efr"]="𝔈",
+["hcirc"]="ĥ",
+["Otilde"]="Õ",
+["subseteq"]="⊆",
+["swarhk"]="⤦",
+["nGtv"]="≫̸",
+["ddotseq"]="⩷",
+["cularrp"]="⤽",
+["RightArrowLeftArrow"]="⇄",
+["rx"]="℞",
+["mnplus"]="∓",
+["auml"]="ä",
+["uogon"]="ų",
+["notinvc"]="⋶",
+["Ffr"]="𝔉",
+["apid"]="≋",
+["lharul"]="⥪",
+["gcirc"]="ĝ",
+["ljcy"]="љ",
+["dharr"]="⇂",
+["phiv"]="ϕ",
+["Beta"]="Β",
+["kgreen"]="ĸ",
+["ne"]="≠",
+["oopf"]="𝕠",
+["top"]="⊤",
+["orslope"]="⩗",
+["succnsim"]="⋩",
+["erDot"]="≓",
+["OverBracket"]="⎴",
+["lesg"]="⋚︀",
+["eDDot"]="⩷",
+["nbsp"]=" ",
+["plusdo"]="∔",
+["Omacr"]="Ō",
+["ape"]="≊",
+["lbrke"]="⦋",
+["zwnj"]="‌",
+["straightphi"]="ϕ",
+["NotGreaterGreater"]="≫̸",
+["cong"]="≅",
+["lopf"]="𝕝",
+["ntlg"]="≸",
+["iiiint"]="⨌",
+["nshortmid"]="∤",
+["Darr"]="↡",
+["LeftAngleBracket"]="⟨",
+["itilde"]="ĩ",
+["triangleright"]="▹",
+["mcomma"]="⨩",
+["ETH"]="Ð",
+["roang"]="⟭",
+["apE"]="⩰",
+["reals"]="ℝ",
+["qopf"]="𝕢",
+["nsub"]="⊄",
+["mid"]="∣",
+["NotSucceedsEqual"]="⪰̸",
+["szlig"]="ß",
+["uwangle"]="⦧",
+["Kappa"]="Κ",
+["rotimes"]="⨵",
+["notniva"]="∌",
+["xutri"]="△",
+["Iota"]="Ι",
+["UnderBar"]="_",
+["leqq"]="≦",
+["notinva"]="∉",
+["nopf"]="𝕟",
+["ubrcy"]="ў",
+["urcorn"]="⌝",
+["luruhar"]="⥦",
+["nLtv"]="≪̸",
+["angsph"]="∢",
+["minusb"]="⊟",
+["nesear"]="⤨",
+["bot"]="⊥",
+["Abreve"]="Ă",
+["equiv"]="≡",
+["EmptyVerySmallSquare"]="▫",
+["bigtriangledown"]="▽",
+["nvlt"]="<⃒",
+["cylcty"]="⌭",
+["PartialD"]="∂",
+["ni"]="∋",
+["leftarrowtail"]="↢",
+["ClockwiseContourIntegral"]="∲",
+["divonx"]="⋇",
+["rsaquo"]="›",
+["bsime"]="⋍",
+["popf"]="𝕡",
+["quaternions"]="ℍ",
+["boxhu"]="┴",
+["disin"]="⋲",
+["Tcedil"]="Ţ",
+["angmsdaa"]="⦨",
+["npre"]="⪯̸",
+["gesl"]="⋛︀",
+["ldquo"]="“",
+["between"]="≬",
+["wedgeq"]="≙",
+["in"]="∈",
+["pi"]="π",
+["acute"]="´",
+["uopf"]="𝕦",
+["succnapprox"]="⪺",
+["nleqq"]="≦̸",
+["ENG"]="Ŋ",
+["NotEqualTilde"]="≂̸",
+["circlearrowleft"]="↺",
+["rtrie"]="⊵",
+["integers"]="ℤ",
+["frac13"]="⅓",
+["gEl"]="⪌",
+["ropf"]="𝕣",
+["Sigma"]="Σ",
+["ocirc"]="ô",
+["DownRightTeeVector"]="⥟",
+["rfloor"]="⌋",
+["SHCHcy"]="Щ",
+["Uuml"]="Ü",
+["llarr"]="⇇",
+["efDot"]="≒",
+["NestedLessLess"]="≪",
+["SHcy"]="Ш",
+["NotCupCap"]="≭",
+["xdtri"]="▽",
+["curlyvee"]="⋎",
+["downharpoonleft"]="⇃",
+["Dopf"]="𝔻",
+["napos"]="ʼn",
+["Auml"]="Ä",
+["profline"]="⌒",
+["Ycirc"]="Ŷ",
+["RightDownTeeVector"]="⥝",
+["rAtail"]="⤜",
+["osol"]="⊘",
+["atilde"]="ã",
+["Kscr"]="𝒦",
+["ang"]="∠",
+["natur"]="♮",
+["Gopf"]="𝔾",
+["AMP"]="&",
+["DoubleDot"]="¨",
+["Ouml"]="Ö",
+["dlcrop"]="⌍",
+["bsolhsub"]="⟈",
+["NestedGreaterGreater"]="≫",
+["prcue"]="≼",
+["Uarr"]="↟",
+["dHar"]="⥥",
+["ssmile"]="⌣",
+["eqslantgtr"]="⪖",
+["glj"]="⪤",
+["hstrok"]="ħ",
+["lesssim"]="≲",
+["lowast"]="∗",
+["cirmid"]="⫯",
+["lates"]="⪭︀",
+["fnof"]="ƒ",
+["ord"]="⩝",
+["rthree"]="⋌",
+["rcub"]="}",
+["Coproduct"]="∐",
+["curren"]="¤",
+["Mscr"]="ℳ",
+["Iopf"]="𝕀",
+["vprop"]="∝",
+["andv"]="⩚",
+["vrtri"]="⊳",
+["yacute"]="ý",
+["tilde"]="˜",
+["numsp"]=" ",
+["acd"]="∿",
+["blk34"]="▓",
+["Pscr"]="𝒫",
+["ReverseEquilibrium"]="⇋",
+["diams"]="♦",
+["Hopf"]="ℍ",
+["veebar"]="⊻",
+["Euml"]="Ë",
+["intprod"]="⨼",
+["macr"]="¯",
+["Oscr"]="𝒪",
+["nvle"]="≤⃒",
+["odblac"]="ő",
+["eqcirc"]="≖",
+["Kopf"]="𝕂",
+["bumpeq"]="≏",
+["twoheadrightarrow"]="↠",
+["apacir"]="⩯",
+["elinters"]="⏧",
+["forall"]="∀",
+["ofcir"]="⦿",
+["dstrok"]="đ",
+["simne"]="≆",
+["mopf"]="𝕞",
+["RightTriangleBar"]="⧐",
+["Jopf"]="𝕁",
+["parsim"]="⫳",
+["pm"]="±",
+["boxh"]="─",
+["sqsupseteq"]="⊒",
+["eplus"]="⩱",
+["xi"]="ξ",
+["Diamond"]="⋄",
+["Wcirc"]="Ŵ",
+["ReverseUpEquilibrium"]="⥯",
+["ovbar"]="⌽",
+["rho"]="ρ",
+["Map"]="⤅",
+["Qscr"]="𝒬",
+["lhblk"]="▄",
+["Igrave"]="Ì",
+["LeftTriangle"]="⊲",
+["LeftVectorBar"]="⥒",
+["late"]="⪭",
+["cups"]="∪︀",
+["lAtail"]="⤛",
+["RightTriangle"]="⊳",
+["Tscr"]="𝒯",
+["capbrcup"]="⩉",
+["verbar"]="|",
+["leqslant"]="⩽",
+["DownBreve"]="̑",
+["Laplacetrf"]="ℒ",
+["nlsim"]="≴",
+["dblac"]="˝",
+["empty"]="∅",
+["bowtie"]="⋈",
+["subdot"]="⪽",
+["oror"]="⩖",
+["LeftUpDownVector"]="⥑",
+["varkappa"]="ϰ",
+["kjcy"]="ќ",
+["iukcy"]="і",
+["angmsdag"]="⦮",
+["Sscr"]="𝒮",
+["frac34"]="¾",
+["acirc"]="â",
+["eqslantless"]="⪕",
+["YUcy"]="Ю",
+["swarr"]="↙",
+["DownArrow"]="↓",
+["Cdot"]="Ċ",
+["RuleDelayed"]="⧴",
+["UnderBracket"]="⎵",
+["sqcaps"]="⊓︀",
+["bbrktbrk"]="⎶",
+["barvee"]="⊽",
+["jukcy"]="є",
+["middot"]="·",
+["Psi"]="Ψ",
+["DifferentialD"]="ⅆ",
+["ordf"]="ª",
+["yucy"]="ю",
+["int"]="∫",
+["maltese"]="✠",
+["lHar"]="⥢",
+["NotLessLess"]="≪̸",
+["filig"]="fi",
+["af"]="⁡",
+["duarr"]="⇵",
+["boxVR"]="╠",
+["elsdot"]="⪗",
+["Egrave"]="È",
+["RightDownVector"]="⇂",
+["bernou"]="ℬ",
+["szlig"]="ß",
+["Ncedil"]="Ņ",
+["Aopf"]="𝔸",
+["Ccedil"]="Ç",
+["DoubleLongLeftArrow"]="⟸",
+["Xscr"]="𝒳",
+["Mellintrf"]="ℳ",
+["ccedil"]="ç",
+["NotRightTriangleEqual"]="⋭",
+["lotimes"]="⨴",
+["gjcy"]="ѓ",
+["boxVr"]="╟",
+["cuepr"]="⋞",
+["DiacriticalTilde"]="˜",
+["nwarr"]="↖",
+["plusb"]="⊞",
+["Iuml"]="Ï",
+["Gt"]="≫",
+["boxuL"]="╛",
+["gsiml"]="⪐",
+["vee"]="∨",
+["NotGreaterEqual"]="≱",
+["isinv"]="∈",
+["eng"]="ŋ",
+["lessdot"]="⋖",
+["olcross"]="⦻",
+["pound"]="£",
+["RightUpVector"]="↾",
+["Chi"]="Χ",
+["num"]="#",
+["Because"]="∵",
+["udarr"]="⇅",
+["Copf"]="ℂ",
+["precnsim"]="⋨",
+["Bernoullis"]="ℬ",
+["angmsdah"]="⦯",
+["LeftFloor"]="⌊",
+["boxvR"]="╞",
+["plusmn"]="±",
+["ContourIntegral"]="∮",
+["notinE"]="⋹̸",
+["nwarhk"]="⤣",
+["gtrless"]="≷",
+["complexes"]="ℂ",
+["dashv"]="⊣",
+["SubsetEqual"]="⊆",
+["NotVerticalBar"]="∤",
+["Yscr"]="𝒴",
+["RightCeiling"]="⌉",
+["Rarr"]="↠",
+["vartheta"]="ϑ",
+["PrecedesSlantEqual"]="≼",
+["boxUR"]="╚",
+["ntilde"]="ñ",
+["boxVL"]="╣",
+["bigvee"]="⋁",
+["aelig"]="æ",
+["angrtvbd"]="⦝",
+["scap"]="⪸",
+["Topf"]="𝕋",
+["hfr"]="𝔥",
+["Nu"]="Ν",
+["Downarrow"]="⇓",
+["rsquor"]="’",
+["circledS"]="Ⓢ",
+["ntilde"]="ñ",
+["circledast"]="⊛",
+["eqsim"]="≂",
+["kcy"]="к",
+["ldrdhar"]="⥧",
+["nLl"]="⋘̸",
+["hyphen"]="‐",
+["Conint"]="∯",
+["xsqcup"]="⨆",
+["asympeq"]="≍",
+["Wopf"]="𝕎",
+["gfr"]="𝔤",
+["larr"]="←",
+["ncy"]="н",
+["iacute"]="í",
+["gE"]="≧",
+["gesdoto"]="⪂",
+["tshcy"]="ћ",
+["IEcy"]="Е",
+["NotGreater"]="≯",
+["Vbar"]="⫫",
+["Vopf"]="𝕍",
+["UpArrowDownArrow"]="⇅",
+["mp"]="∓",
+["RightDownVectorBar"]="⥕",
+["exist"]="∃",
+["frac38"]="⅜",
+["zdot"]="ż",
+["eparsl"]="⧣",
+["lacute"]="ĺ",
+["zopf"]="𝕫",
+["zigrarr"]="⇝",
+["zhcy"]="ж",
+["zeetrf"]="ℨ",
+["vangrt"]="⦜",
+["Breve"]="˘",
+["odot"]="⊙",
+["blacklozenge"]="⧫",
+["NotRightTriangle"]="⋫",
+["yuml"]="ÿ",
+["homtht"]="∻",
+["yscr"]="𝓎",
+["yopf"]="𝕪",
+["afr"]="𝔞",
+["Yopf"]="𝕐",
+["ThinSpace"]=" ",
+["yfr"]="𝔶",
+["larrlp"]="↫",
+["yen"]="¥",
+["nwarrow"]="↖",
+["supmult"]="⫂",
+["nearrow"]="↗",
+["bigsqcup"]="⨆",
+["yacy"]="я",
+["lcy"]="л",
+["ii"]="ⅈ",
+["seswar"]="⤩",
+["yacute"]="ý",
+["lArr"]="⇐",
+["Uparrow"]="⇑",
+["xwedge"]="⋀",
+["xrarr"]="⟶",
+["xrArr"]="⟹",
+["oast"]="⊛",
+["xoplus"]="⨁",
+["ImaginaryI"]="ⅈ",
+["xnis"]="⋻",
+["xhArr"]="⟺",
+["xcirc"]="◯",
+["xcap"]="⋂",
+["wreath"]="≀",
+["wp"]="℘",
+["lfr"]="𝔩",
+["wedbar"]="⩟",
+["psi"]="ψ",
+["Xopf"]="𝕏",
+["vzigzag"]="⦚",
+["realpart"]="ℜ",
+["vsubne"]="⊊︀",
+["DoubleLongLeftRightArrow"]="⟺",
+["nsqsube"]="⋢",
+["varpropto"]="∝",
+["npreceq"]="⪯̸",
+["vopf"]="𝕧",
+["vert"]="|",
+["vellip"]="⋮",
+["vdash"]="⊢",
+["hkswarow"]="⤦",
+["sqsube"]="⊑",
+["tdot"]="⃛",
+["leq"]="≤",
+["nacute"]="ń",
+["succcurlyeq"]="≽",
+["vartriangleright"]="⊳",
+["Re"]="ℜ",
+["varsupsetneqq"]="⫌︀",
+["dsol"]="⧶",
+["Tau"]="Τ",
+["rsqb"]="]",
+["varsupsetneq"]="⊋︀",
+["varsubsetneq"]="⊊︀",
+["varsigma"]="ς",
+["expectation"]="ℰ",
+["kfr"]="𝔨",
+["varr"]="↕",
+["varpi"]="ϖ",
+["varphi"]="ϕ",
+["CloseCurlyDoubleQuote"]="”",
+["varepsilon"]="ϵ",
+["zcy"]="з",
+["lt"]="<",
+["vBarv"]="⫩",
+["vBar"]="⫨",
+["larrfs"]="⤝",
+["lthree"]="⋋",
+["nsimeq"]="≄",
+["div"]="÷",
+["Fopf"]="𝔽",
+["rbrack"]="]",
+["searrow"]="↘",
+["lcedil"]="ļ",
+["uuarr"]="⇈",
+["utrif"]="▴",
+["utilde"]="ũ",
+["urtri"]="◹",
+["mapstoleft"]="↤",
+["olcir"]="⦾",
+["upsih"]="ϒ",
+["upsi"]="υ",
+["curlywedge"]="⋏",
+["uplus"]="⊎",
+["upharpoonleft"]="↿",
+["updownarrow"]="↕",
+["uml"]="¨",
+["cirscir"]="⧂",
+["ffr"]="𝔣",
+["uml"]="¨",
+["epsiv"]="ϵ",
+["umacr"]="ū",
+["ulcrop"]="⌏",
+["ulcorner"]="⌜",
+["dtrif"]="▾",
+["uhblk"]="▀",
+["uharr"]="↾",
+["ugrave"]="ù",
+["ufr"]="𝔲",
+["ufisht"]="⥾",
+["mcy"]="м",
+["ngE"]="≧̸",
+["udhar"]="⥮",
+["iinfin"]="⧜",
+["kcedil"]="ķ",
+["natural"]="♮",
+["udblac"]="ű",
+["Gamma"]="Γ",
+["sol"]="/",
+["ucirc"]="û",
+["dtdot"]="⋱",
+["lsimg"]="⪏",
+["Gfr"]="𝔊",
+["nearhk"]="⤤",
+["NotTildeTilde"]="≉",
+["frac15"]="⅕",
+["uarr"]="↑",
+["succeq"]="⪰",
+["COPY"]="©",
+["uacute"]="ú",
+["uHar"]="⥣",
+["efr"]="𝔢",
+["NotGreaterSlantEqual"]="⩾̸",
+["backsim"]="∽",
+["mlcp"]="⫛",
+["Mu"]="Μ",
+["tscy"]="ц",
+["NotExists"]="∄",
+["tscr"]="𝓉",
+["ssetmn"]="∖",
+["triplus"]="⨹",
+["tridot"]="◬",
+["trianglelefteq"]="⊴",
+["orderof"]="ℴ",
+["thetasym"]="ϑ",
+["emptyv"]="∅",
+["emacr"]="ē",
+["trade"]="™",
+["spades"]="♠",
+["ncedil"]="ņ",
+["tprime"]="‴",
+["NotGreaterFullEqual"]="≧̸",
+["topbot"]="⌶",
+["ctdot"]="⋯",
+["sqsubset"]="⊏",
+["comma"]=",",
+["Mcy"]="М",
+["notni"]="∌",
+["OpenCurlyDoubleQuote"]="“",
+["sup2"]="²",
+["ascr"]="𝒶",
+["UnionPlus"]="⊎",
+["scy"]="с",
+["gesdotol"]="⪄",
+["KHcy"]="Х",
+["frac45"]="⅘",
+["larrsim"]="⥳",
+["COPY"]="©",
+["comp"]="∁",
+["Lopf"]="𝕃",
+["thorn"]="þ",
+["prE"]="⪳",
+["Eta"]="Η",
+["thksim"]="∼",
+["dscr"]="𝒹",
+["thinsp"]=" ",
+["ucirc"]="û",
+["clubsuit"]="♣",
+["LeftDownVector"]="⇃",
+["oscr"]="ℴ",
+["thetav"]="ϑ",
+["TildeFullEqual"]="≅",
+["triangle"]="▵",
+["smashp"]="⨳",
+["subsetneqq"]="⫋",
+["ecirc"]="ê",
+["therefore"]="∴",
+["Theta"]="Θ",
+["plusdu"]="⨥",
+["Assign"]="≔",
+["telrec"]="⌕",
+["UpperLeftArrow"]="↖",
+["boxUL"]="╝",
+["planck"]="ℏ",
+["rarrc"]="⤳",
+["UpDownArrow"]="↕",
+["incare"]="℅",
+["vcy"]="в",
+["Oopf"]="𝕆",
+["cwint"]="∱",
+["Kcy"]="К",
+["PrecedesEqual"]="⪯",
+["coloneq"]="≔",
+["duhar"]="⥯",
+["NewLine"]="\n",
+["tau"]="τ",
+["supE"]="⫆",
+["downarrow"]="↓",
+["half"]="½",
+["cscr"]="𝒸",
+["omacr"]="ō",
+["SquareSubset"]="⊏",
+["downharpoonright"]="⇂",
+["Uopf"]="𝕌",
+["swnwar"]="⤪",
+["swarrow"]="↙",
+["nGg"]="⋙̸",
+["imped"]="Ƶ",
+["diam"]="⋄",
+["gla"]="⪥",
+["horbar"]="―",
+["eth"]="ð",
+["supsup"]="⫖",
+["hslash"]="ℏ",
+["circeq"]="≗",
+["darr"]="↓",
+["supsim"]="⫈",
+["supset"]="⊃",
+["supplus"]="⫀",
+["ecolon"]="≕",
+["csube"]="⫑",
+["Nopf"]="ℕ",
+["RoundImplies"]="⥰",
+["ycy"]="ы",
+["suphsub"]="⫗",
+["SucceedsSlantEqual"]="≽",
+["capand"]="⩄",
+["fscr"]="𝒻",
+["supdot"]="⪾",
+["Bfr"]="𝔅",
+["NotLeftTriangle"]="⋪",
+["RightArrowBar"]="⇥",
+["boxVH"]="╬",
+["raquo"]="»",
+["rightleftarrows"]="⇄",
+["Cross"]="⨯",
+["egsdot"]="⪘",
+["nvDash"]="⊭",
+["RBarr"]="⤐",
+["sup3"]="³",
+["cuvee"]="⋎",
+["sup2"]="²",
+["angst"]="Å",
+["backcong"]="≌",
+["oelig"]="œ",
+["Kfr"]="𝔎",
+["boxVh"]="╫",
+["Zfr"]="ℨ",
+["sung"]="♪",
+["tcy"]="т",
+["nshortparallel"]="∦",
+["Qopf"]="ℚ",
+["sum"]="∑",
+["succsim"]="≿",
+["rmoust"]="⎱",
+["nleftarrow"]="↚",
+["cup"]="∪",
+["vsubnE"]="⫋︀",
+["copy"]="©",
+["Vdash"]="⊩",
+["Kcedil"]="Ķ",
+["escr"]="ℯ",
+["gnE"]="≩",
+["uacute"]="ú",
+["napid"]="≋̸",
+["le"]="≤",
+["DD"]="ⅅ",
+["rarrlp"]="↬",
+["Lfr"]="𝔏",
+["subsim"]="⫇",
+["ZHcy"]="Ж",
+["subseteqq"]="⫅",
+["rcedil"]="ŗ",
+["napprox"]="≉",
+["laquo"]="«",
+["njcy"]="њ",
+["Colone"]="⩴",
+["Nacute"]="Ń",
+["Yfr"]="𝔜",
+["aring"]="å",
+["mapsto"]="↦",
+["brvbar"]="¦",
+["Popf"]="ℙ",
+["sigma"]="σ",
+["subrarr"]="⥹",
+["cire"]="≗",
+["subplus"]="⪿",
+["dfr"]="𝔡",
+["subne"]="⊊",
+["hscr"]="𝒽",
+["lgE"]="⪑",
+["racute"]="ŕ",
+["LeftRightVector"]="⥎",
+["subnE"]="⫋",
+["isinE"]="⋹",
+["boxdR"]="╒",
+["CupCap"]="≍",
+["ncongdot"]="⩭̸",
+["bigcap"]="⋂",
+["nsce"]="⪰̸",
+["submult"]="⫁",
+["NotLessEqual"]="≰",
+["piv"]="ϖ",
+["mstpos"]="∾",
+["sub"]="⊂",
+["cent"]="¢",
+["capcup"]="⩇",
+["blacksquare"]="▪",
+["Oacute"]="Ó",
+["circledR"]="®",
+["Atilde"]="Ã",
+["tritime"]="⨻",
+["notnivb"]="⋾",
+["Sopf"]="𝕊",
+["Sum"]="∑",
+["hoarr"]="⇿",
+["Scedil"]="Ş",
+["square"]="□",
+["cfr"]="𝔠",
+["divide"]="÷",
+["sacute"]="ś",
+["NotLessTilde"]="≴",
+["gscr"]="ℊ",
+["ll"]="≪",
+["isins"]="⋴",
+["PrecedesTilde"]="≾",
+["sqsupset"]="⊐",
+["OverBrace"]="⏞",
+["Epsilon"]="Ε",
+["sqsupe"]="⊒",
+["iprod"]="⨼",
+["dash"]="‐",
+["sqsup"]="⊐",
+["nsccue"]="⋡",
+["infin"]="∞",
+["frac25"]="⅖",
+["backepsilon"]="϶",
+["robrk"]="⟧",
+["harr"]="↔",
+["ogt"]="⧁",
+["sopf"]="𝕤",
+["larrhk"]="↩",
+["boxvl"]="┤",
+["tcedil"]="ţ",
+["cwconint"]="∲",
+["lfloor"]="⌊",
+["ucy"]="у",
+["CloseCurlyQuote"]="’",
+["lsquor"]="‚",
+["softcy"]="ь",
+["smte"]="⪬",
+["smt"]="⪪",
+["isindot"]="⋵",
+["Pi"]="Π",
+["lnE"]="≨",
+["caret"]="⁁",
+["TildeEqual"]="≃",
+["delta"]="δ",
+["euro"]="€",
+["angrtvb"]="⊾",
+["Escr"]="ℰ",
+["Ucirc"]="Û",
+["rarrap"]="⥵",
+["smile"]="⌣",
+["ccupssm"]="⩐",
+["LeftArrow"]="←",
+["frac12"]="½",
+["smallsetminus"]="∖",
+["Zscr"]="𝒵",
+["angrt"]="∟",
+["lurdshar"]="⥊",
+["simrarr"]="⥲",
+["boxUl"]="╜",
+["simplus"]="⨤",
+["scedil"]="ş",
+["Eacute"]="É",
+["ast"]="*",
+["simg"]="⪞",
+["Aring"]="Å",
+["yuml"]="ÿ",
+["bsemi"]="⁏",
+["Omicron"]="Ο",
+["simdot"]="⩪",
+["sim"]="∼",
+["OverBar"]="‾",
+["intlarhk"]="⨗",
+["sfr"]="𝔰",
+["boxDl"]="╖",
+["Cconint"]="∰",
+["ncaron"]="ň",
+["Lmidot"]="Ŀ",
+["shy"]="­",
+["LeftTriangleEqual"]="⊴",
+["esim"]="≂",
+["THORN"]="Þ",
+["REG"]="®",
+["xodot"]="⨀",
+["ddarr"]="⇊",
+["setmn"]="∖",
+["Ugrave"]="Ù",
+["setminus"]="∖",
+["dotminus"]="∸",
+["semi"]=";",
+["sect"]="§",
+["ncong"]="≇",
+["bNot"]="⫭",
+["Rho"]="Ρ",
+["GJcy"]="Ѓ",
+["boxhD"]="╥",
+["searr"]="↘",
+["Del"]="∇",
+["auml"]="ä",
+["Cfr"]="ℭ",
+["VDash"]="⊫",
+["seArr"]="⇘",
+["ncap"]="⩃",
+["Product"]="∏",
+["sdot"]="⋅",
+["frac58"]="⅝",
+["zcaron"]="ž",
+["DZcy"]="Џ",
+["ltlarr"]="⥶",
+["scsim"]="≿",
+["VerticalTilde"]="≀",
+["squf"]="▪",
+["dharl"]="⇃",
+["iexcl"]="¡",
+["bumpE"]="⪮",
+["scnsim"]="⋩",
+["drcorn"]="⌟",
+["Xfr"]="𝔛",
+["nsube"]="⊈",
+["Dfr"]="𝔇",
+["nsmid"]="∤",
+["not"]="¬",
+["ShortRightArrow"]="→",
+["hookrightarrow"]="↪",
+["par"]="∥",
+["sc"]="≻",
+["rtrif"]="▸",
+["tosa"]="⤩",
+["acirc"]="â",
+["gtcc"]="⪧",
+["DJcy"]="Ђ",
+["NotLeftTriangleEqual"]="⋬",
+["bigcirc"]="◯",
+["rbrksld"]="⦎",
+["angmsdab"]="⦩",
+["Aring"]="Å",
+["rlm"]="‏",
+["Therefore"]="∴",
+["lambda"]="λ",
+["LowerRightArrow"]="↘",
+["asymp"]="≈",
+["rscr"]="𝓇",
+["ouml"]="ö",
+["boxDr"]="╓",
+["divideontimes"]="⋇",
+["rppolint"]="⨒",
+["oacute"]="ó",
+["Rcedil"]="Ŗ",
+["roplus"]="⨮",
+["DownLeftVectorBar"]="⥖",
+["Wfr"]="𝔚",
+["lesseqgtr"]="⋚",
+["ropar"]="⦆",
+["bnot"]="⌐",
+["Integral"]="∫",
+["boxdr"]="┌",
+["LeftTee"]="⊣",
+["hercon"]="⊹",
+["rnmid"]="⫮",
+["gvnE"]="≩︀",
+["bdquo"]="„",
+["Zacute"]="Ź",
+["Lscr"]="ℒ",
+["ring"]="˚",
+["supseteqq"]="⫆",
+["kscr"]="𝓀",
+["approxeq"]="≊",
+["ntriangleright"]="⋫",
+["lessgtr"]="≶",
+["prurel"]="⊰",
+["rightleftharpoons"]="⇌",
+["pitchfork"]="⋔",
+["ltrPar"]="⦖",
+["NotSubset"]="⊂⃒",
+["Yacute"]="Ý",
+["eta"]="η",
+["Rfr"]="ℜ",
+["UpTee"]="⊥",
+["rfisht"]="⥽",
+["HumpEqual"]="≏",
+["NotLess"]="≮",
+["sbquo"]="‚",
+["pointint"]="⨕",
+["ycirc"]="ŷ",
+["lescc"]="⪨",
+["looparrowright"]="↬",
+["cross"]="✗",
+["grave"]="`",
+["rdquor"]="”",
+["blacktriangleleft"]="◂",
+["rdldhar"]="⥩",
+["Nscr"]="𝒩",
+["atilde"]="ã",
+["lsqb"]="[",
+["lbrack"]="[",
+["Lambda"]="Λ",
+["rbrace"]="}",
+["times"]="×",
+["deg"]="°",
+["uuml"]="ü",
+["MediumSpace"]=" ",
+["lAarr"]="⇚",
+["bull"]="•",
+["daleth"]="ℸ",
+["ccirc"]="ĉ",
+["capcap"]="⩋",
+["fllig"]="fl",
+["Qfr"]="𝔔",
+["lopar"]="⦅",
+["nspar"]="∦",
+["RightTriangleEqual"]="⊵",
+["rbrke"]="⦌",
+["NotPrecedesSlantEqual"]="⋠",
+["rbbrk"]="❳",
+["hbar"]="ℏ",
+["rbarr"]="⤍",
+["rationals"]="ℚ",
+["Oslash"]="Ø",
+["frac14"]="¼",
+["ratio"]="∶",
+["ratail"]="⤚",
+["rarrw"]="↝",
+["Gammad"]="Ϝ",
+["rarrhk"]="↪",
+["rarrfs"]="⤞",
+["lparlt"]="⦓",
+["rarr"]="→",
+["Backslash"]="∖",
+["zacute"]="ź",
+["euml"]="ë",
+["GreaterGreater"]="⪢",
+["NotTilde"]="≁",
+["rang"]="⟩",
+["deg"]="°",
+["rArr"]="⇒",
+["congdot"]="⩭",
+["rAarr"]="⇛",
+["roarr"]="⇾",
+["emsp14"]=" ",
+["quot"]="\"",
+["isinsv"]="⋳",
+["quatint"]="⨖",
+["bcy"]="б",
+["qprime"]="⁗",
+["race"]="∽̱",
+["tint"]="∭",
+["egs"]="⪖",
+["Proportion"]="∷",
+["aleph"]="ℵ",
+["wcirc"]="ŵ",
+["prime"]="′",
+["barwedge"]="⌅",
+["precsim"]="≾",
+["frac18"]="⅛",
+["nsubseteqq"]="⫅̸",
+["primes"]="ℙ",
+["csup"]="⫐",
+["boxuR"]="╘",
+["lmidot"]="ŀ",
+["squ"]="□",
+["Oslash"]="Ø",
+["SOFTcy"]="Ь",
+["nvinfin"]="⧞",
+["precneqq"]="⪵",
+["precnapprox"]="⪹",
+["SupersetEqual"]="⊇",
+["angmsdaf"]="⦭",
+["preccurlyeq"]="≼",
+["precapprox"]="⪷",
+["amp"]="&",
+["cudarrr"]="⤵",
+["Bscr"]="ℬ",
+["circleddash"]="⊝",
+["pr"]="≺",
+["emsp"]=" ",
+["DoubleLongRightArrow"]="⟹",
+["cupcap"]="⩆",
+["plustwo"]="⨧",
+["numero"]="№",
+["ddagger"]="‡",
+["die"]="¨",
+["vArr"]="⇕",
+["Ograve"]="Ò",
+["LeftArrowBar"]="⇤",
+["period"]=".",
+["InvisibleTimes"]="⁢",
+["NoBreak"]="⁠",
+["ap"]="≈",
+["rtriltri"]="⧎",
+["curarrm"]="⤼",
+["planckh"]="ℎ",
+["Leftarrow"]="⇐",
+["Not"]="⫬",
+["RightDoubleBracket"]="⟧",
+["Xi"]="Ξ",
+["phone"]="☎",
+["blk12"]="▒",
+["boxvr"]="├",
+["intcal"]="⊺",
+["gneqq"]="≩",
+["Hacek"]="ˇ",
+["bscr"]="𝒷",
+["pfr"]="𝔭",
+["pertenk"]="‱",
+["perp"]="⊥",
+["npart"]="∂̸",
+["Odblac"]="Ő",
+["Vfr"]="𝔙",
+["Ocy"]="О",
+["rhard"]="⇁",
+["Vscr"]="𝒱",
+["Square"]="□",
+["hearts"]="♥",
+["NotSubsetEqual"]="⊈",
+["uArr"]="⇑",
+["nrArr"]="⇏",
+["otimesas"]="⨶",
+["ggg"]="⋙",
+["otilde"]="õ",
+["ee"]="ⅇ",
+["NotElement"]="∉",
+["VerticalLine"]="|",
+["orv"]="⩛",
+["Umacr"]="Ū",
+["boxHU"]="╩",
+["Mopf"]="𝕄",
+["Uscr"]="𝒰",
+["EqualTilde"]="≂",
+["Pcy"]="П",
+["ordm"]="º",
+["DoubleContourIntegral"]="∯",
+["triangledown"]="▿",
+["or"]="∨",
+["DownTee"]="⊤",
+["frac56"]="⅚",
+["ominus"]="⊖",
+["oslash"]="ø",
+["omid"]="⦶",
+["para"]="¶",
+["gescc"]="⪩",
+["Ufr"]="𝔘",
+["omicron"]="ο",
+["doteq"]="≐",
+["mumap"]="⊸",
+["urcorner"]="⌝",
+["olarr"]="↺",
+["DotEqual"]="≐",
+["ogon"]="˛",
+["odiv"]="⨸",
+["ltcc"]="⪦",
+["nparsl"]="⫽⃥",
+["Colon"]="∷",
+["REG"]="®",
+["cirE"]="⧃",
+["laemptyv"]="⦴",
+["Igrave"]="Ì",
+["rdsh"]="↳",
+["nsucc"]="⊁",
+["xotime"]="⨂",
+["Wscr"]="𝒲",
+["ShortDownArrow"]="↓",
+["copysr"]="℗",
+["Longleftarrow"]="⟸",
+["oS"]="Ⓢ",
+["Yuml"]="Ÿ",
+["becaus"]="∵",
+["Rightarrow"]="⇒",
+["nwArr"]="⇖",
+["nvsim"]="∼⃒",
+["SquareIntersection"]="⊓",
+["Barv"]="⫧",
+["nvrtrie"]="⊵⃒",
+["nvltrie"]="⊴⃒",
+["sube"]="⊆",
+["boxHd"]="╤",
+["Iukcy"]="І",
+["NotSquareSubsetEqual"]="⋢",
+["DownRightVectorBar"]="⥗",
+["Jscr"]="𝒥",
+["LeftTriangleBar"]="⧏",
+["blacktriangleright"]="▸",
+["ntrianglerighteq"]="⋭",
+["ntrianglelefteq"]="⋬",
+["Bopf"]="𝔹",
+["LeftUpVector"]="↿",
+["OpenCurlyQuote"]="‘",
+["NotSupersetEqual"]="⊉",
+["Barwed"]="⌆",
+["nsupe"]="⊉",
+["nsupE"]="⫆̸",
+["lrtri"]="⊿",
+["pluse"]="⩲",
+["blk14"]="░",
+["Eopf"]="𝔼",
+["boxv"]="│",
+["Pfr"]="𝔓",
+["DownTeeArrow"]="↧",
+["DownLeftVector"]="↽",
+["YIcy"]="Ї",
+["phmmat"]="ℳ",
+["NotRightTriangleBar"]="⧐̸",
+["bigcup"]="⋃",
+["ubreve"]="ŭ",
+["lEg"]="⪋",
+["IJlig"]="IJ",
+["nrtri"]="⋫",
+["npolint"]="⨔",
+["micro"]="µ",
+["cir"]="○",
+["ge"]="≥",
+["NotGreaterLess"]="≹",
+["YAcy"]="Я",
+["nparallel"]="∦",
+["thorn"]="þ",
+["Vert"]="‖",
+["DoubleRightTee"]="⊨",
+["sup3"]="³",
+["notindot"]="⋵̸",
+["not"]="¬",
+["Delta"]="Δ",
+["simeq"]="≃",
+["nltrie"]="⋬",
+["beth"]="ℶ",
+["bfr"]="𝔟",
+["loarr"]="⇽",
+["Ifr"]="ℑ",
+["nleq"]="≰",
+["FilledSmallSquare"]="◼",
+["nldr"]="‥",
+["CirclePlus"]="⊕",
+["nless"]="≮",
+["Atilde"]="Ã",
+["Ograve"]="Ò",
+["nhpar"]="⫲",
+["rlarr"]="⇄",
+["bsol"]="\\",
+["nharr"]="↮",
+["pre"]="⪯",
+["ngtr"]="≯",
+["acy"]="а",
+["ngsim"]="≵",
+["nges"]="⩾̸",
+["ngeqq"]="≧̸",
+["Otilde"]="Õ",
+["nedot"]="≐̸",
+["nearr"]="↗",
+["frac23"]="⅔",
+["frac16"]="⅙",
+["lcaron"]="ľ",
+["naturals"]="ℕ",
+["nang"]="∠⃒",
+["nVDash"]="⊯",
+["longrightarrow"]="⟶",
+["igrave"]="ì",
+["DownArrowUpArrow"]="⇵",
+["Omega"]="Ω",
+["ZeroWidthSpace"]="​",
+["curren"]="¤",
+["Jfr"]="𝔍",
+["DoubleLeftArrow"]="⇐",
+["bcong"]="≌",
+["mscr"]="𝓂",
+["Rscr"]="ℛ",
+["twixt"]="≬",
+["frac12"]="½",
+["slarr"]="←",
+["LessSlantEqual"]="⩽",
+["oint"]="∮",
+["amacr"]="ā",
+["ell"]="ℓ",
+["midcir"]="⫰",
+["Lang"]="⟪",
+["micro"]="µ",
+["ldca"]="⤶",
+["marker"]="▮",
+["succ"]="≻",
+["Int"]="∬",
+["Jukcy"]="Є",
+["succneqq"]="⪶",
+["because"]="∵",
+["male"]="♂",
+["lrhard"]="⥭",
+["complement"]="∁",
+["lvertneqq"]="≨︀",
+["DoubleUpDownArrow"]="⇕",
+["ltrif"]="◂",
+["ltri"]="◃",
+["dot"]="˙",
+["bnequiv"]="≡⃥",
+["Ntilde"]="Ñ",
+["ocy"]="о",
+["lstrok"]="ł",
+["RightVector"]="⇀",
+["backprime"]="‵",
+["loz"]="◊",
+["lowbar"]="_",
+["infintie"]="⧝",
+["nsqsupe"]="⋣",
+["Tfr"]="𝔗",
+["loplus"]="⨭",
+["nsubset"]="⊂⃒",
+["looparrowleft"]="↫",
+["longmapsto"]="⟼",
+["longleftarrow"]="⟵",
+["PlusMinus"]="±",
+["NotSquareSubset"]="⊏̸",
+["lobrk"]="⟦",
+["DoubleVerticalBar"]="∥",
+["NotLeftTriangleBar"]="⧏̸",
+["equivDD"]="⩸",
+["loang"]="⟬",
+["lneqq"]="≨",
+["iuml"]="ï",
+["lmoust"]="⎰",
+["csub"]="⫏",
+["lharu"]="↼",
+["lhard"]="↽",
+["lfisht"]="⥼",
+["lesseqqgtr"]="⪋",
+["rcy"]="р",
+["cent"]="¢",
+["lessapprox"]="⪅",
+["lesges"]="⪓",
+["Utilde"]="Ũ",
+["leftharpoonup"]="↼",
+["leftarrow"]="←",
+["awconint"]="∳",
+["lcub"]="{",
+["excl"]="!",
+["Sfr"]="𝔖",
+["leftharpoondown"]="↽",
+["Vvdash"]="⊪",
+["there4"]="∴",
+["lat"]="⪫",
+["larrtl"]="↢",
+["Precedes"]="≺",
+["Gcedil"]="Ģ",
+["boxtimes"]="⊠",
+["colon"]=":",
+["InvisibleComma"]="⁣",
+["OverParenthesis"]="⏜",
+["lagran"]="ℒ",
+["Rang"]="⟫",
+["djcy"]="ђ",
+["curarr"]="↷",
+["gsim"]="≳",
+["cedil"]="¸",
+["boxur"]="└",
+["rightthreetimes"]="⋌",
+["eth"]="ð",
+["Ropf"]="ℝ",
+["Agrave"]="À",
+["iscr"]="𝒾",
+["ccedil"]="ç",
+["imof"]="⊷",
+["imagline"]="ℐ",
+["UpArrow"]="↑",
+["boxdL"]="╕",
+["Mfr"]="𝔐",
+["SucceedsTilde"]="≿",
+["barwed"]="⌅",
+["NotSuperset"]="⊃⃒",
+["gneq"]="⪈",
+["hksearow"]="⤥",
+["lE"]="≦",
+["nlarr"]="↚",
+["gt"]=">",
+["Zopf"]="ℤ",
+["gammad"]="ϝ",
+["rect"]="▭",
+["Hstrok"]="Ħ",
+["frac34"]="¾",
+["acute"]="´",
+["fork"]="⋔",
+["Vee"]="⋁",
+["ldrushar"]="⥋",
+["ThickSpace"]="  ",
+["LeftTeeVector"]="⥚",
+["egrave"]="è",
+["ngt"]="≯",
+["nsubseteq"]="⊈",
+["frac78"]="⅞",
+["SquareSubsetEqual"]="⊑",
+["ecy"]="э",
+["UpTeeArrow"]="↥",
+["pcy"]="п",
+["GreaterSlantEqual"]="⩾",
+["ecaron"]="ě",
+["cupor"]="⩅",
+["Nfr"]="𝔑",
+["rightarrowtail"]="↣",
+["Ofr"]="𝔒",
+["subE"]="⫅",
+["IOcy"]="Ё",
+["cedil"]="¸",
+["cdot"]="ċ",
+["ShortLeftArrow"]="←",
+["CircleMinus"]="⊖",
+["Dagger"]="‡",
+["cupbrcap"]="⩈",
+["SmallCircle"]="∘",
+["cirfnint"]="⨐",
+["nvge"]="≥⃒",
+["Eacute"]="É",
+["Equal"]="⩵",
+["MinusPlus"]="∓",
+["Tab"]=" ",
+}
diff --git a/macros/luatex/generic/luaxml/luaxml-parse-query.lua b/macros/luatex/generic/luaxml/luaxml-parse-query.lua
new file mode 100644
index 0000000000..7931fa193f
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml-parse-query.lua
@@ -0,0 +1,46 @@
+-- Source: https://github.com/leafo/web_sanitize
+-- Author: Leaf Corcoran
+local R, S, V, P
+do
+ local _obj_0 = require("lpeg")
+ R, S, V, P = _obj_0.R, _obj_0.S, _obj_0.V, _obj_0.P
+end
+local C, Cs, Ct, Cmt, Cg, Cb, Cc, Cp
+do
+ local _obj_0 = require("lpeg")
+ C, Cs, Ct, Cmt, Cg, Cb, Cc, Cp = _obj_0.C, _obj_0.Cs, _obj_0.Ct, _obj_0.Cmt, _obj_0.Cg, _obj_0.Cb, _obj_0.Cc, _obj_0.Cp
+end
+local alphanum = R("az", "AZ", "09")
+local num = R("09")
+local white = S(" \t\n") ^ 0
+-- this is a deviation from the upstream, we allow ":" in the tag name, because
+-- luaxml doesn't support XML namespaces and elements must be queried using
+-- dom:query_selector("namespace:element")
+local word = (alphanum + S("_-") + S("|")) ^ 1
+local mark
+mark = function(name)
+ return function(...)
+ return {
+ name,
+ ...
+ }
+ end
+end
+local parse_query
+parse_query = function(query)
+ local tag = word / mark("tag")
+ local cls = P(".") * (word / mark("class"))
+ local id = P("#") * (word / mark("id"))
+ local any = P("*") / mark("any")
+ local nth = P(":nth-child(") * C(num ^ 1) * ")" / mark("nth-child")
+ local first = P(":first-child") / mark("first-child")
+ local attr = P("[") * C(word) * P("]") / mark("attr")
+ local selector = Ct((any + nth + first + tag + cls + id + attr) ^ 1)
+ local pq = Ct(selector * (white * selector) ^ 0)
+ local pqs = Ct(pq * (white * P(",") * white * pq) ^ 0)
+ pqs = pqs * (white * -1)
+ return pqs:match(query)
+end
+return {
+ parse_query = parse_query
+}
diff --git a/macros/luatex/generic/luaxml/luaxml-pretty.lua b/macros/luatex/generic/luaxml/luaxml-pretty.lua
new file mode 100644
index 0000000000..44f3183949
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml-pretty.lua
@@ -0,0 +1,89 @@
+--module(...,package.seeall)
+
+--- Lua pretty printer from <a href="http://mini.net/cgi-bin/lua/44.html">http://mini.net/cgi-bin/lua/44.html</a><br/>
+-- This was extracted from utility code in "util.lua".<br/>
+-- 23/02/2001 jcw@equi4.com<br/>
+-- Pretty displays a value, properly dealing with tables and cycles
+
+local displayvalue=
+ function (s)
+ if not s or type(s)=='function' or type(s)=='userdata' then
+ s=tostring(s)
+ elseif type(s)~='number' then
+ s=string.gsub(string.format('%q',s),'^"([^"\']*)"$',"'%1'")
+ end
+ return s
+ end
+
+local askeystr=
+ function (u,s)
+ if type(u)=='string' and string.find(u,'^[%w_]+$') then return s..u end
+ return '['..displayvalue(u)..']'
+ end
+
+local horizvec=
+ function (x,n)
+ local o,e='',''
+ for i=1,#x do
+ if type(x[i])=='table' then return end
+ o=o..e..displayvalue(x[i])
+ if string.len(o)>n then return end
+ e=','
+ end
+ return '('..o..')'
+ end
+
+local horizmap=
+ function (x,n)
+ local o,e='',''
+ for k,v in pairs(x) do
+ if type(v)=='table' then return end
+ o=o..e..askeystr(k,'')..'='..displayvalue(v)
+ if string.len(o)>n then return end
+ e=','
+ end
+ return '{'..o..'}'
+ end
+local M = {}
+local function pretty(p,x,h,q)
+ if not p then p,x='globals',globals() end
+ if type(x)=='table' then
+ if not h then h={} end
+ if h[x] then
+ x=h[x]
+ else
+ if not q then q=p end
+ h[x]=q
+ local s={}
+ for k,v in pairs(x) do table.insert(s,k) end
+ if #s>0 then
+ local n=75-string.len(p)
+ local f=#s==#x and horizvec(x,n)
+ if not f then f=horizmap(x,n) end
+ if not f then
+ table.sort(s,function (a,b)
+ --if tag(a)~=tag(b) then a,b=tag(b),tag(a) end
+ if type(a)~=type(b) then a,b=type(b),type(a) end
+ return a<b
+ end)
+ for i=1,#s do
+ if s[i] then
+ local u=askeystr(s[i],'.')
+ pretty(p..u,x[s[i]],h,q..u)
+ p=string.rep(' ',string.len(p))
+ end
+ end
+ return
+ end
+ x=f
+ else
+ x='{}'
+ end
+ end
+ else
+ x=displayvalue(x)
+ end
+ print(p..' = '..x)
+end
+M.pretty = pretty
+return M
diff --git a/macros/luatex/generic/luaxml/luaxml-stack.lua b/macros/luatex/generic/luaxml/luaxml-stack.lua
new file mode 100644
index 0000000000..6c2d83610f
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml-stack.lua
@@ -0,0 +1,67 @@
+-- Code from http://lua-users.org/wiki/SimpleStack
+--module(...,package.seeall)
+local M={}
+local Stack = {}
+M.Stack = Stack
+local unpack = table.unpack
+-- Create a Table with stack functions
+function Stack:Create()
+
+ -- stack table
+ local t = {}
+ -- entry table
+ t._et = {}
+
+ -- push a value on to the stack
+ function t:push(...)
+ if ... then
+ local targs = {...}
+ -- add values
+ for _,v in pairs(targs) do
+ table.insert(self._et, v)
+ end
+ end
+ end
+
+ -- pop a value from the stack
+ function t:pop(num)
+
+ -- get num values from stack
+ local num = num or 1
+
+ -- return table
+ local entries = {}
+
+ -- get values into entries
+ for i = 1, num do
+ -- get last entry
+ if #self._et ~= 0 then
+ table.insert(entries, self._et[#self._et])
+ -- remove last value
+ table.remove(self._et)
+ else
+ break
+ end
+ end
+ -- return unpacked entries
+ return unpack(entries)
+ end
+
+ -- get entries
+ function t:getn()
+ return #self._et
+ end
+
+ -- list values
+ function t:list()
+ for i,v in pairs(self._et) do
+ print(i, v)
+ end
+ end
+ function t:join(s)
+ return table.concat(self._et,s)
+ end
+ return t
+end
+
+return M
diff --git a/macros/luatex/generic/luaxml/luaxml-testxml.lua b/macros/luatex/generic/luaxml/luaxml-testxml.lua
new file mode 100644
index 0000000000..8231642116
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml-testxml.lua
@@ -0,0 +1,147 @@
+#!/usr/bin/lua
+---Simple command line test parser - applies handler[s] specified
+-- to XML file (or STDIN) and dumps results<br/>
+--
+-- $Id: testxml.lua,v 1.1.1.1 2001/11/28 06:11:33 paulc Exp $<br/>
+--
+-- $Log: testxml.lua,v $<br/>
+-- Revision 1.1.1.1 2001/11/28 06:11:33 paulc<br/>
+-- Initial Import
+--
+
+modxml = require('luaxml-mod-xml')
+handler = require('luaxml-mod-handler')
+pretty = require('luaxml-pretty')
+
+
+-- Defaults
+_print = nil
+_simpletree = nil
+_dom = nil
+_file = nil
+_xmlrpc = nil
+_debug = nil
+_ws = nil
+_noentity = nil
+
+_usage = [[
+textxml.lua [-print] [-simpletree] [-dom] [-xmlrpc] [-debug]
+ [-ws] [-noentity] [-help] [file]
+]]
+
+_help = [[
+testxml.lua - Simple command line XML processor
+
+Options:
+
+ -print : Generate event dump (default)
+ -simpletree : Generate simple tree
+ -dom : Generate DOM-like tree
+ -debug : Print debug info (filename/text)
+ -ws : Do not strip whitespace
+ -noentity : Do not expand entities
+ -help : Print help
+ file : XML File (parse stdin in nil)
+]]
+
+index = 1
+local exit = os.exit
+
+function setOptions(x)
+ if _ws then
+ x.options.stripWS = nil
+ end
+ if _noentity then
+ x.options.expandEntities = nil
+ end
+end
+
+while arg[index] do
+ --print (arg[index])
+ if (string.sub(arg[index],1,1)=='-') then
+ if arg[index] == "-print" then
+ _print = 1
+ elseif arg[index] == "-simpletree" then
+ _simpletree= 1
+ elseif arg[index] == "-dom" then
+ _dom= 1
+ elseif arg[index] == "-xmlrpc" then
+ _xmlrpc= 1
+ elseif arg[index] == "-debug" then
+ _debug = 1
+ elseif arg[index] == "-ws" then
+ _ws = 1
+ elseif arg[index] == "-noentity" then
+ _noentity = 1
+ elseif arg[index] == "-help" then
+ print(_usage)
+ exit()
+ else
+ print(_usage)
+ exit()
+ end
+ else
+ -- Filename is last argument if present
+ if arg[index+1] then
+ print(_usage)
+ exit()
+ else
+ _file = arg[index]
+ end
+ end
+ index = index + 1
+end
+
+if _file then
+ print("File",_file)
+ if (_debug) then
+ io.write ( "File: ".._file.."\n" )
+ end
+ --xml = read(openfile(_file,"r"),"*a")
+
+ local f, e = io.open(_file, "r")
+ if f then
+ xml = f:read("*a")
+ else
+ error(e)
+ end
+
+else
+ xml = io.read("*a")
+end
+
+if _debug then
+ io.write ( "----------- XML\n" )
+ io.write (xml.."\n")
+end
+
+if _print or not (_print or _dom or _simpletree or _print or _xmlrpc) then
+ io.write ( "----------- Print\n" )
+ h = handler.printHandler()
+ x = modxml.xmlParser(h)
+ setOptions(x)
+ x:parse(xml)
+end
+
+if _simpletree then
+ io.write ( "----------- SimpleTree\n" )
+ h = handler.simpleTreeHandler()
+ x = modxml.xmlParser(h)
+ setOptions(x)
+ x:parse(xml)
+ pretty.pretty('root',h.root)
+end
+
+if _dom then
+ io.write ( "----------- Dom\n" )
+ h = handler.domHandler()
+ x = modxml.xmlParser(h)
+ setOptions(x)
+ x:parse(xml)
+ pretty.pretty('root',h.root)
+ io.write ( "-----------\n" )
+end
+
+
+
+
diff --git a/macros/luatex/generic/luaxml/luaxml.pdf b/macros/luatex/generic/luaxml/luaxml.pdf
new file mode 100644
index 0000000000..0f5b986026
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml.pdf
Binary files differ
diff --git a/macros/luatex/generic/luaxml/luaxml.tex b/macros/luatex/generic/luaxml/luaxml.tex
new file mode 100644
index 0000000000..ebaba5b4d7
--- /dev/null
+++ b/macros/luatex/generic/luaxml/luaxml.tex
@@ -0,0 +1,749 @@
+\documentclass{ltxdoc}
+% \usepackage{tgschola,url}
+\usepackage{url}
+\usepackage[english]{babel}
+\usepackage{hyperref}
+\usepackage{luacode}
+\usepackage{framed}
+% Version is defined in the makefile, use default values when compiled directly
+\ifdefined\version\else
+\def\version{v0.1h}
+\let\gitdate\date
+\fi
+\newcommand\modulename[1]{\subsection{#1}\label{sec:#1}}
+\newcommand\modulesummary[1]{#1\\}
+\newcommand\moduleclass[1]{\subsubsection{Class: #1}}
+\newcommand\functionname[2]{\par\noindent\textbf{#1(#2)}\\}
+\newcommand\functionsummary[1]{#1\\\textbf{Parameters:}\\}
+\newcommand\functionparam[2]{\texttt{#1}: #2\\}
+\newcommand\functionreturn[1]{\textbf{Return: }\\#1\\}
+
+\begin{document}
+ \title{The \textsc{LuaXML} library}
+ \author{Paul Chakravarti \and Michal Hoftich}
+ \date{Version \version\\\gitdate}
+ \maketitle
+\tableofcontents
+
+\section{Introduction}
+
+|LuaXML| is pure lua library for processing and serializing of the |xml| files.
+The base code code has been written by Paul Chakravarti, with minor changes
+which brings Lua 5.3 or HTML 5 support. On top of that, new modules for
+accessing the |xml| files using |DOM| like methods or |CSS|
+selectors\footnote{Thanks to Leaf Corcoran for |CSS selector| parsing code.}
+have been added.
+
+The documentation is divided to three parts -- first part deals with the |DOM|
+library, second part describes the low-level libraries and the third part is
+original documentation by Paul Chakravarti.
+% Current release is aimed mainly as support for the odsfile package.
+% In first release it was included with the odsfile package,
+% but as it is general library which can be used also with other packages,
+% I decided to distribute it as separate library.
+
+\section{The \texttt{DOM\_Object} library}
+
+This library can process a |xml| sources using |DOM| like functions. To load
+it, you need to require |luaxml-domobject.lua| file. The |parse| function
+provided by the library creates \texttt{DOM\_Object} object, which provides several
+methods for processing the |xml| tree.
+
+\begin{verbatim}
+local dom = require "luaxml-domobject"
+local document = [[
+<html>
+<head><title>sample</title></head>
+<body>
+<h1>test</h1>
+<p>hello</p>
+</body>
+</html>
+ ]]
+
+-- dom.parse returns the DOM_Object
+local obj = dom.parse(document)
+-- it is possible to call methods on the object
+local root_node = obj:root_node()
+for _, x in ipairs(root_node:get_children()) do
+ print(x:get_element_name())
+end
+\end{verbatim}
+
+The details about available methods can be found in the API docs, section
+\ref{sec:luaxml-domobject}. The above code will load a |xml| document, it will
+get the ROOT element and print all it's children element names. The
+\verb|DOM_Object:get_children| function returns Lua table, so it is possible to
+loop over it using standard table functions.
+
+\begin{framed}
+\begin{luacode*}
+dom = require "luaxml-domobject"
+local document = [[
+<html>
+<head><title>sample</title></head>
+<body>
+<h1>test</h1>
+<p>hello</p>
+</body>
+</html>
+ ]]
+
+-- dom.parse returns the DOM_Object
+obj = dom.parse(document)
+-- it is possible to call methods on the object
+local root_node = obj:root_node()
+for _, x in ipairs(root_node:get_children()) do
+ tex.print(x:get_element_name().. "\\par")
+end
+\end{luacode*}
+\end{framed}
+
+\subsection{Node selection methods}
+There are some other methods for element retrieving.
+
+\subsubsection{The \texttt{DOM\_Object:get\_path} method}
+If you want to print text content of all child elements of the body element, you can use \verb|DOM_Object:get_path|:
+
+\begin{verbatim}
+local path = obj:get_path("html body")
+for _, el in ipairs(path[1]:get_children()) do
+ print(el:get_text())
+end
+\end{verbatim}
+
+The \verb|DOM_Object:get_path| function always return array with all elements
+which match the requested path, even it there is only one such element. In this
+case, it is possible to use standard Lua table indexing to get the first and
+only one matched element and get it's children using
+\verb|DOM_Object:get_children| method. It the children node is an element, it's
+text content is printed using \verb|DOM_Object:get_text|.
+
+
+
+\begin{framed}
+ \begin{luacode*}
+local path = obj:get_path("html body")
+
+for _, el in ipairs(path[1]:get_children()) do
+ if el:is_element() then
+ tex.print(el:get_text().."\\par")
+ end
+end
+ \end{luacode*}
+\end{framed}
+
+\subsubsection{The \texttt{DOM\_Object:query\_selector} method}
+
+This method uses |CSS selector| syntax to select elements, similarly to JavaScript \textit{jQuery} library.
+
+\begin{verbatim}
+for _, el in ipairs(obj:query_selector("h1,p")) do
+ print(el:get_text())
+end
+\end{verbatim}
+
+
+\begin{framed}
+ \begin{luacode*}
+for _, el in ipairs(obj:query_selector("h1,p")) do
+ tex.print(el:get_text().."\\par")
+end
+ \end{luacode*}
+\end{framed}
+
+It supports also |XML| namespaces, using \verb_namespace|element_ syntax.
+
+\subsection{Element traversing}
+
+\subsubsection{The \texttt{DOM\_Object:traverse\_elements} method}
+
+It may be useful to traverse over all elements and apply a function on all of them.
+
+\begin{verbatim}
+obj:traverse_elements(function(node)
+ print(node:get_text())
+end)
+\end{verbatim}
+
+\begin{framed}
+ \begin{luacode*}
+obj:traverse_elements(function(node)
+ tex.print(node:get_text().."\\par")
+end)
+ \end{luacode*}
+\end{framed}
+
+The \verb|get_text| method gets text from all children elements, so the first
+line shows all text contained in the \verb|<html>| element, the second one in
+\verb|<head>| element and so on.
+
+\subsection{DOM modifications}
+
+It is possible to add new elements, text nodes, or to remove them.
+
+\begin{verbatim}
+local headers = obj:query_selector("h1")
+for _, header in ipairs(headers) do
+ header:remove_node()
+end
+-- query selector returns array, we must retrieve the first element
+-- to get the actual body element
+local body = obj:query_selector("body")[1]
+local paragraph = body:create_element("p", {})
+body:add_child_node(paragraph)
+paragraph:add_child_node(paragraph:create_text_node("This is a second paragraph"))
+
+for _, el in ipairs(body:get_children()) do
+ if el:is_element() then
+ print(el:get_element_name().. ": ".. el:get_text())
+ end
+end
+\end{verbatim}
+
+In this example, \verb|<h1>| element is being removed from the sample document, and new
+paragraph is added. Two paragraphs should be shown in the output:
+
+\begin{framed}
+ \begin{luacode*}
+local headers = obj:query_selector("h1")
+-- query selector returns array, we must retrieve the first element
+-- to get the actual body element
+local body = obj:query_selector("body")[1]
+local oldbody = body:copy_node()
+for _, header in ipairs(headers) do
+ header:remove_node()
+end
+local paragraph = body:create_element("p", {})
+body:add_child_node(paragraph)
+paragraph:add_child_node(paragraph:create_text_node("This is a second paragraph"))
+
+for _, el in ipairs(body:get_children()) do
+if el:is_element() then
+ tex.print(el:get_element_name().. ": ".. el:get_text() .. "\\par")
+end
+end
+
+body:replace_node(oldbody)
+ \end{luacode*}
+\end{framed}
+
+
+\section{The \texttt{CssQuery} library}
+
+This library serves mainly as a support for the
+\texttt{DOM\_Object:query\_selector} function. It also supports adding
+information to the DOM tree.
+
+\subsection{Example usage}
+
+\begin{verbatim}
+local cssobj = require "luaxml-cssquery"
+local domobj = require "luaxml-domobject"
+
+local xmltext = [[
+<html>
+<body>
+<h1>Header</h1>
+<p>Some text, <i>italics</i></p>
+</body>
+</html>
+]]
+
+local dom = domobj.parse(xmltext)
+local css = cssobj()
+
+css:add_selector("h1", function(obj)
+ print("header found: " .. obj:get_text())
+end)
+
+css:add_selector("p", function(obj)
+ print("paragraph found: " .. obj:get_text())
+end)
+
+css:add_selector("i", function(obj)
+ print("found italics: " .. obj:get_text())
+end)
+
+dom:traverse_elements(function(el)
+ -- find selectors that match the current element
+ local querylist = css:match_querylist(el)
+ -- add templates to the element
+ css:apply_querylist(el,querylist)
+end)
+\end{verbatim}
+
+\begin{framed}
+ \begin{luacode*}
+local cssobj = require "luaxml-cssquery"
+local domobj = require "luaxml-domobject"
+local print = function(s) tex.print(s .. "\\par") end
+
+local xmltext = [[
+<html>
+<body>
+<h1>Header</h1>
+<p>Some text, <i>italics</i></p>
+</body>
+</html>
+]]
+
+local dom = domobj.parse(xmltext)
+local css = cssobj()
+
+css:add_selector("h1", function(obj)
+ print("header found: " .. obj:get_text())
+end)
+
+css:add_selector("p", function(obj)
+ print("paragraph found: " .. obj:get_text())
+end)
+
+css:add_selector("i", function(obj)
+ print("found italics: " .. obj:get_text())
+end)
+
+dom:traverse_elements(function(el)
+ -- find selectors that match the current element
+ local querylist = css:match_querylist(el)
+ -- add templates to the element
+ css:apply_querylist(el,querylist)
+end)
+ \end{luacode*}
+\end{framed}
+
+More complete example may be found in the \texttt{examples} directory in the
+\texttt{LuaXML} source code
+repository\footnote{\url{https://github.com/michal-h21/LuaXML/blob/master/examples/xmltotex.lua}}.
+
+\section{The API documentation}
+
+\input{doc/api.tex}
+
+\section{Low-level functions usage}
+
+% The processing is done with several handlers, their usage will be shown in the
+% following section. Full description of handlers is given in the original
+% documentation in section \ref{sec:handlers}.
+
+% \subsection{Usage examples}
+
+The original |LuaXML| library provides some low-level functions for |XML| handling.
+First of all, we need to load the libraries:
+
+\begin{verbatim}
+xml = require('luaxml-mod-xml')
+handler = require('luaxml-mod-handler')
+\end{verbatim}
+
+
+The |luaxml-mod-xml| file contains the xml parser and also the serializer. In
+|luaxml-mod-handler|, various handlers for dealing with xml data are defined.
+Handlers transforms the |xml| file to data structures which can be handled from
+the Lua code. More information about handlers can be found in the original
+documentation, section \ref{sec:handlers}.
+
+\subsection{The simpleTreeHandler}
+\begin{verbatim}
+sample = [[
+<a>
+ <d>hello</d>
+ <b>world.</b>
+ <b at="Hi">another</b>
+</a>]]
+treehandler = handler.simpleTreeHandler()
+x = xml.xmlParser(treehandler)
+x:parse(sample)
+\end{verbatim}
+
+You have to create handler object, using |handler.simpleTreeHandler()| and xml
+parser object using |xml.xmlParser(handler object)|. |simpleTreehandler|
+creates simple table hierarchy, with top root node in |treehandler.root|
+
+\begin{verbatim}
+-- pretty printing function
+function printable(tb, level)
+ level = level or 1
+ local spaces = string.rep(' ', level*2)
+ for k,v in pairs(tb) do
+ if type(v) ~= "table" then
+ print(spaces .. k..'='..v)
+ else
+ print(spaces .. k)
+ level = level + 1
+ printable(v, level)
+ end
+ end
+end
+
+-- print table
+printable(treehandler.root)
+-- print xml serialization of table
+print(xml.serialize(treehandler.root))
+-- direct access to the element
+print(treehandler.root["a"]["b"][1])
+\end{verbatim}
+
+This code produces the following output:
+
+\begin{verbatim}
+ output:
+ a
+ d=hello
+ b
+ 1=world.
+ 2
+ 1=another
+ _attr
+ at=Hi
+ <?xml version="1.0" encoding="UTF-8"?>
+ <a>
+ <d>hello</d>
+ <b>world.</b>
+ <b at="Hi">
+ another
+ </b>
+ </a>
+
+ world.
+\end{verbatim}
+
+First part is pretty-printed dump of Lua table structure contained in the handler, the second
+part is |xml| serialized from that table and the last part demonstrates direct access to particular
+elements.
+
+Note that |simpleTreeHandler| creates tables that can be easily accessed using
+standard lua functions, but if the xml document is of mixed-content type\footnote{%
+This means that element may contain both children elements and text.}:
+
+\begin{verbatim}
+<a>hello
+ <b>world</b>
+</a>
+\end{verbatim}
+
+\noindent then it produces wrong results. It is useful mostly for data |xml| files, not for
+text formats like |xhtml|.
+
+\subsection{The domHandler}
+
+% For complex xml documents with mixed content, |domHandler| is capable of representing any valid XML document:
+For complex xml documents, it is best to use the |domHandler|, which creates object which contains all information
+from the |xml| document.
+
+\begin{verbatim}
+-- file dom-sample.lua
+-- next line enables scripts called with texlua to use luatex libraries
+--kpse.set_program_name("luatex")
+function traverseDom(current,level)
+ local level = level or 0
+ local spaces = string.rep(" ",level)
+ local root= current or current.root
+ local name = root._name or "unnamed"
+ local xtype = root._type or "untyped"
+ local attributes = root._attr or {}
+ if xtype == "TEXT" then
+ print(spaces .."TEXT : " .. root._text)
+ else
+ print(spaces .. xtype .. " : " .. name)
+ end
+ for k, v in pairs(attributes) do
+ print(spaces .. " ".. k.."="..v)
+ end
+ local children = root._children or {}
+ for _, child in ipairs(children) do
+ traverseDom(child, level + 1)
+ end
+end
+
+local xml = require('luaxml-mod-xml')
+local handler = require('luaxml-mod-handler')
+local x = '<p>hello <a href="http://world.com/">world</a>, how are you?</p>'
+local domHandler = handler.domHandler()
+local parser = xml.xmlParser(domHandler)
+parser:parse(x)
+traverseDom(domHandler.root)
+\end{verbatim}
+
+The ROOT element is stored in |domHandler.root| table, it's child nodes are stored in |_children|
+tables. Node type is saved in |_type| field, if the node type is |ELEMENT|, then |_name| field contains
+element name, |_attr| table contains element attributes. |TEXT| node contains text content in |_text|
+field.
+
+The previous code produces following output in the terminal: % after command
+% |texlua dom-sample.lua| running:
+
+\begin{verbatim}
+ROOT : unnamed
+ ELEMENT : p
+ TEXT : hello
+ ELEMENT : a
+ href=http://world.com/
+ TEXT : world
+ TEXT : , how are you?
+\end{verbatim}
+
+% With \verb|domHandler|, you can process documents with mixed content, like
+% \verb|xhtml|, so it is a most powerful handler.
+
+
+\clearpage
+\part{Original \texttt{LuaXML} documentation by Paul Chakravarti}
+\medskip
+
+\noindent This document was created automatically from the original source code comments using Pandoc\footnote{\url{http://johnmacfarlane.net/pandoc/}}
+
+\section{Overview}
+
+
+This module provides a non-validating XML stream parser in Lua.
+\section{Features}
+
+\begin{itemize}
+\item
+ Tokenises well-formed XML (relatively robustly)
+\item
+ Flexible handler based event api (see below)
+\item
+ Parses all XML Infoset elements - ie.
+ \begin{itemize}
+ \item
+ Tags
+ \item
+ Text
+ \item
+ Comments
+ \item
+ CDATA
+ \item
+ XML Decl
+ \item
+ Processing Instructions
+ \item
+ DOCTYPE declarations
+ \end{itemize}
+\item
+ Provides limited well-formedness checking (checks for basic syntax \&
+ balanced tags only)
+\item
+ Flexible whitespace handling (selectable)
+\item
+ Entity Handling (selectable)
+\end{itemize}
+\section{Limitations}
+
+\begin{itemize}
+\item
+ Non-validating
+\item
+ No charset handling
+\item
+ No namespace support
+\item
+ Shallow well-formedness checking only (fails to detect most semantic
+ errors)
+\end{itemize}
+\section{API}
+
+The parser provides a partially object-oriented API with functionality
+split into tokeniser and hanlder components.
+
+The handler instance is passed to the tokeniser and receives callbacks
+for each XML element processed (if a suitable handler function is
+defined). The API is conceptually similar to the SAX API but implemented
+differently.
+
+The following events are generated by the tokeniser
+
+\begin{verbatim}
+handler:starttag - Start Tag
+handler:endtag - End Tag
+handler:text - Text
+handler:decl - XML Declaration
+handler:pi - Processing Instruction
+handler:comment - Comment
+handler:dtd - DOCTYPE definition
+handler:cdata - CDATA
+\end{verbatim}
+The function prototype for all the callback functions is
+
+\begin{verbatim}
+callback(val,attrs,start,end)
+\end{verbatim}
+where attrs is a table and val/attrs are overloaded for specific
+callbacks - ie.
+
+\begin{tabular}{llp{5cm}}
+Callback & val & attrs (table)\\
+\hline
+starttag & name & |{ attributes (name=val).. }|\\
+endtag & name & nil\\
+text & |<text>| & nil\\
+cdata & |<text> | & nil\\
+decl & "xml" & |{ attributes (name=val).. }|\\
+pi & pi name & \begin{verbatim}{ attributes (if present)..
+ _text = <PI Text>
+}\end{verbatim}\\
+comment & |<text>| & nil\\
+dtd & root element & \begin{verbatim}{ _root = <Root Element>,
+ _type = SYSTEM|PUBLIC,
+ _name = <name>,
+ _uri = <uri>,
+ _internal = <internal dtd>
+}\end{verbatim}\\
+\end{tabular}
+
+(starttag \& endtag provide the character positions of the start/end of the
+element)
+
+XML data is passed to the parser instance through the `parse' method
+(Note: must be passed as single string currently)
+
+\section{Options}
+
+Parser options are controlled through the `self.options' table.
+Available options are -
+
+\begin{itemize}
+\item
+ stripWS
+
+ Strip non-significant whitespace (leading/trailing) and do not
+ generate events for empty text elements
+\item
+ expandEntities
+
+ Expand entities (standard entities + single char numeric entities only
+ currently - could be extended at runtime if suitable DTD parser added
+ elements to table (see obj.\_ENTITIES). May also be possible to expand
+ multibyre entities for UTF--8 only
+\item
+ errorHandler
+
+ Custom error handler function
+\end{itemize}
+NOTE: Boolean options must be set to `nil' not `0'
+
+\section{Usage}
+
+Create a handler instance -
+
+\begin{verbatim}
+h = { starttag = function(t,a,s,e) .... end,
+ endtag = function(t,a,s,e) .... end,
+ text = function(t,a,s,e) .... end,
+ cdata = text }
+\end{verbatim}
+(or use predefined handler - see luaxml-mod-handler.lua)
+
+Create parser instance -
+
+\begin{verbatim}
+p = xmlParser(h)
+\end{verbatim}
+Set options -
+
+\begin{verbatim}
+p.options.xxxx = nil
+\end{verbatim}
+Parse XML data -
+
+\begin{verbatim}
+xmlParser:parse("<?xml... ")
+\end{verbatim}
+\section{Handlers}\label{sec:handlers}
+
+\subsection{Overview}
+
+Standard XML event handler(s) for XML parser module (luaxml-mod-xml.lua)
+
+\subsection{Features}
+
+\begin{verbatim}
+printHandler - Generate XML event trace
+domHandler - Generate DOM-like node tree
+simpleTreeHandler - Generate 'simple' node tree
+simpleTeXhandler - SAX like handler with support for CSS selectros
+\end{verbatim}
+\subsection{API}
+
+Must be called as handler function from xmlParser and implement XML
+event callbacks (see xmlParser.lua for callback API definition)
+
+\subsubsection{printHandler}
+
+printHandler prints event trace for debugging
+
+\subsubsection{domHandler}
+
+domHandler generates a DOM-like node tree structure with
+a single ROOT node parent - each node is a table comprising
+fields below.
+
+\begin{verbatim}
+node = { _name = <Element Name>,
+ _type = ROOT|ELEMENT|TEXT|COMMENT|PI|DECL|DTD,
+ _attr = { Node attributes - see callback API },
+ _parent = <Parent Node>
+ _children = { List of child nodes - ROOT/NODE only }
+ }
+
+\end{verbatim}
+\subsubsection{simpleTreeHandler}
+
+simpleTreeHandler is a simplified handler which attempts to generate a
+more `natural' table based structure which supports many common XML
+formats.
+
+The XML tree structure is mapped directly into a recursive table
+structure with node names as keys and child elements as either a table
+of values or directly as a string value for text. Where there is only a
+single child element this is inserted as a named key - if there are
+multiple elements these are inserted as a vector (in some cases it may
+be preferable to always insert elements as a vector which can be
+specified on a per element basis in the options). Attributes are
+inserted as a child element with a key of `\_attr'.
+
+Only Tag/Text \& CDATA elements are processed - all others are ignored.
+
+This format has some limitations - primarily
+
+\begin{itemize}
+\item Mixed-Content behaves unpredictably - the relationship between text
+ elements and embedded tags is lost and multiple levels of mixed
+ content does not work
+\item If a leaf element has both a text element and attributes then the text
+ must be accessed through a vector (to provide a container for the
+ attribute)
+\end{itemize}
+In general however this format is relatively useful.
+
+
+\subsection{Options}
+
+\begin{verbatim}
+simpleTreeHandler.options.noReduce = { <tag> = bool,.. }
+
+ - Nodes not to reduce children vector even if only
+ one child
+
+domHandler.options.(comment|pi|dtd|decl)Node = bool
+
+ - Include/exclude given node types
+\end{verbatim}
+\subsection{Usage}
+
+Pased as delegate in xmlParser constructor and called as callback by
+xmlParser:parse(xml) method.
+
+\section{History}
+
+This library is fork of LuaXML library originaly created by Paul
+Chakravarti. Some files not needed for use with luatex were droped from the distribution.
+Documentation was converted from original comments in the source code.
+
+\section{License}
+
+This code is freely distributable under the terms of the Lua license
+(\url{http://www.lua.org/copyright.html})
+\end{document}