0

I have successfully loaded XML in LuaLaTeX with help of Michal.h21. Now I would like to store all the customized defined Lua Script in a separate LaTeX Style file, like bibr.sty, so that I will call just \usepackage{bibr} in the LaTeX file.

In the bibr.sty file all the customized defined lua script need to be defined.

My BIBR Cross-Links XML file is below:

\documentclass{article}
\usepackage{luacode}
\usepackage{natbib}

\begin{document}

\begin{luacode*}
local domobject = require "luaxml-domobject"
local transform = require "luaxml-transform"
sample = [[
<?xml version="1.0" encoding="utf-8"?>
<art>
<title>Scattering of flexural waves an electric current</title>
<para>The first <xref ref-type="section" rid="Sec1">Section 1</xref> description and correlation between gait impairment and hydrocephalus were made in 1965 by Hakim and Adam (<xref ref-type="bibr" rid="B1">1</xref>). The etiology of idiopathic normal pressure hydrocephalus (iNPH) has not yet been entirely understood (<xref ref-type="bibr" rid="B2">2</xref>&#x02013;<xref ref-type="bibr" rid="B5">5</xref>). In elderly patients, other conditions such as spinal canal stenosis, Parkinson&#x00027;s disease, and polyneuropathy may influence the gait negatively.</para>
</art>]]

local dom = domobject.parse(sample)
local function process_instructions(el)

-- try to find <xref> followed by dash and another <xref>
-- we then expand rid attributes
for _, xref in ipairs(dom:query_selector("xref[ref-type='bibr']")) do
  local first = xref:get_sibling_node(1)
  local second = xref:get_sibling_node(2)
  if first and second and
     first:is_text() and first:get_text() == "–" and -- next node must be "–" text
     second:is_element() and second:get_element_name() == "xref" -- second element must be <xref>
  then
    local rid1 = xref:get_attribute("rid") or ""
    local rid2 = second:get_attribute("rid") or ""
    local prefix1, number1 = rid1:match("(%a+)(%d+)")
    local prefix2, number2 = rid2:match("(%a+)(%d+)")
    -- expand only if prefixes match each other
    if prefix1 and prefix2 and prefix1 == prefix2 then
      -- expand numbers
      local t = {}
      for i = number1, number2 do
        t[#t+1] = prefix1 .. math.floor(i)
      end
      -- save expanded numbers
      xref:set_attribute("rid", table.concat(t, ","))
      -- remove unnecessary elements
      first:remove_node()
      second:remove_node()
    end
  end

  
end
end

process_instructions(dom:root_node())

local transformer = transform.new()
transformer:add_action("title", "\\section{@<.>}")
transformer:add_action("para", "@<.>\\par")
transformer:add_action("xref[ref-type='bibr']", "\\citep{@{rid}}")
-- handle the processing instruction
transformer:add_custom_action("lualatex-instruction",
    function(el)
        return el:get_attribute("text")
    end)
local result = transformer:process_dom(dom)
-- Print Output Result in Command-Prompt/Terminal
print(result)
-- Print Output Result in PDF uncomment below
--transform.print_tex(result)
\end{luacode*}
\end{document}

How to achieve this?

3
  • 1
    why do you want a latex style here rather than just include the lua? Commented Jul 26, 2023 at 15:19
  • @DavidCarlisle: I have need to include many developments through lua script. So, Its better to include all the lua code in Main LaTeX file, to maintain each and separate LaTeX Style file (for fixing any bugs our ends in future).
    – Balaji
    Commented Jul 26, 2023 at 15:39
  • 1
    even if you offer a .sty to the user to save them doing \directlua{require("Balaji")} I would put the lua in a .lua file and include it that way in the latex package, using lua inline in the tex especially via luacode is tricky and inefficient. Commented Jul 26, 2023 at 15:43

2 Answers 2

3

As David suggested, it is a good idea to move the Lua code to a standalone file, to prevent some interaction issues between TeX and Lua. It could look like this, bibr.lua:

local M = {}
local domobject = require "luaxml-domobject"
local transform = require "luaxml-transform"

local function process_instructions(el)
  for _, child in ipairs(el:get_children()) do
    local ntype = child:get_node_type()
    if ntype == "PI" and child._name=="LuaLaTeX" then
      local text = child._attr[ "_text" ]
      local newel = el:create_element("lualatex-instruction", {text = text})
      child:replace_node(newel)
    end
    if child:is_element() then
      process_instructions(child)
    end
  end
end

function M.process(sample)
  local dom = domobject.parse(sample)
  -- try to find <xref> followed by dash and another <xref>
  -- we then expand rid attributes
  for _, xref in ipairs(dom:query_selector("xref[ref-type='bibr']")) do
    local first = xref:get_sibling_node(1)
    local second = xref:get_sibling_node(2)
    if first and second and
      first:is_text() and first:get_text() == "–" and -- next node must be "–" text
      second:is_element() and second:get_element_name() == "xref" -- second element must be <xref>
    then
      local rid1 = xref:get_attribute("rid") or ""
      local rid2 = second:get_attribute("rid") or ""
      local prefix1, number1 = rid1:match("(%a+)(%d+)")
      local prefix2, number2 = rid2:match("(%a+)(%d+)")
      -- expand only if prefixes match each other
      if prefix1 and prefix2 and prefix1 == prefix2 then
        -- expand numbers
        local t = {}
        for i = number1, number2 do
          t[#t+1] = prefix1 .. math.floor(i)
        end
        -- save expanded numbers
        xref:set_attribute("rid", table.concat(t, ","))
        -- remove unnecessary elements
        first:remove_node()
        second:remove_node()
      end
    end


  end

  process_instructions(dom:root_node())

  local transformer = transform.new()
  transformer:add_action("title", "\\section{@<.>}")
  transformer:add_action("para", "@<.>\\par")
  transformer:add_action("xref[ref-type='bibr']", "\\citep{@{rid}}")
  -- handle the processing instruction
  transformer:add_custom_action("lualatex-instruction",
  function(el)
    return el:get_attribute("text")
  end)
  local result = transformer:process_dom(dom)
  print(result)
  transform.print_tex(result)
end

function M.process_file(filename)
  local f = io.open(filename, "r")
  if not f then return nil, "Cannot open file: " .. filename end
  local content = f:read("*all")
  f:close()
  M.process(content)
end

return M

I've moved the code that was originally in the main body of the luacode environment to a function M.process. The M table is returned from this library, so it will enable you to use this code in this way:

 local bibr = require "bibr"
 bibr.process("xml code...")

I've also made another function, M.process_file, which will transform XML file, so you don't need to pass the XML code to your document.

You then need a LaTeX package that will provide commands that can be used in your documents. It can look like this, bibr.sty:

\ProvidesPackage{bibr}

\NewDocumentEnvironment{processbibr}{+b}{%
  \directlua{
    local bibr = require "bibr"
    bibr.process([[\unexpanded{#1}]])
  }
}{}

\NewDocumentCommand\processbibrfile{m}{%
  \directlua{%
    local bibr = require "bibr"
    bibr.process_file("#1")
  }
}

\endinput

It provides processbibr environment and \processbibrfile command. The environment can be used if you want to put the XML code in the document, the command for including external XML files.

It can be used like this:

\documentclass{article}
\usepackage{natbib}
\usepackage{bibr}
\begin{document}
\begin{processbibr}
<?xml version="1.0" encoding="utf-8"?>
<art>
<title>Scattering of flexural waves an electric current</title>
<para>Smart testing structures are $a+b$ components Reduce acoustic noise used in engineering applications that are capable of sensing or reacting to their environment change <?LuaLaTeX Sample XXX1?> their mechanical properties. in a predictable and desired manner. In addition to carrying mechanical loads, <?LuaLaTeX \hspace*{12pt}Abc?> alleviate vibration, reduce acoustic noise, change their mechanical properties as required or monitor their own condition.</para>
<para>The first <xref ref-type="section" rid="Sec1">Section 1</xref> description and correlation between gait impairment and hydrocephalus were made in 1965 by Hakim and Adam (<xref ref-type="bibr" rid="B1">1</xref>). The etiology of idiopathic normal pressure hydrocephalus (iNPH) has not yet been entirely understood (<xref ref-type="bibr" rid="B2">2</xref>&#x02013;<xref ref-type="bibr" rid="B5">5</xref>). In elderly patients, other conditions such as spinal canal stenosis, Parkinson&#x00027;s disease, and polyneuropathy may influence the gait negatively.</para>
</art>
\end{processbibr}

\processbibrfile{test.xml}
\end{document}

In general, I think it is better to use \processbibrfile, as you shouldn't run into strange errors that can happen when you include the XML file directly to your TeX file.

This is the result:

enter image description here

2

You put this

\ProvidesPackage{bibr}
\RequirePackage{luacode}
\begin{luacode*}
% HERE YOUR CODE, exactly as it is in your example
\end{luacode*}

in a file, and save it with .sty extension in the same folder as your .tex.

2
  • @lacobus1983: It's working fine. But Input may different each XML. In this file it's sample. How to get XML Filename from user when running lualatex?
    – Balaji
    Commented Jul 26, 2023 at 13:07
  • @Balaji I'm not a lua expert... Perhaps you should use a method to read the file, have a look here: tex.stackexchange.com/questions/97822/… Commented Jul 26, 2023 at 13:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .