Edit: The development version of make4ht
now supports filters in the ODT
output, so it is no longer necessary to update the ODT
files using zip
methods.
Simplified build file can look like this:
local filter = require "make4ht-filter"
local utfchar = unicode.utf8.char
local process = filter {
function(content)
return content:gsub("%&%#x([A-Fa-f0-9]+);", function(entity)
-- convert hexadecimal entity to Unicode
print(entity,utfchar(tonumber(entity, 16)))
return utfchar(tonumber(entity, 16))
end)
end
}
Make:match("4oo$", process)
It is just necessary to use temporary file names produced by tex4ht
, so instead of content.xml
it is necessary to process file with a .4oo
extension, which contains the document text.
Original answer:
Unicode characters in content.xml
are escapes as XML entities by xtpipes
command, which post-process the file in order to fix some issues regarding to math and sections. xtpipes
can be requested from t4ht
command using -cooxtpipes
option, make4ht
uses this option by default for the ODT
output.
If you use the same arguments as for htlatex
and ommit xtpipes
, make4ht
will produce identical result, with Unicode characters:
make4ht sample.tex "xhtml,ooffice" " -cmozhtf -utf8" " -coo"
<text:p text:style-name="First-line-indent"> áéíóúâêîôûüãõç.
But I would advise against disabling xtpipes
, because you can end with invalid ODT file.
Instead, it is possible to convert the entities to Unicode using make4ht
build file:
local mkutils = require "mkutils"
local zip = require "zip"
local utfchar = unicode.utf8.char
-- use function to change contents of the ODT file
local function update_odt(odtfilename, file_path, fn)
-- get name of the odt file
local odtname = mkutils.remove_extension(odtfilename) .. ".odt"
-- open and read contents of the requested file inside ODT file
local odtfile = zip.open(odtname)
local local_file = odtfile:open(file_path)
local content = local_file:read("*all")
local_file:close()
odtfile:close()
-- update the content using user function
content = fn(content)
-- write the updated file
local local_file_file = io.open(file_path,"w")
local_file_file:write(content)
local_file_file:close()
os.execute("zip " .. odtname .. " " .. file_path)
os.remove(file_path)
end
Make:match("tmp$", function(name, par)
update_odt(name, "content.xml", function(content)
return content:gsub("%&%#x([A-Fa-f0-9]+);", function(entity)
-- convert hexadecimal entity to Unicode
print(entity,utfchar(tonumber(entity, 16)))
return utfchar(tonumber(entity, 16))
end)
end)
end)
Becase the ODT file is zipped in the same step as xtpipes
are called, it is necessary to open the ODT file, read content.xml
from it and then pack again.
The content seems to be correct then:
<text:p text:style-name="First-line-indent"> áéíóúâêîôûüãõç.