aboutsummaryrefslogtreecommitdiff
path: root/pip-bins/xml2odf
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukasz.kasprzak@pm.me>2026-03-19 15:05:32 +0100
committerLukasz Kasprzak <lukasz.kasprzak@pm.me>2026-03-19 15:05:32 +0100
commitb1844d805a8f190af00faf3f6e5bed7d997ecaae (patch)
treed6296ba5e85034836e203a542d2ad34a9e5c5b32 /pip-bins/xml2odf
parentc74163f1ecbd809c83bb465ee89fa04369a89972 (diff)
downloadbin-b1844d805a8f190af00faf3f6e5bed7d997ecaae.tar.gz
bin-b1844d805a8f190af00faf3f6e5bed7d997ecaae.zip
created sorter for sorting downloads with custom rules; created straper for recreation of server
Diffstat (limited to 'pip-bins/xml2odf')
-rwxr-xr-xpip-bins/xml2odf241
1 files changed, 241 insertions, 0 deletions
diff --git a/pip-bins/xml2odf b/pip-bins/xml2odf
new file mode 100755
index 0000000..e7114a8
--- /dev/null
+++ b/pip-bins/xml2odf
@@ -0,0 +1,241 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+# Copyright (C) 2006 Søren Roug, European Environment Agency
+#
+# This is free software. You may redistribute it under the terms
+# of the Apache license and the GNU General Public License Version
+# 2 or at your option any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#
+# Contributor(s):
+#
+#
+
+# OpenDocument can be a complete office document in a single
+# XML document. This script will take such a document and create
+# a package
+import io
+import zipfile,time, sys, getopt
+import xml.sax, xml.sax.saxutils
+from odf import manifest
+
+class SplitWriter:
+ def __init__(self):
+ self.activefiles = []
+ self._content = []
+ self._meta = []
+ self._styles = []
+ self._settings = []
+
+ self.files = {'content': self._content, 'meta': self._meta,
+ 'styles':self._styles, 'settings': self._settings }
+
+ def write(self, str):
+ for f in self.activefiles:
+ f.append(str)
+
+ def activate(self, filename):
+ file = self.files[filename]
+ if file not in self.activefiles:
+ self.activefiles.append(file)
+
+ def deactivate(self, filename):
+ file = self.files[filename]
+ if file in self.activefiles:
+ self.activefiles.remove(file)
+
+odmimetypes = {
+ 'application/vnd.oasis.opendocument.text': '.odt',
+ 'application/vnd.oasis.opendocument.text-template': '.ott',
+ 'application/vnd.oasis.opendocument.graphics': '.odg',
+ 'application/vnd.oasis.opendocument.graphics-template': '.otg',
+ 'application/vnd.oasis.opendocument.presentation': '.odp',
+ 'application/vnd.oasis.opendocument.presentation-template': '.otp',
+ 'application/vnd.oasis.opendocument.spreadsheet': '.ods',
+ 'application/vnd.oasis.opendocument.spreadsheet-template': '.ots',
+ 'application/vnd.oasis.opendocument.chart': '.odc',
+ 'application/vnd.oasis.opendocument.chart-template': '.otc',
+ 'application/vnd.oasis.opendocument.image': '.odi',
+ 'application/vnd.oasis.opendocument.image-template': '.oti',
+ 'application/vnd.oasis.opendocument.formula': '.odf',
+ 'application/vnd.oasis.opendocument.formula-template': '.otf',
+ 'application/vnd.oasis.opendocument.text-master': '.odm',
+ 'application/vnd.oasis.opendocument.text-web': '.oth',
+}
+
+OFFICENS = u"urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+base = xml.sax.saxutils.XMLGenerator
+
+class odfsplitter(base):
+
+ def __init__(self):
+ self._mimetype = ''
+ self.output = SplitWriter()
+ self._prefixes = []
+ base.__init__(self, self.output, 'utf-8')
+
+ def startPrefixMapping(self, prefix, uri):
+ base.startPrefixMapping(self, prefix, uri)
+ self._prefixes.append('xmlns:%s="%s"' % (prefix, uri))
+
+ def startElementNS(self, name, qname, attrs):
+ if name == (OFFICENS, u"document"):
+ self._mimetype = attrs.get((OFFICENS, "mimetype"))
+ elif name == (OFFICENS, u"meta"):
+ self.output.activate('meta')
+
+ elif name == (OFFICENS, u"settings"):
+ self.output.activate('settings')
+ elif name == (OFFICENS, u"scripts"):
+ self.output.activate('content')
+ elif name == (OFFICENS, u"font-face-decls"):
+ self.output.activate('content')
+ self.output.activate('styles')
+ elif name == (OFFICENS, u"styles"):
+ self.output.activate('styles')
+ elif name == (OFFICENS, u"automatic-styles"):
+ self.output.activate('content')
+ self.output.activate('styles')
+ elif name == (OFFICENS, u"master-styles"):
+ self.output.activate('styles')
+ elif name == (OFFICENS, u"body"):
+ self.output.activate('content')
+ base.startElementNS(self, name, qname, attrs)
+
+ def endElementNS(self, name, qname):
+ base.endElementNS(self, name, qname)
+ if name == (OFFICENS, u"meta"):
+ self.output.deactivate('meta')
+ elif name == (OFFICENS, u"settings"):
+ self.output.deactivate('settings')
+ elif name == (OFFICENS, u"scripts"):
+ self.output.deactivate('content')
+ elif name == (OFFICENS, u"font-face-decls"):
+ self.output.deactivate('content')
+ self.output.deactivate('styles')
+ elif name == (OFFICENS, u"styles"):
+ self.output.deactivate('styles')
+ elif name == (OFFICENS, u"automatic-styles"):
+ self.output.deactivate('content')
+ self.output.deactivate('styles')
+ elif name == (OFFICENS, u"master-styles"):
+ self.output.deactivate('styles')
+ elif name == (OFFICENS, u"body"):
+ self.output.deactivate('content')
+
+
+ def content(self):
+ """ Return the content inside a wrapper called <office:document-content>
+ """
+ prefixes = ' '.join(self._prefixes)
+ return ''.join(['<?xml version="1.0" encoding="UTF-8"?>\n<office:document-content %s office:version="1.0">' % prefixes] + list(map(lambda x: x.decode("utf-8"), self.output._content)) + ['</office:document-content>'])
+
+ def settings(self):
+ prefixes = ' '.join(self._prefixes).encode('utf-8')
+ return ''.join( ['<?xml version="1.0" encoding="UTF-8"?>\n<office:document-settings %s office:version="1.0">' % prefixes] + self.output._settings + ['''</office:document-settings>'''])
+
+ def styles(self):
+ prefixes = ' '.join(self._prefixes)
+ return ''.join( ['<?xml version="1.0" encoding="UTF-8"?>\n<office:document-styles %s office:version="1.0">' % prefixes] + list(map(lambda x: x.decode("utf-8"), self.output._styles)) + ['''</office:document-styles>'''])
+
+ def meta(self):
+ prefixes = ' '.join(self._prefixes)
+ return ''.join( ['<?xml version="1.0" encoding="UTF-8"?>\n<office:document-meta %s office:version="1.0">' % prefixes] + list(map(lambda x: x.decode("utf-8"), self.output._meta)) + ['''</office:document-meta>'''])
+
+def usage():
+ sys.stderr.write("Usage: %s [-o outputfile] [-s] inputfile\n" % sys.argv[0])
+
+def manifestxml(m):
+ """ Generates the content of the manifest.xml file """
+ xml=io.StringIO()
+ xml.write(u"<?xml version='1.0' encoding='UTF-8'?>\n")
+ m.toXml(0,xml)
+ return xml.getvalue()
+
+try:
+ opts, args = getopt.getopt(sys.argv[1:], "o:s", ["output=","suffix"])
+except getopt.GetoptError:
+ usage()
+ sys.exit(2)
+
+outputfile = '-'
+addsuffix = False
+
+for o, a in opts:
+ if o in ("-o", "--output"):
+ outputfile = a
+ if o in ("-s", "--suffix"):
+ addsuffix = True
+
+if len(args) > 1:
+ usage()
+ sys.exit(2)
+
+odfs = odfsplitter()
+parser = xml.sax.make_parser()
+parser.setFeature(xml.sax.handler.feature_namespaces, 1)
+parser.setContentHandler(odfs)
+if len(args) == 0:
+ parser.parse(sys.stdin)
+else:
+ parser.parse(open(args[0],"r"))
+
+mimetype = odfs._mimetype
+suffix = odmimetypes.get(mimetype,'.xxx')
+
+if outputfile == '-':
+ if sys.stdout.isatty():
+ sys.stderr.write("Won't write ODF file to terminal\n")
+ sys.exit(1)
+ z = zipfile.ZipFile(sys.stdout,"w")
+else:
+ if addsuffix:
+ outputfile = outputfile + suffix
+ z = zipfile.ZipFile(outputfile,"w")
+
+now = time.localtime()[:6]
+
+# Write mimetype
+zi = zipfile.ZipInfo('mimetype', now)
+zi.compress_type = zipfile.ZIP_STORED
+z.writestr(zi,mimetype)
+
+# Write content
+zi = zipfile.ZipInfo("content.xml", now)
+zi.compress_type = zipfile.ZIP_DEFLATED
+z.writestr(zi,odfs.content() )
+# Write styles
+zi = zipfile.ZipInfo("styles.xml", now)
+zi.compress_type = zipfile.ZIP_DEFLATED
+z.writestr(zi,odfs.styles() )
+
+# Write meta
+zi = zipfile.ZipInfo("meta.xml", now)
+zi.compress_type = zipfile.ZIP_DEFLATED
+z.writestr(zi,odfs.meta() )
+
+m = manifest.Manifest()
+m.addElement(manifest.FileEntry(fullpath="/", mediatype=mimetype))
+m.addElement(manifest.FileEntry(fullpath="content.xml",mediatype="text/xml"))
+m.addElement(manifest.FileEntry(fullpath="styles.xml", mediatype="text/xml"))
+m.addElement(manifest.FileEntry(fullpath="meta.xml", mediatype="text/xml"))
+
+# Write manifest
+zi = zipfile.ZipInfo("META-INF/manifest.xml", now)
+zi.compress_type = zipfile.ZIP_DEFLATED
+z.writestr(zi, manifestxml(m).encode("utf-8") )
+z.close()
+
+
+
+# Local Variables: ***
+# mode: python ***
+# End: ***