jdum / odfdo Goto Github PK
View Code? Open in Web Editor NEWpython library for OpenDocument format (ODF)
License: Apache License 2.0
python library for OpenDocument format (ODF)
License: Apache License 2.0
When creating a new section using, for example, sectn=Section(style='sss', name='nnn') the section will be created with style & name both set to 'sss'.
The reason for this appears to be line 51 of section.py which reads 'self.name=style' instead of 'self.name=name'
Please forgive my not forking, patching & creating a pull request as I'm currently developing some software that writes .ODT files using the pip version of odfdo & don't want to risk confusing my environment
As a reminder for me:
Hey,
First of all great project!
I just have a question regarding accessing lists (bullet points) within tables. Basically, I have many documents that are comprised of tables that have identical structure (rows / columns etc) and I'm trying to extract all data from all tables from multiple documents in a meaningful way. The problem is some cells contain bullet points (lists).
Is there any way to get all text in a table cell with one method?
From some testing, it appears if I use get_value / get_values it doesn't return the text that is part of the List. However, I can use get_cells --> get_lists to extract the text, but I would need to check for the presence of any lists for each cell. Lastly, I could also use get_styled_elements for each cell, but this might get tricky.
What would you recommend? Thank you in advance and keep up the excellent work.
A reminder for me:
Hi, I had the following errors when installing ODFDO in my system, I have Ubuntu 20.04.6 and Python 3.10.4,
File "setup.py", line 2
SyntaxError: Non-ASCII character '\xc3' in file setup.py on line 2, but no encoding declared
solution: EDIT edit setup.py and add # -- coding: utf-8 -- in the first line of code
ImportError: No module named setuptools
solution: ~/odfdo$ pip install setuptools
File "setup.py", line 28, in
from setuptools import find_packages, setup
ImportError: No module named setuptools
solution: activate my_envpy3 and YOU NEED TO RUN WITHOUT SUDO
These are the steps I followed and this is the way I corrected them, in case someone needs the solution, thank you
~$ git clone https://github.com/jdum/odfdo.git
Cloning into 'odfdo'...
remote: Enumerating objects: 627, done.
remote: Counting objects: 100% (301/301), done.
remote: Compressing objects: 100% (211/211), done.
remote: Total 627 (delta 149), reused 150 (delta 90), pack-reused 326
Receiving objects: 100% (627/627), 4.08 MiB | 7.69 MiB/s, done.
Resolving deltas: 100% (264/264), done.
~$ cd odfdo
~/odfdo$ sudo python setup.py install
~$ [sudo] password for:
File "setup.py", line 2
SyntaxError: Non-ASCII character '\xc3' in file setup.py on line 2, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
**** EDIT ****
edit setup.py and add # -- coding: utf-8 -- in the first line of code
~/odfdo$ sudo python setup.py install
ImportError: No module named setuptools
~/odfdo$ pip install setuptools
Requirement already satisfied: setuptools
~/odfdo$ sudo python setup.py install
Traceback (most recent call last):
File "setup.py", line 28, in
from setuptools import find_packages, setup
ImportError: No module named setuptools
~/odfdo$ conda activate my_envpy3
***** IN my_envpy3 YOU NEED TO RUN WITHOUT SUDO ****
(my_envpy3):~/odfdo$ python setup.py install
running install....
.... Finished processing dependencies for odfdo==3.3.2
Detected (at least) in spreadsheet context / libreOffice 6, a clone of a document does not permit to work on tables. Table of cloned document is empty.
Hi
I'm trying to create a presentation with an image as the background. While looking through the document's XML code, which I created using Apache Open Office, I noticed that I have to create a draw:fill-image object like this:
<office:styles>
<draw:fill-image
draw:name="background"
xlink:href="Pictures/10000000000004B000000640068E29EE.jpg"
xlink:type="simple"
xlink:show="embed"
xlink:actuate="onLoad" />
It seems that the DrawFillImage class is responsible for this, but I couldn't find instructions on how to use it.
So, I attempted to insert the style in the following manner:
self.document.insert_style('<draw:fill-image'
' draw:name="background"'
' xlink:href="Pictures/10000000000004B000000640068E29EE.jpg"
' xlink:type="simple"'
' xlink:show="embed"'
' xlink:actuate="onLoad"'
' />')
And I encountered an error:
File "C:\Users\Kreg\PycharmProjects\slide_convertor\venv\lib\site-packages\odfdo\document.py", line 547, in insert_style
family = style.family
AttributeError: 'DrawFillImage' object has no attribute 'family'
On the other hand, I created a script to enumerate all the styles in my "image_background.odp" presentation document, which contains an image as a background:
from odfdo import Document
doc = Document("image_background.odp")
doc.show_styles()
I encountered the same error:
Traceback (most recent call last):
File "C:\Users\Kreg\PycharmProjects\slide_convertor\get_styles.py", line 5, in <module>
doc.show_styles()
File "C:\Users\Kreg\PycharmProjects\slide_convertor\venv\lib\site-packages\odfdo\document.py", line 674, in show_styles
"family": style.family or "",
AttributeError: 'DrawFillImage' object has no attribute 'family'
Could you please provide a guide for working with the DrawFillImage class?
I have created a test ods document using the following code:
from odfdo import Document, Table
body = doc.body
table = Table("Frequency Table")
table.set_values([[1,2],[2,3]])
body.append(table)
doc.save("hello.ods",pretty=True)
It has an empty extra empty sheet "Feuille 1" !
At the moment, it is not really clear what has been in each release. While I could have a look at the corresponding commits as well, this just complicates it as these changes seem to include rendered doc updates as well.
Therefore I would appreciate if a suitable changelog would be maintained to quickly see what changed in each version and what might break existing code for example.
I'm attempting to modify the underlying data in a chart within an existing text document. The chart is placed inside a table for formatting. In the main content.xml for the document, I can see the following:
<table:table table:name="Table1" table:style-name="Table1">
<table:table-column table:style-name="Table1.A" table:number-columns-repeated="3" />
<table:table-row>
<table:table-cell table:style-name="Table1.A1" office:value-type="string">
<text:p text:style-name="Table_20_Contents">
<draw:frame draw:style-name="fr3" draw:name="Performance_20_Chart"
text:anchor-type="paragraph" svg:x="0.0598in" svg:y="0.1402in"
svg:width="2.1283in" svg:height="1.6075in" draw:z-index="1">
<draw:object xlink:href="./Object 1" xlink:type="simple"
xlink:show="embed" xlink:actuate="onLoad" />
<draw:image xlink:href="./ObjectReplacements/Object 1"
xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" />
<svg:desc>chart</svg:desc>
</draw:frame>
</text:p>
</table:table-cell>
And within the content.xml file (./Object 1/content.xml) for the chart I see a chart node and table node that describe the chart and it's data.
<office:body>
<office:chart>
<chart:chart svg:width="5.406cm" svg:height="4.083cm" xlink:href="." xlink:type="simple"
chart:class="chart:ring" chart:style-name="ch1">
<chart:title svg:x="1.35cm" svg:y="0.217cm" chart:style-name="ch2">
<text:p>Performance</text:p>
</chart:title>
<chart:plot-area chart:style-name="ch3" chart:data-source-has-labels="both"
svg:x="0.108cm" svg:y="1.077cm" svg:width="5.19cm" svg:height="2.925cm">
<chart:coordinate-region svg:x="1.241cm" svg:y="1.078cm" svg:width="2.924cm"
svg:height="2.924cm" />
<chart:axis chart:dimension="x" chart:name="primary-x" chart:style-name="ch4"
chartooo:axis-type="auto">
<chartooo:date-scale />
<chart:categories table:cell-range-address="local-table.$A$2:.$A$3" />
</chart:axis>
<chart:axis chart:dimension="y" chart:name="primary-y" chart:style-name="ch5">
<chart:grid chart:style-name="ch6" chart:class="major" />
</chart:axis>
<chart:series chart:style-name="ch7"
chart:values-cell-range-address="local-table.$B$2:.$B$3"
chart:label-cell-address="local-table.$B$1" chart:class="chart:circle">
<chart:data-point chart:style-name="ch8" />
<chart:data-point chart:style-name="ch9" />
</chart:series>
<chart:wall chart:style-name="ch10" />
<chart:floor chart:style-name="ch11" />
</chart:plot-area>
<table:table table:name="local-table">
<table:table-header-columns>
<table:table-column />
</table:table-header-columns>
<table:table-columns>
<table:table-column />
</table:table-columns>
<table:table-header-rows>
<table:table-row>
<table:table-cell office:value="">
<text:p />
</table:table-cell>
<table:table-cell office:value-type="string" office:value="Column1">
<text:p>Column 1</text:p>
</table:table-cell>
</table:table-row>
</table:table-header-rows>
<table:table-rows>
<table:table-row>
<table:table-cell office:value-type="string" office:value="Space">
<text:p>Space</text:p>
</table:table-cell>
<table:table-cell office:value-type="float" office:value="16">
<text:p>10</text:p>
</table:table-cell>
</table:table-row>
<table:table-row>
<table:table-cell office:value-type="string" office:value="Score">
<text:p>Score</text:p>
</table:table-cell>
<table:table-cell office:value-type="float" office:value="84">
<text:p>90</text:p>
</table:table-cell>
</table:table-row>
</table:table-rows>
</table:table>
</chart:chart>
</office:chart>
However, when I attempt to get all tables using "doc.body.get_tables()", the table for the chart is not returned. How does one manipulate the data of a chart within a text document?
LibreOffice 7.3.7.2
odfdo 3.7.7
I try to build a document with a section inside it to have two columns in this section.
I didn't find a way to specify that the created section has 2 columns. Here my attempt:
title = "My great document"
writer = Document('text')
writer.body.append(Paragraph(title))
writer.body.append(Element.from_tag("text:soft-page-break"))
writer.body.append(Header(1, "New page"))
writer.body.append(Paragraph("A first Paragraph"))
section_style = Style(name="Twocol",
family="section",
display_name="Two columns"
)
section_style.set_properties(properties={"fo:column-count":"2"}, area="columns")
section = Section(name="Section1", style = section_style)
section.append(Header(2,"Something:"))
section.append(Paragraph("Blabla"))
section.append(Header(2,"Something else:"))
section.append(Paragraph("Blabla"))
section.append(Header(2,"Something else:"))
section.append(Paragraph("Blabla"))
writer.body.append(section)
writer.body.append(Header(1, "End part"))
writer.body.append(Paragraph("A last Paragraph"))
#section_style = Element.from_tag(
#( '<style:style style:name="Sect1" style:family="section"><style:section-properties style:editable="false"><style:columns fo:column-count="2" fo:column-gap="0.497cm"><style:column style:rel-width="32767*" fo:start-indent="0cm" fo:end-indent="0.248cm"/><style:column style:rel-width="32768*" fo:start-indent="0.248cm" fo:end-indent="0cm"/></style:columns></style:section-properties></style:style>'
#)
#)
writer.save("mydoc.odt")
The document is created with the section, but the section doesn't have 2 columns.
I tried also to add a break page
I have also tried to define the style from a tag (see what is commented), without success.
I tried also to add a break page after the title, without more success.
What have I missed?
Due to lack of documentation or examples, it is hard to figure out whether odfdo provides a way to a) locating elements in an existing tree (e.g. a user field), b) any way of filling those fields in an existing document.
Please, help.
hi,
I can't find the way to insert a page break.
Is there already a function for this as paragraph does not accept
doc.body.append(Paragraph("\u000C"))
https://www.fileformat.info/info/unicode/char/000c/index.htm
hi,
I can't find the way to apply text and table style on a cell.
table cell style (created with create_table_cell_style) controls borders, padding, shadow and background (no text style)
paragraph style (created in style document) controls all I need except borders
is there a way to control both for table-cell?
I thought about applying table template, but it is not merged from style_document.
The default document language is french. This might be not what most users want. The code in the meta.py example
document.set_language('fr-FR')
does not work. This should be the most pythonic way of doing this.
Hi, after few tries, I'm wondering if it's possible to apply a column style (basically a column width) in a table appended in a text document. I've seen the recipe for doing a such styling in a spreadsheet, unfortunately, this doesn't work in my text document.
col_style` = Style("table-column", width="3.6cm", bold=True)
name = doc.insert_style(style=col_style, automatic=True)
for column in table.get_columns():
column.style = name
table.set_column(column.x, column)
Is there a way to set the width of a column in a text document, then?
In my code at the bottom of this issue I'm appending an image_frame
directly to the body of the document. When Iopen the resulting odt file in LibreOffice, the image is not shown, because odfdo inserts a paragraph before the draw:frame
element
<text:p text:style-name="Standard"/>
<draw:frame draw:style-name="fr1" draw:name="Bild1" text:anchor-type="page" text:anchor-page-number="1" svg:x="3cm" svg:y="3cm" svg:width="4.001cm" svg:height="2.379cm" draw:z-index="0">
<draw:image xlink:href="Pictures/10000000000001D800000119335792A6F1966427.png" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" draw:mime-type="image/png"/>
</draw:frame>
I suggest that the default paragraph should be inserted behind the elements appended to the body. Workaround: When I remove the default paragraph, the image will be shown in LibreOffice:
# Remove Standard paragraph before draw:frame
p = body.get_paragraph()
if not p==None:
body.delete(p)
Python code to append an image_frame
directly to the body of the document
from odfdo import Document, Paragraph, Frame, Style
doc = Document("text")
doc.insert_style(Style(name="fr1", family="graphic", parent_style="Graphics", vertical_pos="from-top", vertical_rel="page",
horizontal_pos="from-left", horizontal_rel="page"), automatic=True)
body = doc.body
uri = doc.add_file("10000000000001D800000119335792A6F1966427.png")
image_frame = Frame.image_frame(uri, size=("4cm", "2.38cm"), anchor_type="page", anchor_page=1, position=("14.7cm", "1.23cm"), style="fr1")
body.append(image_frame)
doc.save(target='test_picture.odt', pretty=True)
Let's assume a simple sequence, read an ODT, write it to some other file.
mydoc = Document(inp_fname)
content = mydoc.get_part('content')
mydoc.save(target=output_fname, pretty=True)
The call to get_part
shouldn't be doing much, but it is essential for the bug to show up. Probably reading anything from mydoc will trigger it.
If the input ODT contains simple text paragraphs. However, some of the text is edited, delete a letter in a word, or add a letter in a word. The result is a Paragraph
with multiple span
s. Something like
<text:p text:style-name="P7">
<text:span text:style-name="T12">This is an example with =></text:span>
<text:span text:style-name="T5"> v</text:span>
<text:span text:style-name="T8">8</text:span>
<text:span text:style-name="T5">.1.</text:span>
<text:span text:style-name="T8">4</text:span>
<text:span text:style-name="T5"> <</text:span>
<text:span text:style-name="T12">= spaces </text:span>
<text:span text:style-name="T13">after reading and writing with odfdo.</text:span>
</text:p>
The input document shows:
This is an example with => v8.1.4 <= spaces after reading and writing with odfdo.
The output document shows:
This is an example with => v 8 .1. 4 < = spaces after reading and writing with odfdo.
for selectedParagraph in body.get_paragraphs():
# Work on the element itself
selectedParagraph.set_span("Text Body")
so I tried the append route (as described in the recipes) but that just adds an extra element. I hunted down what seems to be the correct way to do it, which is 'set_span' since I'm iterating through the paragraphs but... no joy.
Still stays as "Default Paragraph Style".
What gives?
Additional
For applying a style to a paragraph the recipes offer:
body.append(Paragraph("some text", style="Text Body"))
However, append does exactly what it is designed to do and basically copies the paragraph.
windows 11
Traceback (most recent call last):
File "run_tests.py", line 3, in <module>
from external.tests import main_test
File "main_test.py", line 6, in <module>
from odsparsator import odsparsator
File "\Lib\site-packages\odsparsator\odsparsator.py", line 21, in <module>
from odfdo import Document, Element
File "\Lib\site-packages\odfdo\__init__.py", line 138, in <module>
from .bookmark import Bookmark, BookmarkEnd, BookmarkStart
File "\Lib\site-packages\odfdo\bookmark.py", line 27, in <module>
from .element import Element, PropDef, register_element_class
File "\Lib\site-packages\odfdo\element.py", line 39, in <module>
from lxml.etree import (
ImportError: cannot import name '_ElementStringResult' from 'lxml.etree' (\Lib\site-packages\lxml\etree.cp311-win_amd64.pyd)
python -m pip uninstall lxml
Found existing installation: lxml 5.1.1
Uninstalling lxml-5.1.1:
Would remove:
\lib\site-packages\lxml-5.1.1.dist-info\*
\lib\site-packages\lxml\*
Proceed (Y/n)? Y
Successfully uninstalled lxml-5.1.1
It doesn't help
python -m pip install lxml==3.1.2
Collecting lxml==3.1.2
Downloading lxml-3.1.2.tar.gz (3.3 MB)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.3/3.3 MB 7.8 MB/s eta 0:00:00
Preparing metadata (setup.py) ... done
Building wheels for collected packages: lxml
Building wheel for lxml (setup.py) ... error
error: subprocess-exited-with-error
× python setup.py bdist_wheel did not run successfully.
│ exit code: 1
╰─> [83 lines of output]
Building lxml version 3.1.2.
Building without Cython.
ERROR: b"'xslt-config' is not recognized as an internal or external command,\r\noperable program or batch file.\r\n"
** make sure the development packages of libxml2 and libxslt are installed **
(some more useless output and...)
...and finally installing older version of lxml stucks with error
error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\VC\\Tools\\MSVC\\14.39.33519\\bin\\HostX86\\x64\\cl.exe' failed with exit code 2
[end of output]
note: This error originates from a subprocess, and is likely not a problem with pip.
ERROR: Failed building wheel for lxml
Running setup.py clean for lxml
Failed to build lxml
ERROR: Could not build wheels for lxml, which is required to install pyproject.toml-based projects
Tested on python --version Python 3.11.6
Does anyone worked on windows with this library? What lxml version should I try?
Hi,
Thanks for creating this awesome project.
It would be more awesome if you added that this project supports python 3.11
Thanks :D
odfdo uses F strings, which was introduced in Python 3.6
(( Unfortunately Ubuntu 16.04 is at Python 3.5, so odfdo cannot be used out-of-the-box. ))
Hello,
following setting: I'm loading an existing odt (that already has a TOC) and add extra text and also headers using odfdo.
Then I like to update the TOC also with odfdo, but do not manage to do that.
I try to get the element with something like:
doc.body.get_toc(0)
and then call
.fill()
I also tried to look up and down, but couldn't make it work. Also going through the doc and the examples. I just started to work with odfdo and odt in this way, so there is some understanding missing.
How can I updated for example the existing TOC?
I've tried the suppress_numbering parameter to Header() but it does not seem to have any impact when I load the document up in LibreOffice. Trying to prevent numbering for depth 2 and lower and for depth 2 and lower to be excluded from TOC.
Suggestions?
The script odfdo-styles.py
has a few problems. The -o
is not working, there is a typo in a variable name, and with Python3 opening a file with wb
requires bytes not str
.
Anyway, here is a git-diff of the proposed changes (too lazy for a PullRequest right now):
diff --git a/scripts/odfdo-styles.py b/scripts/odfdo-styles.py
index 17db262..155895d 100755
--- a/scripts/odfdo-styles.py
+++ b/scripts/odfdo-styles.py
@@ -38,15 +38,16 @@ def show_styles(document,
properties=False):
"""Show the different styles of a document and their properties.
"""
- output = document.show_styles(
+ output = document.show_styles(
automatic=automatic, common=common, properties=properties)
# Print the output
if target is None:
- print(output)
+ print(output, end='')
return
target.write(output)
target.flush()
- tatget.close()
+ target.close()
+
def delete_styles(document, target, pretty=True):
n = document.delete_styles()
@@ -182,9 +183,8 @@ if __name__ == '__main__':
if not automatic ^ common:
automatic, common = True, True
target = options.output
- target = None
if target is not None:
- target = open(target, 'wb')
+ target = open(target, 'w')
show_styles(
document,
target,
I just had a look at https://github.com/jdum/odfdo/blob/master/test/test_scripts.sh, which references some scripts which are missing in the repository, like lpod-convert.py
: https://github.com/jdum/odfdo/tree/master/scripts They apparently only exist on the "original" repository: https://github.com/lpod/lpod-python/tree/master/scripts
Due to not using any CI (like GitHub Actions), it seems like this has not been obvious yet.
The border
and padding
attributes are ignored when the style is used for a text_frame (Frame.text_frame
).
I seems that these attributes can only be used for table-cells, see https://github.com/jdum/odfdo/blob/master/odfdo/style.py#L461
Workaround: Define fo attributes directly using **{"fo:border": "none", "fo:padding": "0cm"}
Is there any feature that would avoid the use of doc.save(target=PATH, pretty=True)
in order to write the produced Document() in a response object?
Since the name in the copyright contains non-ASCII characters it is better to be explicit about the encoding. See PEP 263.
For example
# -*- coding: utf-8 -*-
# Copyright 2018 Jérôme Dumonteil
Dear @jdum,
thank God someone pointed me to your project. It seems quite active compared to other projects.
Before your project I only know odfpy
and ezodf
which are booth (nearly) dead.
Could you please update the README with a section describing your project organisation and the current status. It will help new contributors to decide about to which project to contribute or what the future plans are.
I assume this is a one-person-freetime-project. But people need to know that, too. It will always help to know the humans behind a project. Are there others involved in that project? How many maintainers are there with admin rights to the repo?
It also would be great if you could write about your project relation to odfpy
and ezodf
if there is one.
Do you have any plans for the future?
While I was trying to create a new document and fill it with a table from a template document I noticed that that styles are not inserted properly in the new document. Every time .insert_style
is called it will delete the previously inserted style.
Document.insert_style() should accept str argument, and convert the str with Element.from_tag().
The str argument beeing usually a valid XML description of an automatic style.
Sounds ridiculous if I want to open the resulted file in Microsoft Word, but as I'm working in a project which requires any kind of user, I was testing the ODT to open in the respective, but it does not succeed.
So... I have created an ODT template, which is used to open, edit, and wrapped in a response object. The problem is that it can not be open Microsoft after the user save it. Still, the ODT template can be open. The message is something like:
"Error trying to open file in Word!
Is there any trick to avoid this? Should I specify a metadata or something?
Thank you so much!
I can't quite figure out how to delete a paragraph with this.
I have empty lines that need removing. With odfpy, I could use "element.parentNode.removeChild(element" but with this I'm not so sure.
Hey jdum,
I'm trying to copy multiple tables from multiple documents to one final single document. The problem is the tables have styles and sub-elements (such as images / tables) which are not being copied as they should to the new document.
I have tried merging all styles into the final document and then copying over the tables but this seems to cause some conflict. I have also just tried cloning the tables and appending them to the new document but this doesn't work either.
Could you suggest the best way of attempting to do this ?
Thanks in advance,
s3nn
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.