diff options
author | Norbert Preining <norbert@preining.info> | 2020-09-08 03:02:12 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2020-09-08 03:02:12 +0000 |
commit | bc2d0660f4f460b55009ab4e525f2a0e4cde6187 (patch) | |
tree | d35815089faf23c45f4f21690e42cfcc7c65a5fd /support/tex4ebook/tex4ebook-exec_epub.lua | |
parent | 57edbaffbe7daad894e3036a4123acd03e0fdb9b (diff) |
CTAN sync 202009080302
Diffstat (limited to 'support/tex4ebook/tex4ebook-exec_epub.lua')
-rw-r--r-- | support/tex4ebook/tex4ebook-exec_epub.lua | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/support/tex4ebook/tex4ebook-exec_epub.lua b/support/tex4ebook/tex4ebook-exec_epub.lua index 52e2ab6134..b0ccee6202 100644 --- a/support/tex4ebook/tex4ebook-exec_epub.lua +++ b/support/tex4ebook/tex4ebook-exec_epub.lua @@ -5,6 +5,7 @@ local io = require("io") local log = logging.new("exec_epub") --local ebookutils = require("ebookutils") local ebookutils = require "mkutils" +local dom = require("luaxml-domobject") local outputdir_name="OEBPS" local metadir_name = "META-INF" local mimetype_name="mimetype" @@ -319,11 +320,123 @@ function pack_container() ebookutils.cp(basedir .."/"..outputfile, destdir .. outputfile) end +local function update_file(filename, fn) + -- update contents of a filename using function + local f = io.open(filename, "r") + local content = f:read("*all") + f:close() + local newcontent = fn(content) + local f = io.open(filename, "w") + f:write(newcontent) + f:close() +end + +local function fix_ncx_toc_levels(dom) + -- OK, this is a weird hack. The problem is that when \backmatter + -- follows \part, the subsequent chapters are listed under part + -- in the NCX TOC + -- I've added special element <navmark> to the ncx file to detect mark numbers. + -- chapters in backmatter should have empty mark number + + -- get current <navpoint> section type and mark number + local get_navpoint_info = function(navpoint) + local navmarks = navpoint:query_selector("navmark") + if navmarks and #navmarks > 0 then + -- we are interested only in the first navmark, because it contains the current navPoint info + local navmark = navmarks[1] + return navmark:get_attribute("type"), navmark:get_text() + end + return nil, "Cannot find navLabel" + end + + local fix_chapters = function(part) + -- move chapters from backmatter and appendix from the current part + -- find part position in the element list, it will be place where backmatter will be moved + local part_pos = part:find_element_pos() + 1 + local part_parent = part:get_parent() + -- child chapters + local children = part:get_children() + -- loop over children from back, where backmatter or appendix may be placed + for i = #children, 1, -1 do + local current = children[i] + local sect_type, mark = get_navpoint_info(current) + if sect_type then + -- remove spaces from mark + mark = mark:gsub("%s", "") + if sect_type == "appendix" or (sect_type == "chapter" and mark=="") then + -- move chapter at the same level as part, after part + -- the correct order will be kept, because we move from the back of the node list + -- and every new node is placed before previous added nodes + part_parent:add_child_node(current:copy_node(), part_pos) + current:remove_node() + else + -- break processing if we find normal chapter + break + end + end + end + end + + -- find the last part in the ncx table. it can contain incorrectly nested chapters + local parts = {} + for _, navpoint in ipairs(dom:query_selector("navMap navPoint")) do + -- we are not able to match just direct navPoint ancestors, so we will use this trick + if navpoint:get_parent():get_element_name() == "navMap" then + local sec_type, navmark = get_navpoint_info(navpoint) + if sec_type == "part" then table.insert(parts, navpoint) end + end + end + if #parts > 0 then + -- fix chapters in the last part + fix_chapters(parts[#parts]) + end + return dom +end + +local function clean_xml_files() + local opf_file = outputdir .. "/content.opf" + update_file(opf_file, function(content) + -- remove wrong elements from the OPF file + -- open opf file and create LuaXML DOM + local opf_dom = dom.parse(content) + -- remove child elements from elements that don't allow them + for _, el in ipairs(opf_dom:query_selector("dc|title, dc|creator")) do + -- get text content + local text = el:get_text() + -- replace element text with a new text node containing original text + el._children = {el:create_text_node(text)} + end + return opf_dom:serialize() + end) + local ncxfilename = outputdir .. "/" .. outputfilename .. ".ncx" + update_file(ncxfilename, function(content) + -- remove spurious spaces at the beginning + content = content:gsub("^%s*","") + local ncx_dom = dom.parse(content) + fix_ncx_toc_levels(ncx_dom) + -- remove child elements from <text> element + for _, el in ipairs(ncx_dom:query_selector("text")) do + local text = el:get_text() + -- replace element text with a new text node containing original text + el._children = {el:create_text_node(text)} + end + for _, el in ipairs(ncx_dom:query_selector("navPoint")) do + -- fix attribute names. this issue is caused by a LuaXML behavior + -- that makes all attributes lowercase + el._attr["playOrder"] = el._attr["playorder"] + el._attr["playorder"] = nil + end + return ncx_dom:serialize() + end) + +end function writeContainer() make_opf() + clean_xml_files() pack_container() end + local function deldir(path) for entry in lfs.dir(path) do if entry~="." and entry~=".." then |