diff options
author | Karl Berry <karl@freefriends.org> | 2022-12-12 21:02:56 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2022-12-12 21:02:56 +0000 |
commit | a2a6f21e711bb27829653d592df98c8d9060a22a (patch) | |
tree | 959a9b17a7acfc8e3032356bc508788b61d58e23 /Master | |
parent | b9f1af0e32ccc5a7ef1d735db15f2466960cf523 (diff) |
scikgtex (12dec22)
git-svn-id: svn://tug.org/texlive/trunk@65256 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master')
-rw-r--r-- | Master/texmf-dist/doc/lualatex/scikgtex/LICENSE | 21 | ||||
-rw-r--r-- | Master/texmf-dist/doc/lualatex/scikgtex/README | 21 | ||||
-rw-r--r-- | Master/texmf-dist/tex/lualatex/scikgtex/scikgtex.lua | 685 | ||||
-rw-r--r-- | Master/texmf-dist/tex/lualatex/scikgtex/scikgtex.sty | 149 | ||||
-rwxr-xr-x | Master/tlpkg/bin/tlpkg-ctan-check | 2 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/collection-luatex.tlpsrc | 1 | ||||
-rw-r--r-- | Master/tlpkg/tlpsrc/scikgtex.tlpsrc | 0 |
7 files changed, 878 insertions, 1 deletions
diff --git a/Master/texmf-dist/doc/lualatex/scikgtex/LICENSE b/Master/texmf-dist/doc/lualatex/scikgtex/LICENSE new file mode 100644 index 00000000000..bde9a445ef5 --- /dev/null +++ b/Master/texmf-dist/doc/lualatex/scikgtex/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Christof Bless + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Master/texmf-dist/doc/lualatex/scikgtex/README b/Master/texmf-dist/doc/lualatex/scikgtex/README new file mode 100644 index 00000000000..e754496c6f5 --- /dev/null +++ b/Master/texmf-dist/doc/lualatex/scikgtex/README @@ -0,0 +1,21 @@ +SciKGTeX +------------- +AUTHOR + Christof Bless, christofbless@gmail.com + +DESCRIPTION + Scientific Knowledge Graph TeX (SciKgTeX) is a LuaLaTeX package which makes + it possible to annotate specific research contributions in scientific documents. + SciKGTeX will enrich the document by adding the marked contributions to PDF metadata + in a structured XMP format which can be picked up by Search Engines and + Knowledge Graphs. + More information on how to use the package can be found here: + https://github.com/Christof93/SciKGTeX#readme + +VERSION + 2.1.1 (13.11.2022) + +LICENSE + This work is published under MIT License. https://opensource.org/licenses/MIT + + Copyright (C) 2022 Christof Bless diff --git a/Master/texmf-dist/tex/lualatex/scikgtex/scikgtex.lua b/Master/texmf-dist/tex/lualatex/scikgtex/scikgtex.lua new file mode 100644 index 00000000000..94bd0c1f40d --- /dev/null +++ b/Master/texmf-dist/tex/lualatex/scikgtex/scikgtex.lua @@ -0,0 +1,685 @@ +RANDOM_SEED = math.randomseed(os.time()) +MATRIX_AND = {{0,0},{0,1}} +MATRIX_OR = {{0,1},{1,1}} +HEXES = '0123456789abcdef' +local SciKGTeX = {} +SciKGTeX.whole_string = "" +SciKGTeX.properties_used = {} +SciKGTeX.property_commands = {} +SciKGTeX.mandatory_properties = { + 'researchproblem', + 'objective', + 'method', + 'result', + 'conclusion' +} +SciKGTeX.PRODUCE_XMP_FILE = true +SciKGTeX.WARNING_LEVEL = 1 + +local XMP = {} +XMP.lines = {} +XMP.namespaces = {} +XMP.property_ns = {} +XMP.XMP_TOP = [[<x:xmpmeta xmlns:x="adobe:ns:meta/">]] +XMP.XMP_BOTTOM = [[</rdf:RDF> +</x:xmpmeta>]] +XMP.PACKET_END = [[<?xpacket end="r"?>]] + +local UUID = {} + +---------------------------- utilities ------------------------------- + +-- performs the bitwise operation specified by truth matrix on two numbers. +function BITWISE(x, y, matrix) + local z = 0 + local pow = 1 + while x > 0 or y > 0 do + z = z + (matrix[x%2+1][y%2+1] * pow) + pow = pow * 2 + x = math.floor(x/2) + y = math.floor(y/2) + end + return z +end + +function INT2HEX(x) + local s,base,pow = '',16,0 + local d + while x > 0 do + d = x % base + 1 + x = math.floor(x/base) + s = string.sub(HEXES, d, d)..s + end + if #s == 1 then s = "0" .. s end + return s +end + +function get_output_dir() + if arg ~= nil then + for k,v in ipairs(arg) do + val, is_output_argument = v:gsub('%-%-output%-directory=(.*)','%1') + if is_output_argument > 0 then + return val + end + end + return nil + end + return nil +end + +function read_header_of_file(path) + local fh = io.open(path, "rb") + if fh then + local first_line = assert(fh:read()) + fh:close() + return first_line + else + print ("No xmp metadata file found!") + return nil + end +end + +function extract_uuid_from_header(header) + return header:gsub('.*id=\"(.-)\".*','%1') +end + +function generate_UUID() + UUID:initialize('00:0c:29:69:41:c6') + return UUID:toString() +end + +function string:split(sep) + if sep == nil then + sep = "%s" + end + local t = {} + for str in self:gmatch("([^"..sep.."]+)") do + table.insert(t, str) + end + return t +end + +function spaces_to_underscores(s) + return s:gsub('%s+','_') +end + +function remove_environments(s) + s,c = s:gsub('\\begin%s*{.-}{.-}%s*','') + s,c = s:gsub('\\begin%s*{.-}%s*','') + s,c = s:gsub('\\end%s*{.-}%s*','') + return s +end + +function remove_any_latex_command(s) + s, c = s:gsub('\\%w+%s*%[%d*%]%s*{(.*)}','%1') + if c > 0 then + return remove_latex_commands(s) + end + s, c = s:gsub('\\%w+%s*{(.*)}','%1') + if c > 0 then + return remove_latex_commands(s) + end + s, c = s:gsub('\\%w+%s*','') + if c > 0 then + return remove_latex_commands(s) + end + return s +end + +function find_last_occurence(s, repls) + occurences = {} + for pattern, repl in pairs(repls) do + i, j = s:find(pattern) + if i ~= nil then + table.insert(occurences, {i,j,pattern}) + end + end + table.sort(occurences, function(l, r) return l[1]>r[1] end) + if #occurences > 0 then + return occurences[1] + else + return nil + end +end + +function exhaustively_replace_last_occurence_of_pattern(s, repls) + last_occurence = find_last_occurence(s, repls) + if last_occurence ~= nil then + starts, ends, pattern = table.unpack(last_occurence) + to_replace = s:sub(starts,ends) + else + return s + end + new_string = s:sub(0,starts-1) .. to_replace:gsub(pattern, repls[pattern], 1) .. s:sub(ends+1) + return exhaustively_replace_last_occurence_of_pattern(new_string, repls) +end + +function remove_latex_commands(s) + replacements = { + -- contribution with * and [] + ['\\contribution%s*%*%s*%[%d*%]%s*{.-}{.*}%s*'] = '', + -- contribution with * + ['\\contribution%s*%*%s*{.-}%s*{.*}%s*'] = '', + -- contribution with [] + ['\\contribution%s*%[%d*%]%s*{.-}{(.*)}'] = '%1', + -- contribution normal + ['\\contribution%s*{.-}%s*{(.*)}'] = '%1', + + ['\\uri%s*{.-}%s*{(.*)}'] = '%1', + } + for cmd, used in pairs(SciKGTeX.property_commands) do + -- [] + replacements['\\'.. cmd .. '%s*%[%d*%]%s*{(.*)}'] = '%1' + -- normal command + replacements['\\'.. cmd .. '%s*{(.*)}'] = '%1' + -- with * and [] + replacements['\\'.. cmd .. '%s*%*%s*%[%d*%]%s*{.*}%s*'] = '' + -- with * + replacements['\\'.. cmd .. '%s*%*%s*{.*}%s*'] ='' + end + s = remove_environments(s) + s = exhaustively_replace_last_occurence_of_pattern(s, replacements) + s = remove_any_latex_command(s) + -- remove escape chars + s = s:gsub('\\','') + return s +end + +function uri_valid(s) + if s:find('http') ~= 1 then + return false + else + return true + end +end + +function resolve_entity(s) + -- make sure the entity is only resolved at the innermost of nested commands. + for _, cmd in ipairs(SciKGTeX.mandatory_properties) do + if s:find('\\' .. cmd) then + return false + end + end + if s:find('\\contribution') then + return false + end + uri, found = s:gsub('.*\\uri%s*{(.-)}%s*{.*}.*', '%1') + if found == 1 then + label = s:gsub('.*\\uri%s*{.-}%s*{(.*)}.*', '%1') + entity = string.format('<rdf:Description rdf:about=\"%s\"><rdfs:label>%s</rdfs:label></rdf:Description>', uri, label) + return entity + else + uri, found = s:gsub('.*\\uri%s*{(.-)}.*', '%1') + if found == 1 then + entity = string.format('<rdf:Description rdf:about=\"%s\"></rdf:Description>', uri) + return entity + else + return false + end + end +end + +---------------------------- UUID class methods ------------------------------------- + +-- hwaddr is a string: hexes delimited by colons. e.g.: 00:0c:29:69:41:c6 +function UUID:initialize(hwaddr) + self._bytes = { + math.random(0, 255), + math.random(0, 255), + math.random(0, 255), + math.random(0, 255), + math.random(0, 255), + math.random(0, 255), + math.random(0, 255), + math.random(0, 255), + math.random(0, 255), + math.random(0, 255), + -- should come from mac address + tonumber(hwaddr:sub(1, 2), 16), + tonumber(hwaddr:sub(4, 5), 16), + tonumber(hwaddr:sub(7, 8), 16), + tonumber(hwaddr:sub(10, 11), 16), + tonumber(hwaddr:sub(13, 14), 16), + tonumber(hwaddr:sub(16, 17), 16) + } + -- set the version + self._bytes[7] = BITWISE(self._bytes[7], 0x0f, MATRIX_AND) + self._bytes[7] = BITWISE(self._bytes[7], 0x40, MATRIX_OR) + -- set the variant + self._bytes[9] = BITWISE(self._bytes[7], 0x3f, MATRIX_AND) + self._bytes[9] = BITWISE(self._bytes[7], 0x80, MATRIX_OR) + self._string = nil + end + + -- lazy string creation. + function UUID:toString() + if self._string == nil then + self._string = INT2HEX(self._bytes[1])..INT2HEX(self._bytes[2])..INT2HEX(self._bytes[3])..INT2HEX(self._bytes[4]).."-".. + INT2HEX(self._bytes[5])..INT2HEX(self._bytes[6]).."-".. + INT2HEX(self._bytes[7])..INT2HEX(self._bytes[8]).."-".. + INT2HEX(self._bytes[9])..INT2HEX(self._bytes[10]).."-".. + INT2HEX(self._bytes[11])..INT2HEX(self._bytes[12])..INT2HEX(self._bytes[13])..INT2HEX(self._bytes[14])..INT2HEX(self._bytes[15])..INT2HEX(self._bytes[16]) + end + return self._string + end + +---------------------------- Main class methods ------------------------------- + +function SciKGTeX:set_warning_level(wl) + self.WARNING_LEVEL = wl +end + +function SciKGTeX:warn(warning_message, ...) + if self.WARNING_LEVEL > 0 then + texio.write_nl("term and log", + [[Package SciKGTeX Warning: ]] .. string.format(warning_message, ...)) + texio.write_nl("term and log","\n") + end +end + +function SciKGTeX:error(warning_message, ...) + tex.error([[Package SciKGTeX Error: ]] .. string.format(warning_message, ...)) +end + +SciKGTeX.command_factory = {} + +SciKGTeX.command_factory.cmd_top = [[\newcommand{\%s}[2][]{]] + +SciKGTeX.command_factory.cmd_top_star = [[\WithSuffix\newcommand\%s*[2][]{]] + +SciKGTeX.command_factory.cmd_top_override = [[\renewcommand{\%s}[2][]{]] + +SciKGTeX.command_factory.cmd_top_star_override = [[\WithSuffix\renewcommand\%s*[2][]{]] + +SciKGTeX.command_factory.directlua_part = [[ \directlua{ + local content = "\luaescapestring{\unexpanded{#2}}" + local belongs_to_contribution = "\luaescapestring{\unexpanded{#1}}" + SciKGTeX.XMP:add_annotation(belongs_to_contribution, '%s', content, 'annotation-id') + }]] + +SciKGTeX.command_factory.cmd_bottom = [[}]] +SciKGTeX.command_factory.cmd_bottom_star = [[\ignorespaces}]] + +function SciKGTeX.command_factory:build_command(command_name) + full_cmd = self.cmd_top .. "\n" .. self.directlua_part .. "\n #2\n" .. self.cmd_bottom + formatted_cmd = string.format(full_cmd, command_name, command_name) + for i, line in ipairs(formatted_cmd:split("\n")) do + tex.print(line .. "%") + end +end + +function SciKGTeX.command_factory:build_star_command(command_name) + full_cmd = self.cmd_top_star .. "\n" .. self.directlua_part .. "\n" .. self.cmd_bottom_star + formatted_cmd = string.format(full_cmd, command_name, command_name) + for i, line in ipairs(formatted_cmd:split("\n")) do + tex.print(line .. "%") + end +end + +function SciKGTeX.command_factory:override_command(command_name) + full_cmd = self.cmd_top_override .. "\n" .. self.directlua_part .. "\n #2\n" .. self.cmd_bottom + formatted_cmd = string.format(full_cmd, command_name, command_name) + for i, line in ipairs(formatted_cmd:split("\n")) do + tex.print(line .. "%") + end +end + +function SciKGTeX.command_factory:override_star_command(command_name) + full_cmd = self.cmd_top_star_override .. "\n" .. self.directlua_part .. "\n" .. self.cmd_bottom_star + formatted_cmd = string.format(full_cmd, command_name, command_name) + for i, line in ipairs(formatted_cmd:split("\n")) do + tex.print(line .. "%") + end +end + +function SciKGTeX:make_new_command(new_property, namespace) + -- check if property already exists + if self.property_commands[new_property]~=nil then + self:warn([[Method newpropertycommand: Repeated definition. + Command %s already exists! + Are you sure you want to override it?]], new_property) + self:add_property(new_property, namespace) + self.command_factory:override_command(new_property, namespace) + self.command_factory:override_star_command(new_property, namespace) + else + self.property_commands[new_property] = false + self:add_property(new_property, namespace) + self.command_factory:build_command(new_property, namespace) + self.command_factory:build_star_command(new_property, namespace) + end +end + +function SciKGTeX:add_property(new_property, namespace) + new_property = self.XMP:escape_xml_tags(new_property) + -- check if property already exists + if self.properties_used[new_property]~=nil then + self:warn([[Method addmetaproperty: Repeated definition. + Property %s already added! + Are you sure you want to replace it?]], new_property) + -- if not make it known to the object + else + self.properties_used[new_property] = false + end + ns_prefix = self.XMP:extract_namespace_prefix(namespace) + self.XMP.property_ns[new_property] = ns_prefix +end + +function SciKGTeX:register_property(prop_type) + self.properties_used[prop_type] = true +end + +function SciKGTeX:warn_unused_command() + warning_message = [[No %s annotation found! + Are you sure you don't want to mark an entity with %s?]] + for i, p in ipairs(self.mandatory_properties) do + used = self.properties_used[p] + if not used then + self:warn(warning_message, p, p); + end + end +end + +function SciKGTeX:print_entity(uri, label) + if label ~= "" then + tex.print(string.format('\\href{%s}{%s}',uri , label)) + else + tex.print(string.format('\\url{%s}',uri)) + end +end + +---------------------------- XMP class methods ------------------------------- + +function XMP:escape_xml_tags(s) + s = spaces_to_underscores(s) + s, i = s:gsub('[^%a%d%.-_]','') + if i > 0 then + SciKGTeX:warn([[Method escape_xml_tags: Forbidden characters. + Property %s can only contain letters, digits, underscores, hyphens and periods! + Forbidden characters removed.]], s) + end + s, i = s:gsub('^([Xx][Mm][Ll])','_%1') + if i > 0 then + SciKGTeX:warn([[Method escape_xml_tags: Forbidden characters. + Property %s can not start with xml! + Changed to _xml.]], s) + end + return s +end + +function XMP:escape_xml_content(s) + s = s:gsub('&', '&') + s = s:gsub('>', '>') + return s:gsub('<', '<') +end + +function XMP:add_line(...) + table.insert(self.lines, string.format(...)) +end + +function XMP:add_paper_node(paper_iri) + self.paper = {} + self.paper.contributions = {} + self.paper.id = paper_iri + self.paper.title = nil + self.paper.authors = {} + self.paper.researchfield = nil +end + +function XMP:add_contribution(key, contribution_iri) + local contribution = {} + contribution.properties = {} + contribution.id = contribution_iri:gsub("<(default_contribution)>", "ORKG_default") + self.paper.contributions[key] = contribution +end + +function XMP:extract_namespace_prefix(ns_arg) + if ns_arg == '' then + return nil + end + uri_and_prefix = ns_arg:split(',%s+?') + + if #uri_and_prefix < 2 then + SciKGTeX:error([[Method addmetaproperty: No prefix found. + Unknown prefix, URI specification: %s. + Please specify the arguments as [prefix, URI]!]], ns_arg) + return nil + elseif #uri_and_prefix > 2 then + SciKGTeX:warn([[Method addmetaproperty: Too many arguments. + Too many arguments in prefix, URI specification: %s. + Excess arguments are ignored.]], ns_arg) + end + + if not uri_valid(uri_and_prefix[2]) then + message = [[Method addmetaproperty: Invalid URI. + The given URI %s is not a valid choice! + Please use a resolvable URI starting with 'http'.]] + SciKGTeX:error(message, uri_and_prefix[2]) + return nil + end + -- add the namespace if it has not been added yet + if self.namespaces[uri_and_prefix[1]]==nil then + self:add_namespace(uri_and_prefix[1], uri_and_prefix[2]) + end + return uri_and_prefix[1] +end + +function XMP:process_content(c) + c = self:escape_xml_content(c) + entity = resolve_entity(c) + if entity ~= false then + return entity + end + c = remove_latex_commands(c) + return c +end + +function XMP:property_has_namespace(annotation_type) + annotation_type_t = annotation_type:split(':') + + if #annotation_type_t > 1 then + annotation_type = annotation_type_t[2] + prefix = annotation_type_t[1] + else + annotation_type = annotation_type_t[1] + prefix = nil + end + return prefix, annotation_type +end + +function XMP:set_title(title) + self.paper.title = title +end + +function XMP:add_author(author) + table.insert(self.paper.authors, author) +end + +function XMP:set_researchfield(researchfield) + self.paper.researchfield = researchfield +end + +function XMP:add_annotation(contribution_ids, annotation_type, content, annotation_id) + local annotation = {} + -- check if a namespace is attached to the property specification + prefix, annotation_type = self:property_has_namespace(annotation_type) + + annotation.content = content + annotation.id = annotation_id + annotation.type = self:escape_xml_tags(annotation_type) + + -- take the prefix given, the prefix saved in the namespace dictionary or the default ns + annotation.prefix = prefix or self.property_ns[annotation.type] or 'orkg_property' + + -- register the use of the property in text + SciKGTeX:register_property(annotation.type) + + -- check if the annotation was numbered + if contribution_ids == '' then + contribution_ids = '<default_contribution>' + end + contributions_ids_t = contribution_ids:split(',%s+?') + -- add the annotations at the specified contribution + for i, contribution_id in ipairs(contributions_ids_t) do + -- add a new contribution if it has not been added yet + if self.paper.contributions[contribution_id] == nil then + self:add_contribution(contribution_id, 'contribution_'..contribution_id) + end + -- add the property annotation to the list of properties of a contribution + -- check if the same annotation already exists (in case of double evaluation of the LaTeX command for example) + already_there = false + for _, prop in pairs(self.paper.contributions[contribution_id].properties) do + if prop.content == annotation.content and prop.type == annotation.type then + already_there = true + break + end + end + if not already_there then + table.insert(self.paper.contributions[contribution_id].properties, annotation) + end + end +end + +function XMP:add_namespace(abbr, uri) + self.namespaces[abbr] = uri +end + +function XMP:generate_rdf_root() + ns_key_array = {} + for ns, uri in pairs(self.namespaces) do table.insert(ns_key_array, ns) end + root_string = [[<rdf:RDF ]] + table.sort(ns_key_array) + for i, key in ipairs(ns_key_array) do + root_string = root_string .. "\n xmlns:" .. key .. [[="]] .. self.namespaces[key] .. [["]] + end + root_string = root_string .. [[>]] + return root_string +end + +function XMP:generate_xmp_string(lb_char) + lb_char = lb_char or "\n" + if lb_char == "r" then + lb_char = "\r" + end + output_string = "" + sorted_contributions = {} + for cb_id, contribution in pairs(XMP.paper.contributions) do + table.insert(sorted_contributions,cb_id) + end + table.sort(sorted_contributions) + self:add_line('<?xpacket begin="?" id="%s"?>',self.paper.id) + self:add_line(self.XMP_TOP) + self:add_line(self:generate_rdf_root()) + --print(debug.traceback()) + if self.paper then + self:add_line( + ' <rdf:Description rdf:about="https://www.orkg.org/orkg/paper/%s">', + self.paper.id + ) + self:add_line(' <rdf:type rdf:resource="http://orkg.org/core#Paper"/>') + if self.paper.title ~= nil then + self:add_line( + ' <orkg:hasTitle>%s</orkg:hasTitle>', + self:process_content(self.paper.title) + ) + end + for i, author in ipairs(self.paper.authors) do + self:add_line( + ' <orkg:hasAuthor>%s</orkg:hasAuthor>', + self:process_content(author)) + end + if self.paper.researchfield ~= nil then + self:add_line( + ' <orkg:hasResearchField>%s</orkg:hasResearchField>', + self:process_content(self.paper.researchfield) + ) + end + for i, cb_id in pairs(sorted_contributions) do + contribution = self.paper.contributions[cb_id] + self:add_line(' <orkg:hasResearchContribution>') + self:add_line( + ' <orkg:ResearchContribution rdf:about="https://www.orkg.org/orkg/paper/%s">', + self.paper.id .. "/" ..contribution.id + ) + for j, property in ipairs(contribution.properties) do + self:add_line( + ' <%s:%s>%s</%s:%s>', + property.prefix, + property.type, + self:process_content(property.content), + property.prefix, + property.type + ) + end + self:add_line(' </orkg:ResearchContribution>') + self:add_line(' </orkg:hasResearchContribution>') + end + self:add_line(' </rdf:Description>') + end + self:add_line(self.XMP_BOTTOM) + self:add_line(self.PACKET_END) + + return table.concat(self.lines, lb_char) + +end + +function XMP:attach_metadata_pdfstream() + local xmp_string = self:generate_xmp_string() + local new_pdf = pdf.obj { + type = 'stream', + attr = '/Type/Metadata /Subtype/XML', + immediate = true, + compresslevel = 0, + string = xmp_string, + } + self.lines = {} + return new_pdf +end + +function XMP:dump_metadata() + local xmp_string = self:generate_xmp_string() + local dir = get_output_dir() or '.' + f = io.open(dir .. '/' .. tex.jobname .. '.xmp_metadata.xml','w') + io.output(f) + io.write(xmp_string) + io.close(f) +end + +luatexbase.add_to_callback('stop_run', function() + SciKGTeX:warn_unused_command() + if SciKGTeX.PRODUCE_XMP_FILE then + XMP:dump_metadata() + end +end, 'at_end') + +-- Writing metadata packets +luatexbase.add_to_callback('finish_pdffile', function() + if XMP.paper then + local metadata_obj = XMP:attach_metadata_pdfstream() + local catalog = pdf.getcatalog() or '' + pdf.setcatalog(catalog..string.format('/Metadata %s 0 R', metadata_obj)) + --if SciKGTeX.PRODUCE_XMP_FILE then + -- XMP:dump_metadata() + --end + end +end, 'finish') + +-- TODO: real identifier assigned + +-- get the id or generate UUID +local output_dir = get_output_dir() or '.' +local header = read_header_of_file(output_dir .. '/' .. tex.jobname .. '.xmp_metadata.xml') +if header ~= nil then + id = extract_uuid_from_header(header) +end +if id == nil then + id = generate_UUID() + print('generate new id:', id) +end +XMP:add_paper_node(id) +XMP:add_namespace("rdf","http://www.w3.org/1999/02/22-rdf-syntax-ns#") +XMP:add_namespace("rdfs","http://www.w3.org/2000/01/rdf-schema#") +XMP:add_namespace("orkg","http://orkg.org/core#") +XMP:add_namespace("orkg_property","http://orkg.org/property/") + +SciKGTeX.XMP = XMP +return SciKGTeX
\ No newline at end of file diff --git a/Master/texmf-dist/tex/lualatex/scikgtex/scikgtex.sty b/Master/texmf-dist/tex/lualatex/scikgtex/scikgtex.sty new file mode 100644 index 00000000000..9f94c11a1b4 --- /dev/null +++ b/Master/texmf-dist/tex/lualatex/scikgtex/scikgtex.sty @@ -0,0 +1,149 @@ +%% ---------------------------------------------------------------- +%% scikgtex --- Scientific Knowledge Graph TeX (SciKgTeX) is a +%% LuaLaTeX package which makes it possible to annotate specific +%% research contributions in scientific documents. SciKGTeX will +%% enrich the document by adding marked contributions to PDF +%% metadata in a structured XMP format which can be picked up by +%% Search Engines and Knowledge Graphs. +%% More information on how to use the package can be found here: +%% https://github.com/Christof93/SciKGTeX#readme +%% +%% Author: Christof Bless +%% E-mail: christofbless@gmail.com +%% Released under the MIT License +%% See https://opensource.org/licenses/MIT +%% ---------------------------------------------------------------- +%% +\NeedsTeXFormat{LaTeX2e} +\ProvidesPackage{scikgtex}[2022/11/13 v2.1.1] + +\def\useignorespacesandallpars#1\ignorespaces\fi{% +#1\fi\ignorespacesandallpars} + +\makeatletter +\def\ignorespacesandallpars{% + \@ifnextchar\par + {\expandafter\ignorespacesandallpars\@gobble}% + {}% +} +\makeatother + +\RequirePackage{suffix} +\RequirePackage{hyperref} + +\errorcontextlines=5 + +\directlua { + SciKGTeX = require('scikgtex') +} + +\newcommand{\addmetaproperty}[2][]{% + \directlua{% + local new_property = "\luaescapestring{\unexpanded{#2}}"% + local ns = "\luaescapestring{\unexpanded{#1}}"% + SciKGTeX:add_property(new_property, ns)% + }% + \ignorespaces +}% + +\newcommand{\newpropertycommand}[2][]{% + \directlua{% + local new_property = "\luaescapestring{\unexpanded{#2}}"% + local ns = "\luaescapestring{\unexpanded{#1}}"% + SciKGTeX:make_new_command(new_property, ns)% + }% + \ignorespaces +}% + +\newcommand{\metatitle}[2][]{% + \directlua{% + local value = "\luaescapestring{\unexpanded{#2}}"% + SciKGTeX.XMP:set_title(value)% + }% + #2% +}% + +\WithSuffix\newcommand\metatitle*[2][]{% + \directlua{% + local value = "\luaescapestring{\unexpanded{#2}}"% + SciKGTeX.XMP:set_title(value)% + }% + \ignorespaces +}% + +\newcommand{\metaauthor}[2][]{% + \directlua{% + local value = "\luaescapestring{\unexpanded{#2}}"% + SciKGTeX.XMP:add_author(value)% + }% + #2% +}% + +\WithSuffix\newcommand\metaauthor*[2][]{% + \directlua{% + local value = "\luaescapestring{\unexpanded{#2}}"% + SciKGTeX.XMP:add_author(value)% + }% + \ignorespaces +}% + +\newcommand{\researchfield}[2][]{% + \directlua{% + local value = "\luaescapestring{\unexpanded{#2}}"% + SciKGTeX.XMP:set_researchfield(value)% + }% + #2% +}% + +\WithSuffix\newcommand\researchfield*[2][]{% + \directlua{% + local value = "\luaescapestring{\unexpanded{#2}}"% + SciKGTeX.XMP:set_researchfield(value)% + }% + \ignorespaces +}% + +\newcommand{\uri}[2]{% + \directlua{% + local label = "\luaescapestring{\unexpanded{#2}}"% + local uri = "\luaescapestring{\unexpanded{#1}}"% + SciKGTeX:print_entity(uri, label)% + }% +}% + +\newcommand{\contribution}[3][]{% + \directlua{% + local contrib_n = "\luaescapestring{\unexpanded{#1}}"% + local property = "\luaescapestring{\unexpanded{#2}}"% + local value = "\luaescapestring{\unexpanded{#3}}"% + SciKGTeX.XMP:add_annotation(contrib_n, property, value, 'annotation-id')% + }% + #3% +}% + +\WithSuffix\newcommand\contribution*[3][]{% + \directlua{% + local contrib_n = "\luaescapestring{\unexpanded{#1}}"% + local property = "\luaescapestring{\unexpanded{#2}}"% + local value = "\luaescapestring{\unexpanded{#3}}"% + SciKGTeX.XMP:add_annotation(contrib_n, property, value, 'annotation-id')% + }% + \ignorespaces +}% + +\newpropertycommand{researchproblem} +\newpropertycommand{result} +\newpropertycommand{method} +\newpropertycommand{objective} +\newpropertycommand{conclusion} + +%% Copyright (C) 2022 by Christof Bless <christofbless@gmail.com> +%% +%% This work may be distributed and/or modified under the +%% conditions of the MIT License. +%% +%% This work consists of the file scikgtex.sty +%% and the lua file scikgtex.lua. +%% +%% +%% End of file `scikgtex.sty'. diff --git a/Master/tlpkg/bin/tlpkg-ctan-check b/Master/tlpkg/bin/tlpkg-ctan-check index 63bb1555f1d..0ac2ec275e1 100755 --- a/Master/tlpkg/bin/tlpkg-ctan-check +++ b/Master/tlpkg/bin/tlpkg-ctan-check @@ -715,7 +715,7 @@ my @TLP_working = qw( schedule schemabloc schemata schola-otf scholax schooldocs schulmathematik sclang-prettifier schule schulschriften schwalbe-chess - sciposter scientific-thesis-cover scontents + scikgtex sciposter scientific-thesis-cover scontents scrambledenvs scratch scratch3 scratchx screenplay screenplay-pkg scripture scrjrnl scrlayer-fancyhdr scrlttr2copy scsnowman sdaps sdrt sduthesis diff --git a/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc b/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc index 7a9539a0956..e73542cb07d 100644 --- a/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc +++ b/Master/tlpkg/tlpsrc/collection-luatex.tlpsrc @@ -81,6 +81,7 @@ depend piton depend placeat depend plantuml depend pyluatex +depend scikgtex depend selnolig depend showhyphenation depend showkerning diff --git a/Master/tlpkg/tlpsrc/scikgtex.tlpsrc b/Master/tlpkg/tlpsrc/scikgtex.tlpsrc new file mode 100644 index 00000000000..e69de29bb2d --- /dev/null +++ b/Master/tlpkg/tlpsrc/scikgtex.tlpsrc |