How to change LibreOffice Writer Templates

A “template changer” existed for OpenOffice and LibreOffice. This was incompatible for some time and therefore did not work. In fact, each document is a zip file containing numerous xml files, which contain the location of the template used.

The template contains the house style and if you change the template, all the documents change with it. The fact that a document is linked to a template is a hugely powerful feature of LibreOffice. Templates have the extension .ott.

Using master documents (.odm) in the process creates an enormously beautiful environment for building large documents.

This places LibreOffice above LaTeX in terms of usability and above MS Word in terms of stability of large documents.

For business use in maintaining technical documentation, large manuals, I got stuck and had to find a solution to be able to link templates to .odm and .odt files.

Meanwhile, there is another TemplateChanger available that is a bit friendlier for most users than the shell script below. However, the script has proven itself for many years.

Without tools, it is not possible to attach templates to documents from the user interface. This sounds a bit crazy and yes, it could be considered a bug.

It has been tested on Linux but should also work with Cygwin on Windows. OS-X should work with minor changes, such as that the date function in Unix does not need an @ sign.

The underlying idea is that you have documentation projects where both the documents and the templates are in the same directory. If that is the case with you, then this script can help you.

You can paste the following to a text file called “cht.sh”, give it executable rights, put it in your documentation directory,  and start attaching templates to your documents.

Hope you like it!

Update 2018-11-19: Now both ODT and ODM files are supported.
Update 2023: Repaginating bug is solved and information is removed from this page.
Update 2023: Apparently a working extension is back.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
#!/bin/bash
 
# Template CHanger alternative
# This script uses xmlstarlet, zip and unzip.
echo
echo ./cht.sh, CHange Template...
echo This script inserts or replaces, a template XML node in a 
echo LibreOffice Writer file, by modifying meta.xml and adding an
echo absolute url for template location. It accepts both
echo document and master document files and template files.
echo xmlstarlet is expected to be installed.
echo This is for documentation projects where Writer files and Templates
echo reside in the same directory!
echo USE AT YOUR OWN RISK, HAVE A BACK-UP READY, wiebe-nedcad-nl
echo Run script always in directory with documents, cd your_project
echo "Usage: cht <OTT-file> <ODT-or-ODM-file>"
echo Example: ./cht.sh template.ott writer.odt
echo
 
## Variables I, more below Checks
 
# General
TEMPL=$1
DOC=$2
WORKDIR="temp_extracted"
 
## Checks
 
# Do files exist with right extension?
 
if [ -f $TEMPL ] && [ "${TEMPL: -4}" == ".ott" ]; then
   echo "File $TEMPL found."
else
   echo "ERROR: Writer template $TEMPL does not exist or is not valid. Aborting."
   exit 1
fi
 
if [ -f $DOC ] && ([ "${DOC: -4}" == ".odt" ] || [ "${DOC: -4}" == ".odm" ]); then
   echo "File $DOC found."
else
   echo "ERROR: Writer document $DOC does not exist or is not valid. Aborting."
   exit 1
fi
 
# Do we have xmlstarlet?
 
hash xmlstarlet 2>/dev/null || { echo >&2 "ERROR: xmlstarlet is required. Please install this first. Aborting."; exit 1; }
 
## Variables II
 
# XML node "meta:template" values
echo Node meta:template will contain the following bare attributes:
# xlink:type xlink:actuate xlink:title xlink:href meta:date
 
# Static
N_XLINK_TYPE="xlink:type" && V_XLINK_TYPE="simple"
echo $N_XLINK_TYPE -- $V_XLINK_TYPE
 
# Static
N_XLINK_ACTUATE="xlink:actuate" && V_XLINK_ACTUATE="onRequest"
echo $N_XLINK_ACTUATE -- $V_XLINK_ACTUATE
 
# Template name
N_XLINK_TITLE="xlink:title"
NO_EXT="${TEMPL%.*}"
V_XLINK_TITLE=${NO_EXT##*/}
echo $N_XLINK_TITLE -- $V_XLINK_TITLE
 
# Absolute template location
N_XLINK_HREF="xlink:href"
V_XLINK_HREF="$PWD/$TEMPL"
echo $N_XLINK_HREF -- $V_XLINK_HREF
 
# Template time
N_META_DATE="meta:date"
# Lower epoch time sec to force updating document styles
BELLE_EPOCH_COR=-1
BELLE_EPOCH_X=$(stat -c %Y $TEMPL)
BELLE_EPOCH=$((BELLE_EPOCH_X+BELLE_EPOCH_COR))
V_META_DATE=$(date -d @$BELLE_EPOCH +%Y-%m-%dT%T.%9N)
echo $N_META_DATE -- $V_META_DATE
echo
 
## The proces
 
# Unzip the document file
 
mkdir -p $WORKDIR
if [ -z "$(ls -A ./$WORKDIR)" ]; then
   echo "Ready for processing meta.xml"
else
   echo "ERROR: ./$WORKDIR is not empty and may contain an unzipped document file. Aborting."
   exit 1
fi
unzip -q $DOC -d $WORKDIR
cd $WORKDIR
 
# If exists, delete node meta:template, add node and subnodes via pipes
xmlstarlet ed -d "/office:document-meta/office:meta/meta:template" meta.xml | \
xmlstarlet ed -s  "/office:document-meta/office:meta" -t elem -n meta:template | \
xmlstarlet ed -i  "/office:document-meta/office:meta/meta:template" -t attr -n $N_XLINK_TYPE -v $V_XLINK_TYPE | \
xmlstarlet ed -i  "/office:document-meta/office:meta/meta:template" -t attr -n $N_XLINK_ACTUATE -v $V_XLINK_ACTUATE | \
xmlstarlet ed -i  "/office:document-meta/office:meta/meta:template" -t attr -n $N_XLINK_TITLE -v $V_XLINK_TITLE | \
xmlstarlet ed -i  "/office:document-meta/office:meta/meta:template" -t attr -n $N_XLINK_HREF -v $V_XLINK_HREF | \
xmlstarlet ed -i  "/office:document-meta/office:meta/meta:template" -t attr -n $N_META_DATE -v $V_META_DATE \
> temp.xml && mv temp.xml meta.xml
 
# What is the result?
echo meta.xml is now: && echo
cat meta.xml && echo
 
# Back-up original file
mv ../$DOC "../${DOC%.*}.bak"
echo A .bak file is created && echo
 
# Create modified Writer file, mimetype first
zip -rq ../$DOC mimetype .
 
# Cleaning up
cd ..
rm -rf $WORKDIR
echo Finished && echo

Leave a comment