插入 libreoffice 表作为输入

插入 libreoffice 表作为输入

这个问题导致了一个新的方案的出现:
odsfile

假设您有一个localc电子表格myspread.ods,并且想要将范围的内容H4:I40作为表格插入到您的 latex 文档中。我知道我可以导出表格或只是进行一些复制和粘贴。但是,是否可以编写如下代码:

\includespread{file=myspread.ods,range=H4:I40}

然后,当相应的电子表格发生变化时,我的文档中的表格LaTeX也会发生变化。

如果能够将表的全局外观属性作为可选参数进行修改就好了\includespread

答案1


编辑:现在有 LaTeX 包可供测试https://github.com/michal-h21/odsfile

在我将其发布到 CTAN 之前,非常欢迎对文档文件中的样式/语法/拼写的任何评论,以及对源代码的评论。


有使用luatex的zip库和纯lua xml处理库的解决方案LuaXML,您应该将其安装到与 相同的目录中odsfile.lua

odsxml格式由文件中打包的文件数组成zip。数据包含在 content.xml文件中。其结构如下:

<?xml version="1.0" encoding="UTF-8"?>
<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" ... >
  <office:scripts/>
  <office:font-face-decls>
    ...
  </office:font-face-decls>
  <office:automatic-styles>
    ...
  </office:automatic-styles>
  <office:body>
    <office:spreadsheet>
      <table:table table:name="List1" table:style-name="ta1" table:print="false">
        <table:table-column table:style-name="co1" table:number-columns-repeated="3" table:default-cell-style-name="Default"/>
        <table:table-row table:style-name="ro1">
          <table:table-cell office:value-type="string">
            <text:p>Hello</text:p>
          </table:table-cell>
          <table:table-cell office:value-type="float" office:value="1">
            <text:p>1</text:p>
          </table:table-cell>
          <table:table-cell table:formula="of:=[.B1]+2" office:value-type="float" office:value="3">
            <text:p>3</text:p>
          </table:table-cell>
        </table:table-row>
        ...
      </table:table>
      <table:table table:name="List2" table:style-name="ta1" table:print="false">
        ...
      </table:table>
    </office:spreadsheet>
  </office:body>
</office:document-content>

从我创建的示例文件来看,工作表数据似乎保存在office:document-content / office:body / office:spreadsheet / table:table路径中。表格行保存为,table:table-row 单元格保存为table:table-cell。每个单元格都设置了其内容的数据类型,如果单元格包含公式,则保存在table:formula属性中。在每种情况下,准备打印的计算值都包含在 的子元素中table-celltext:p我希望这个结构也能用与我的不同的版本创建Open/Libre Office Calc,否则代码将无法正常工作 :(

有了LuaXML,我们可以转换xmllua表格,然后可以使用标准lua技术轻松处理。

图书馆odsfile.lua

module(...,package.seeall)
require "zip"
dofile("xml.lua")
dofile("handler.lua")


function load(filename)
  local p = {
    file = zip.open(filename),
    content_file_name = "content.xml",
    loadContent = function(self,filename)
      local treehandler = simpleTreeHandler()
      local filename = filename or self.content_file_name  
      local xmlfile = self.file:open(filename)
      local text = xmlfile:read("*a")
      local xml = xmlParser(treehandler)
      xml:parse(text)
      return treehandler
    end
  }
  return p
end

function getTable(x,table_name)
  local tables = x.root["office:document-content"]["office:body"]["office:spreadsheet"]["table:table"]
  if type(tables) == "table" and table_name ~= nil then 
    for k,v in pairs(tables) do
      if(v["_attr"]["table:name"]==table_name) then
        return v
      end 
    end
  elseif type(tables) == "table" and table_name == nil then
    return tables[1]  
  else 
    return tables  
  end
end

function tableValues(tbl,x1,y1,x2,y2)
  local t= {}
  if type(tbl["table:table-row"])=="table" then
    local rows = table_slice(tbl["table:table-row"],y1,y2)
    for k,v in pairs(rows) do
      local j = {}
      if #v["table:table-cell"] > 1 then
        local r = table_slice(v["table:table-cell"],x1,x2)
        for p,n in pairs(r) do
          table.insert(j,{value=n["text:p"],attr=n["_attr"]})
        end
      else
        local p = {value=v["table:table-cell"]["text:p"],attr=v["table:table-cell"]["_attr"]} 
        table.insert(j,p) 
      end  
      table.insert(t,j)
    end
  end
  return t
end

function getRange(range)
  local r = range:lower()
  local function getNumber(s)
    if s == "" or s == nil then return nil end
    local f,ex = 0,0
    for i in string.gmatch(s:reverse(),"(.)") do
      f = f + (i:byte()-96) * 26 ^ ex
      ex = ex + 1 
    end
    return f
  end
  for x1,y1,x2,y2 in r:gmatch("(%a*)(%d*):*(%a*)(%d*)") do
    return getNumber(x1),tonumber(y1),getNumber(x2),tonumber(y2) 
   --print(string.format("%s, %s, %s, %s",getNumber(x1),y1,getNumber(x2),y2))
  end
end

function table_slice (values,i1,i2)
  -- Function from http://snippets.luacode.org/snippets/Table_Slice_116
  local res = {}
  local n = #values
  -- default values for range
  i1 = i1 or 1
  i2 = i2 or n
  if i2 < 0 then
    i2 = n + i2 + 1
  elseif i2 > n then
    i2 = n
  end
  if i1 < 1 or i1 > n then
    return {}
  end
  local k = 1
  for i = i1,i2 do
    res[k] = values[i]
    k = k + 1
  end
  return res
end

函数odsfile.load(filename)返回odsfile对象,loadContent()方法返回lua表示content.xml文件的表。我们可以使用 从电子表格中选择工作表odsfile.getTable(xmlobject,sheet_name)。如果我们省略sheet_name,则选择电子表格中的第一个工作表。

可以使用 读取工作表中的数据odsfile.tableValues(sheet, x1, y1, x2, y2)x1 - y2是要选择的范围,它们可以为空,在这种情况下会选择整个行和单元格。 要将标准的表格范围表达式转换a1:b2为此表示形式,odsfile.getRange(range)可以使用函数。

现在有一些LaTeX界面。odsfile.sty

\ProvidesPackage{odsfile.sty}
\RequirePackage{luacode,xkeyval}

%keyval keys

\define@key{includespread}{file}{\loadodsfile{#1}}
\define@key{includespread}{sheet}{\luaexec{sheetname = "\luatexluaescapestring{#1}"}}
\define@key{includespread}{range}{\luaexec{%
local x1,y1,x2,y2 = odsreader.getRange("\luatexluaescapestring{#1}")%
range = {x1,y1,x2,y2}%
}}


\begin{luacode*}
odsreader = require("odsfile")
odsfile   = nil
sheetname     = nil
range     = {nil,nil,nil,nil}
\end{luacode*}

\newcommand\loadodsfile[2][]{%
  \setkeys{includespread}{#1}%
  \luaexec{%
    odsfile     = "\luatexluaescapestring{#2}"%
    local ods   = odsreader.load(odsfile)%
    odsfile, e  = ods:loadContent()%
  }%
}

\newcommand\includespread[1]{%
  \luaexec{range = {nil,nil,nil,nil}}%
  \setkeys{includespread}{#1}%
  \luaexec{%
    local body = odsreader.getTable(odsfile,sheetname)
    local values =odsreader.tableValues(body,range[1],range[2],range[3],range[4])
    local rowValues = function(row)
      local t={} 
      for _,column in pairs(row) do table.insert(t,column.value) end
      return t
    end   
    for i,row in pairs(values) do
      tex.sprint(table.concat(rowValues(row)," & ").."\\\\")
    end
  }
}
\endinput

在这个版本中,您必须手动指定表列,但分析例如第一行的内容并从中生成列规范应该并不困难。

使用示例:

\documentclass{article}
\usepackage{odsfile,lmodern}
\begin{document}

\pagestyle{empty}

Inserting range from sheet

\begin{tabular}{l l}
\includespread{file=pokus.ods,sheet=List1,range=a2:b4}
\end{tabular}

Including of whole sheet

\begin{tabular}{l l l}
\includespread{}
\end{tabular}

Inserting second sheet

\begin{tabular}{l}
\includespread{file=pokus.ods,sheet=List2}
\end{tabular}


\end{document}

在此处输入图片描述

答案2

您可以通过 \write18 传递命令管道来将 document.xml 解压缩到 stdin 并放入 lxprintf (LTxml 套件的一部分)来实现此目的 http://www.ltg.ed.ac.uk/software/ltxml/它允许您从 XML 中提取内容),然后通过 awk 或其他方式处理结果。或者直接使用 Perl/Tcl/Python。

相关内容