65.9K
CodeProject 正在变化。 阅读更多。
Home

PyOOCalc - Python Libre/Open Office Calc 接口 API (UNO)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2015年12月20日

GPL3

4分钟阅读

viewsIcon

20460

用 Python 创建 Libre/Open Office Calc 文档、报告

引言

不时地,我需要为用户生成报告或其他文档。我指的是真正的最终用户,而不是其他开发者或系统管理员。真正设计精良的报告。

我在以下项目中曾有过这样的任务:

  • 文件流转项目
  • 会计系统
  • 房地产会计

最简单的方法是使用 **Office** 软件(如 **Libre/OpenOffice**)创建文档模板。用户无需开发者的帮助即可在 **Office** 中生成自己的模板。

背景

我的第一个经验是使用 **Microsoft Office**,但后来有必要开发跨平台解决方案,因此选择了 **OpenOffice**。

最常见的文档或报告包含

  • 标题
  • 表格
  • 页脚

因此,选择了 **OpenOffice Calc**。

第一个实现是使用 **C++**。我在多个项目中使用了那个库。但是 **Office** 的每个新版本都需要编译库。甚至需要对代码进行一些更改。我不得不为多个 Linux 发行版编译库。这是一项非常繁琐且耗时的任务。

这些困难促使我寻找更简单的解决方案。我查找了 **Office API** 以及支持的编程语言列表。我看到了 **Python**,找到一个简单的例子并尝试了一下。同一个 Python 脚本在不同的发行版和 **Office** 版本上都能很好地运行。

所以,就做出了选择。

描述

有许多 Python 库可以通过 API (UNO) 处理 Libre/OpenOffice。就我而言,最有趣的项目之一是 pyoo。它支持从打开/保存文档到单元格合并以及处理图表和图的许多功能。但没有一个实现了我需要的功能。

我需要为许多项目生成不同的文档,例如会计系统、房产管理、文件流转等。最简单的方法是使用标准的办公软件。最终用户可以毫不费力地创建自己的模板。

创建模板很容易,但如何知道数据应该插入到模板的哪个位置?我可以使用**单元格**索引(列、行)或名称(**E5**)。

但是,如果我想为报告使用多个模板怎么办?例如,一个报告用于横向格式,另一个用于纵向格式。不能保证我必须在不同模板的相同**单元格名称**或**单元格位置**中设置相同的值。因此,我必须将不同模板的规则存储在某处。我找到了一个更简单的方法,那就是 `NamedRange`。

`NamedRange` 是工作表中单元格或单元格范围的名称。`NamedRange` 在整个文档中是唯一的。

另一个未找到的功能是插入行。任何报告或发票都有一个带有页眉和页脚的表格。因此,我需要将行插入到表格区域并保留行的格式(字体、单元格合并等)。

主要特点

  • 打开和创建电子表格文档
  • 将文档保存到 OpenOffice 支持的所有格式
  • 插入和删除工作表
  • 插入行
  • 通过 `NamedRange` 设置/获取值
  • 通过单元格地址或名称设置/获取值

您可以在*examples*文件夹中找到一个包含 `NamedRanges` 的文档示例以及如何使用它的说明。

要求

**pyoocalc** 在 **Python 3** 上运行。

唯一的依赖项是 Python-UNO 库(导入为 uno 模块)。它通常随 Office 套件一起安装。在基于 Debian 的系统上,可以安装为 `python-uno` 或 `python3-uno` 包。

显然,您还需要 **OpenOffice** 或 **LibreOffice Calc**。在 Debian 系统上,可以作为 `libreoffice-calc` 包提供。

Install

您可以将 *pyoocalc.py* 文件复制到您的 `PYTHONPATH` 目录中。

用法

以监听模式启动 OpenOffice.org

**pyoocalc** 需要一个正在运行的 `OpenOffice` 或 `LibreOffice` 实例才能连接。在 Ubuntu 上,您可以使用类似以下命令的命令从命令行启动 `LibreOffice`:

$ soffice --accept="socket,host=localhost,port=2002;urp;" --norestore --nologo --nodefault # --headless

LibreOffice 将监听 localhost 连接的 2002 端口。或者,可以使用命名管道:

$ soffice --accept="pipe,name=hello;urp;" --norestore --nologo --nodefault # --headless

如果使用了 `--headless` 选项,即使打开文档,也不会显示用户界面。

有关更多信息,请运行:

$ soffice --help

建议直接启动 soffice 二进制文件。可能有各种脚本(例如 `libreoffice`)会运行 `soffice` 二进制文件,但您可能无法获得正在运行程序的正确 PID。

Using the Code

以下是使用库代码的简要说明:

import pyoocalc

# open document
doc = pyoocalc.Document()
file_name = os.getcwd() + "/example.ods"
doc.open_document(file_name)

# Get document fields
fields = doc.fields()

# Get field "HEADER"
field = fields.field("HEADER")
print ("Document header is: " + str(field.is_null()))

# Set values
field = fields.field("TABLE_NAME")
field.set_value("Test table name")
print ("New table name is: " + field.value())

# Insert 5 rows
field1 = fields.field("FIELD_1")
num_rows = 5
step = 2
if num_rows > 0:
    field1.insert_rows(num_rows=num_rows-1, step=step, columns_to_copy=200)
for i in range(1, num_rows + 1):
    field1.set_value("F1." + str(i), 0, i * step - (step - 1))

# Set value="value1" at column=1, row=1 (B1)
sheet = doc.sheets().sheet(0)
sheet.set_cell_value_by_index(1, 0, "value1")
print (sheet.cell_value_by_index(1, 0))
del doc

您可以在这里找到一个示例文件:

./src/examples/example.py

运行示例

$ python3 example.py

文档

您可以在这里找到文档:

./doc/index.html

测试

自动集成单元测试涵盖了大部分代码。

测试套件假定 `OpenOffice` 或 `LibreOffice` 正在运行,并且正在 localhost 的 2002 端口上监听。

测试脚本路径

$ ./src/unit-tests/test.py

运行测试

$ python3 test.py

输出必须如下:

$ python3 test.py 
............
----------------------------------------------------------------------
Ran 12 tests in 8.719s

OK
© . All rights reserved.