mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add support for the Open Document Format (ODT) as an input format. Can now be converted to both LRF and EPUB. Fixes #233 (ODT2LRF request)
This commit is contained in:
parent
c1995474be
commit
323dfce595
@ -28,3 +28,4 @@ src/cssutils/_todo/
|
||||
src/cssutils/scripts/
|
||||
src/cssutils/css/.svn/
|
||||
src/cssutils/stylesheets/.svn/
|
||||
src/odf/.svn
|
||||
|
@ -21,4 +21,4 @@ class DRMError(ValueError):
|
||||
BOOK_EXTENSIONS = ['lrf', 'rar', 'zip', 'rtf', 'lit', 'txt', 'htm', 'xhtm',
|
||||
'html', 'xhtml', 'epub', 'pdf', 'prc', 'mobi', 'azw',
|
||||
'epub', 'fb2', 'djvu', 'lrx', 'cbr', 'cbz', 'oebzip',
|
||||
'rb', 'imp']
|
||||
'rb', 'imp', 'odt']
|
||||
|
@ -72,7 +72,6 @@ def pdf2opf(path, tdir, opts):
|
||||
def epub2opf(path, tdir, opts):
|
||||
zf = ZipFile(path)
|
||||
zf.extractall(tdir)
|
||||
print os.listdir(os.path.join(tdir, 'META-INF'))
|
||||
if os.path.exists(os.path.join(tdir, 'META-INF', 'encryption.xml')):
|
||||
raise DRMError(os.path.basename(path))
|
||||
for f in walk(tdir):
|
||||
@ -80,6 +79,10 @@ def epub2opf(path, tdir, opts):
|
||||
return f
|
||||
raise ValueError('%s is not a valid EPUB file'%path)
|
||||
|
||||
def odt2epub(path, tdir, opts):
|
||||
from calibre.ebooks.odt.to_oeb import Extract
|
||||
opts.encoding = 'utf-8'
|
||||
return Extract()(path, tdir)
|
||||
|
||||
MAP = {
|
||||
'lit' : lit2opf,
|
||||
@ -90,8 +93,9 @@ MAP = {
|
||||
'txt' : txt2opf,
|
||||
'pdf' : pdf2opf,
|
||||
'epub' : epub2opf,
|
||||
'odt' : odt2epub,
|
||||
}
|
||||
SOURCE_FORMATS = ['lit', 'mobi', 'prc', 'fb2', 'rtf', 'txt', 'pdf', 'rar', 'zip', 'oebzip', 'htm', 'html', 'epub']
|
||||
SOURCE_FORMATS = ['lit', 'mobi', 'prc', 'fb2', 'odt', 'rtf', 'txt', 'pdf', 'rar', 'zip', 'oebzip', 'htm', 'html', 'epub']
|
||||
|
||||
def unarchive(path, tdir):
|
||||
extract(path, tdir)
|
||||
|
@ -23,6 +23,7 @@ preferred_source_formats = [
|
||||
'LIT',
|
||||
'MOBI',
|
||||
'EPUB',
|
||||
'ODT',
|
||||
'HTML',
|
||||
'HTM',
|
||||
'XHTM',
|
||||
|
@ -1,3 +1,4 @@
|
||||
from __future__ import with_statement
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
'''Convert any ebook file into a LRF file.'''
|
||||
@ -7,6 +8,7 @@ import sys, os, logging, shutil, tempfile, re
|
||||
from calibre.ebooks import UnknownFormatError
|
||||
from calibre.ebooks.lrf import option_parser as _option_parser
|
||||
from calibre import __appname__, setup_cli_handlers, extract
|
||||
from calibre.ptempfile import TemporaryDirectory
|
||||
from calibre.ebooks.lrf.lit.convert_from import process_file as lit2lrf
|
||||
from calibre.ebooks.lrf.pdf.convert_from import process_file as pdf2lrf
|
||||
from calibre.ebooks.lrf.rtf.convert_from import process_file as rtf2lrf
|
||||
@ -89,6 +91,21 @@ def handle_archive(path):
|
||||
file = file.decode(sys.getfilesystemencoding())
|
||||
return tdir, file
|
||||
|
||||
def odt2lrf(path, options, logger):
|
||||
from calibre.ebooks.odt.to_oeb import Extract
|
||||
from calibre.ebooks.lrf.html.convert_from import process_file as html_process_file
|
||||
|
||||
if logger is None:
|
||||
level = logging.DEBUG if options.verbose else logging.INFO
|
||||
logger = logging.getLogger('odt2lrf')
|
||||
setup_cli_handlers(logger, level)
|
||||
|
||||
with TemporaryDirectory('_odt2lrf') as tdir:
|
||||
opf = Extract()(path, tdir)
|
||||
options.use_spine = True
|
||||
options.encoding = 'utf-8'
|
||||
html_process_file(opf.replace('metadata.opf', 'index.html'), options, logger)
|
||||
|
||||
def process_file(path, options, logger=None):
|
||||
path = os.path.abspath(os.path.expanduser(path))
|
||||
tdir = None
|
||||
@ -138,8 +155,10 @@ def process_file(path, options, logger=None):
|
||||
convertor = mobi2lrf
|
||||
elif ext == 'fb2':
|
||||
convertor = fb22lrf
|
||||
elif ext == 'odt':
|
||||
convertor = odt2lrf
|
||||
if not convertor:
|
||||
raise UnknownFormatError('Coverting from %s to LRF is not supported.'%ext)
|
||||
raise UnknownFormatError(_('Converting from %s to LRF is not supported.')%ext)
|
||||
convertor(path, options, logger)
|
||||
finally:
|
||||
os.chdir(cwd)
|
||||
|
@ -14,17 +14,17 @@ from calibre.ebooks.metadata.rb import get_metadata as rb_metadata
|
||||
from calibre.ebooks.metadata.epub import get_metadata as epub_metadata
|
||||
from calibre.ebooks.metadata.html import get_metadata as html_metadata
|
||||
from calibre.ebooks.mobi.reader import get_metadata as mobi_metadata
|
||||
from calibre.ebooks.metadata.odt import get_metadata as odt_metadata
|
||||
from calibre.ebooks.metadata.opf import OPFReader
|
||||
from calibre.ebooks.metadata.rtf import set_metadata as set_rtf_metadata
|
||||
from calibre.ebooks.lrf.meta import set_metadata as set_lrf_metadata
|
||||
from calibre.ebooks.metadata.epub import set_metadata as set_epub_metadata
|
||||
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.utils.config import prefs
|
||||
|
||||
_METADATA_PRIORITIES = [
|
||||
'html', 'htm', 'xhtml', 'xhtm',
|
||||
'rtf', 'fb2', 'pdf', 'prc',
|
||||
'rtf', 'fb2', 'pdf', 'prc', 'odt',
|
||||
'epub', 'lit', 'lrf', 'mobi', 'rb', 'imp'
|
||||
]
|
||||
|
||||
@ -64,6 +64,8 @@ def get_metadata(stream, stream_type='lrf', use_libprs_metadata=False):
|
||||
stream_type = 'html'
|
||||
if stream_type in ('mobi', 'prc'):
|
||||
stream_type = 'mobi'
|
||||
if stream_type in ('odt', 'ods', 'odp', 'odg', 'odf'):
|
||||
stream_type = 'odt'
|
||||
|
||||
opf = None
|
||||
if hasattr(stream, 'name'):
|
||||
|
266
src/calibre/ebooks/metadata/odt.py
Executable file
266
src/calibre/ebooks/metadata/odt.py
Executable file
@ -0,0 +1,266 @@
|
||||
#!/usr/bin/python
|
||||
# -*- 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):
|
||||
#
|
||||
import zipfile, sys, re
|
||||
import xml.sax.saxutils
|
||||
from cStringIO import StringIO
|
||||
|
||||
from odf.namespaces import OFFICENS, DCNS, METANS
|
||||
from calibre.ebooks.metadata import MetaInformation, string_to_authors
|
||||
|
||||
whitespace = re.compile(r'\s+')
|
||||
|
||||
fields = {
|
||||
'title': (DCNS,u'title'),
|
||||
'description': (DCNS,u'description'),
|
||||
'subject': (DCNS,u'subject'),
|
||||
'creator': (DCNS,u'creator'),
|
||||
'date': (DCNS,u'date'),
|
||||
'language': (DCNS,u'language'),
|
||||
'generator': (METANS,u'generator'),
|
||||
'initial-creator': (METANS,u'initial-creator'),
|
||||
'keyword': (METANS,u'keyword'),
|
||||
'editing-duration': (METANS,u'editing-duration'),
|
||||
'editing-cycles': (METANS,u'editing-cycles'),
|
||||
'printed-by': (METANS,u'printed-by'),
|
||||
'print-date': (METANS,u'print-date'),
|
||||
'creation-date': (METANS,u'creation-date'),
|
||||
'user-defined': (METANS,u'user-defined'),
|
||||
#'template': (METANS,u'template'),
|
||||
}
|
||||
|
||||
def normalize(str):
|
||||
"""
|
||||
The normalize-space function returns the argument string with whitespace
|
||||
normalized by stripping leading and trailing whitespace and replacing
|
||||
sequences of whitespace characters by a single space.
|
||||
"""
|
||||
return whitespace.sub(' ', str).strip()
|
||||
|
||||
class MetaCollector:
|
||||
"""
|
||||
The MetaCollector is a pseudo file object, that can temporarily ignore write-calls
|
||||
It could probably be replaced with a StringIO object.
|
||||
"""
|
||||
def __init__(self):
|
||||
self._content = []
|
||||
self.dowrite = True
|
||||
|
||||
def write(self, str):
|
||||
if self.dowrite:
|
||||
self._content.append(str)
|
||||
|
||||
def content(self):
|
||||
return ''.join(self._content)
|
||||
|
||||
|
||||
class odfmetaparser(xml.sax.saxutils.XMLGenerator):
|
||||
""" Parse a meta.xml file with an event-driven parser and replace elements.
|
||||
It would probably be a cleaner approach to use a DOM based parser and
|
||||
then manipulate in memory.
|
||||
Small issue: Reorders elements
|
||||
"""
|
||||
|
||||
def __init__(self, deletefields={}, yieldfields={}, addfields={}):
|
||||
self.deletefields = deletefields
|
||||
self.yieldfields = yieldfields
|
||||
self.addfields = addfields
|
||||
self._mimetype = ''
|
||||
self.output = MetaCollector()
|
||||
self._data = []
|
||||
self.seenfields = {}
|
||||
xml.sax.saxutils.XMLGenerator.__init__(self, self.output, 'utf-8')
|
||||
|
||||
def startElementNS(self, name, qname, attrs):
|
||||
self._data = []
|
||||
field = name
|
||||
# I can't modify the template until the tool replaces elements at the same
|
||||
# location and not at the end
|
||||
# if name == (METANS,u'template'):
|
||||
# self._data = [attrs.get((XLINKNS,u'title'),'')]
|
||||
if name == (METANS,u'user-defined'):
|
||||
field = attrs.get((METANS,u'name'))
|
||||
if field in self.deletefields:
|
||||
self.output.dowrite = False
|
||||
elif field in self.yieldfields:
|
||||
del self.addfields[field]
|
||||
xml.sax.saxutils.XMLGenerator.startElementNS(self, name, qname, attrs)
|
||||
else:
|
||||
xml.sax.saxutils.XMLGenerator.startElementNS(self, name, qname, attrs)
|
||||
self._tag = field
|
||||
|
||||
def endElementNS(self, name, qname):
|
||||
field = name
|
||||
if name == (METANS,u'user-defined'):
|
||||
field = self._tag
|
||||
if name == (OFFICENS,u'meta'):
|
||||
for k,v in self.addfields.items():
|
||||
if len(v) > 0:
|
||||
if type(k) == type(''):
|
||||
xml.sax.saxutils.XMLGenerator.startElementNS(self,(METANS,u'user-defined'),None,{(METANS,u'name'):k})
|
||||
xml.sax.saxutils.XMLGenerator.characters(self, v)
|
||||
xml.sax.saxutils.XMLGenerator.endElementNS(self, (METANS,u'user-defined'),None)
|
||||
else:
|
||||
xml.sax.saxutils.XMLGenerator.startElementNS(self, k, None, {})
|
||||
xml.sax.saxutils.XMLGenerator.characters(self, v)
|
||||
xml.sax.saxutils.XMLGenerator.endElementNS(self, k, None)
|
||||
if isinstance(self._tag, tuple):
|
||||
texttag = self._tag[1]
|
||||
else:
|
||||
texttag = self._tag
|
||||
self.seenfields[texttag] = self.data()
|
||||
|
||||
if field in self.deletefields:
|
||||
self.output.dowrite = True
|
||||
else:
|
||||
xml.sax.saxutils.XMLGenerator.endElementNS(self, name, qname)
|
||||
|
||||
def characters(self, content):
|
||||
xml.sax.saxutils.XMLGenerator.characters(self, content)
|
||||
self._data.append(content)
|
||||
|
||||
def meta(self):
|
||||
return self.output.content()
|
||||
|
||||
def data(self):
|
||||
return normalize(''.join(self._data))
|
||||
|
||||
def get_metadata(stream):
|
||||
zin = zipfile.ZipFile(stream, 'r')
|
||||
odfs = odfmetaparser()
|
||||
parser = xml.sax.make_parser()
|
||||
parser.setFeature(xml.sax.handler.feature_namespaces, 1)
|
||||
parser.setContentHandler(odfs)
|
||||
content = zin.read('meta.xml')
|
||||
parser.parse(StringIO(content))
|
||||
data = odfs.seenfields
|
||||
mi = MetaInformation(None, [])
|
||||
if data.has_key('title'):
|
||||
mi.title = data['title']
|
||||
if data.has_key('creator'):
|
||||
mi.authors = string_to_authors(data['creator'])
|
||||
if data.has_key('description'):
|
||||
mi.comments = data['description']
|
||||
if data.has_key('language'):
|
||||
mi.language = data['language']
|
||||
if data.get('keywords', ''):
|
||||
mi.tags = data['keywords'].split(',')
|
||||
|
||||
return mi
|
||||
|
||||
def main(args=sys.argv):
|
||||
if len(args) != 2:
|
||||
print 'Usage: %s file.odt'%args[0]
|
||||
return 1
|
||||
mi = get_metadata(open(args[1], 'rb'))
|
||||
print mi
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
|
||||
#now = time.localtime()[:6]
|
||||
#outputfile = "-"
|
||||
#writemeta = False # Do we change any meta data?
|
||||
#usenormalize = False
|
||||
#
|
||||
#try:
|
||||
# opts, args = getopt.getopt(sys.argv[1:], "cdlI:A:a:o:x:X:")
|
||||
#except getopt.GetoptError:
|
||||
# exitwithusage()
|
||||
#
|
||||
#if len(opts) == 0:
|
||||
# opts = [ ('-l','') ]
|
||||
#
|
||||
#for o, a in opts:
|
||||
# if o in ('-a','-A','-I'):
|
||||
# writemeta = True
|
||||
# if a.find(":") >= 0:
|
||||
# k,v = a.split(":",1)
|
||||
# else:
|
||||
# k,v = (a, "")
|
||||
# if len(k) == 0:
|
||||
# exitwithusage()
|
||||
# k = fields.get(k,k)
|
||||
# addfields[k] = unicode(v,'utf-8')
|
||||
# if o == '-a':
|
||||
# yieldfields[k] = True
|
||||
# if o == '-I':
|
||||
# deletefields[k] = True
|
||||
# if o == '-d':
|
||||
# writemeta = True
|
||||
# addfields[(DCNS,u'date')] = "%04d-%02d-%02dT%02d:%02d:%02d" % now
|
||||
# deletefields[(DCNS,u'date')] = True
|
||||
# if o == '-c':
|
||||
# usenormalize = True
|
||||
# if o == '-l':
|
||||
# Xfields = fields.values()
|
||||
# if o == "-x":
|
||||
# xfields.append(fields.get(a,a))
|
||||
# if o == "-X":
|
||||
# Xfields.append(fields.get(a,a))
|
||||
# if o == "-o":
|
||||
# outputfile = a
|
||||
#
|
||||
## The specification says we should change the element to our own,
|
||||
## and must not export the original identifier.
|
||||
#if writemeta:
|
||||
# addfields[(METANS,u'generator')] = TOOLSVERSION
|
||||
# deletefields[(METANS,u'generator')] = True
|
||||
#
|
||||
#odfs = odfmetaparser()
|
||||
#parser = xml.sax.make_parser()
|
||||
#parser.setFeature(xml.sax.handler.feature_namespaces, 1)
|
||||
#parser.setContentHandler(odfs)
|
||||
#
|
||||
#if len(args) == 0:
|
||||
# zin = zipfile.ZipFile(sys.stdin,'r')
|
||||
#else:
|
||||
# if not zipfile.is_zipfile(args[0]):
|
||||
# exitwithusage()
|
||||
# zin = zipfile.ZipFile(args[0], 'r')
|
||||
#
|
||||
#content = zin.read('meta.xml')
|
||||
#parser.parse(StringIO(content))
|
||||
#
|
||||
#if writemeta:
|
||||
# if outputfile == '-':
|
||||
# if sys.stdout.isatty():
|
||||
# sys.stderr.write("Won't write ODF file to terminal\n")
|
||||
# sys.exit(1)
|
||||
# zout = zipfile.ZipFile(sys.stdout,"w")
|
||||
# else:
|
||||
# zout = zipfile.ZipFile(outputfile,"w")
|
||||
#
|
||||
#
|
||||
#
|
||||
# # Loop through the input zipfile and copy the content to the output until we
|
||||
# # get to the meta.xml. Then substitute.
|
||||
# for zinfo in zin.infolist():
|
||||
# if zinfo.filename == "meta.xml":
|
||||
# # Write meta
|
||||
# zi = zipfile.ZipInfo("meta.xml", now)
|
||||
# zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
# zout.writestr(zi,odfs.meta() )
|
||||
# else:
|
||||
# payload = zin.read(zinfo.filename)
|
||||
# zout.writestr(zinfo, payload)
|
||||
#
|
||||
# zout.close()
|
||||
#zin.close()
|
9
src/calibre/ebooks/odt/__init__.py
Normal file
9
src/calibre/ebooks/odt/__init__.py
Normal file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
'''
|
||||
Handle the Open Document Format
|
||||
'''
|
||||
|
72
src/calibre/ebooks/odt/to_oeb.py
Normal file
72
src/calibre/ebooks/odt/to_oeb.py
Normal file
@ -0,0 +1,72 @@
|
||||
from __future__ import with_statement
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
'''
|
||||
Convert an ODT file into a Open Ebook
|
||||
'''
|
||||
import os, sys
|
||||
from odf.odf2xhtml import ODF2XHTML
|
||||
|
||||
from calibre import CurrentDir, walk
|
||||
from calibre.utils.zipfile import ZipFile
|
||||
from calibre.utils.config import OptionParser
|
||||
from calibre.ebooks.metadata.odt import get_metadata
|
||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||
|
||||
class Extract(ODF2XHTML):
|
||||
|
||||
def extract_pictures(self, zf):
|
||||
if not os.path.exists('Pictures'):
|
||||
os.makedirs('Pictures')
|
||||
for name in zf.namelist():
|
||||
if name.startswith('Pictures'):
|
||||
data = zf.read(name)
|
||||
with open(name, 'wb') as f:
|
||||
f.write(data)
|
||||
|
||||
def __call__(self, path, odir):
|
||||
if not os.path.exists(odir):
|
||||
os.makedirs(odir)
|
||||
path = os.path.abspath(path)
|
||||
with CurrentDir(odir):
|
||||
print 'Extracting ODT file...'
|
||||
html = self.odf2xhtml(path)
|
||||
with open('index.html', 'wb') as f:
|
||||
f.write(html.encode('utf-8'))
|
||||
with open(path, 'rb') as f:
|
||||
zf = ZipFile(f, 'r')
|
||||
self.extract_pictures(zf)
|
||||
f.seek(0)
|
||||
mi = get_metadata(f)
|
||||
if not mi.title:
|
||||
mi.title = os.path.splitext(os.path.basename(path))
|
||||
if not mi.authors:
|
||||
mi.authors = [_('Unknown')]
|
||||
opf = OPFCreator(os.path.abspath(os.getcwdu()), mi)
|
||||
opf.create_manifest([(os.path.abspath(f), None) for f in walk(os.getcwd())])
|
||||
opf.create_spine([os.path.abspath('index.html')])
|
||||
with open('metadata.opf', 'wb') as f:
|
||||
opf.render(f)
|
||||
return os.path.abspath('metadata.opf')
|
||||
|
||||
def option_parser():
|
||||
parser = OptionParser('%prog [options] file.odt')
|
||||
parser.add_option('-o', '--output-dir', default='.',
|
||||
help=_('The output directory. Defaults to the current directory.'))
|
||||
return parser
|
||||
|
||||
def main(args=sys.argv):
|
||||
parser = option_parser()
|
||||
opts, args = parser.parse_args(args)
|
||||
if len(args) < 2:
|
||||
parser.print_help()
|
||||
print 'No ODT file specified'
|
||||
return 1
|
||||
Extract()(args[1], os.path.abspath(opts.output_dir))
|
||||
print 'Extracted to', os.path.abspath(opts.output_dir)
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
@ -24,11 +24,13 @@ entry_points = {
|
||||
'imp-meta = calibre.ebooks.metadata.imp:main',
|
||||
'rb-meta = calibre.ebooks.metadata.rb:main',
|
||||
'opf-meta = calibre.ebooks.metadata.opf:main',
|
||||
'odt-meta = calibre.ebooks.metadata.odt:main',
|
||||
'epub-meta = calibre.ebooks.metadata.epub:main',
|
||||
'txt2lrf = calibre.ebooks.lrf.txt.convert_from:main',
|
||||
'html2lrf = calibre.ebooks.lrf.html.convert_from:main',
|
||||
'html2oeb = calibre.ebooks.html:main',
|
||||
'html2epub = calibre.ebooks.epub.from_html:main',
|
||||
'odt2oeb = calibre.ebooks.odt.to_oeb:main',
|
||||
'markdown-calibre = calibre.ebooks.markdown.markdown:main',
|
||||
'lit2lrf = calibre.ebooks.lrf.lit.convert_from:main',
|
||||
'epub2lrf = calibre.ebooks.lrf.epub.convert_from:main',
|
||||
@ -176,11 +178,12 @@ def setup_completion(fatal_errors):
|
||||
from calibre.ebooks.lrf.comic.convert_from import option_parser as comicop
|
||||
from calibre.ebooks.epub.from_html import option_parser as html2epub
|
||||
from calibre.ebooks.html import option_parser as html2oeb
|
||||
from calibre.ebooks.odt.to_oeb import option_parser as odt2oeb
|
||||
from calibre.ebooks.epub.from_feeds import option_parser as feeds2epub
|
||||
from calibre.ebooks.epub.from_any import option_parser as any2epub
|
||||
from calibre.ebooks.epub.from_comic import option_parser as comic2epub
|
||||
any_formats = ['epub', 'htm', 'html', 'xhtml', 'xhtm', 'rar', 'zip',
|
||||
'txt', 'lit', 'rtf', 'pdf', 'prc', 'mobi', 'fb2']
|
||||
'txt', 'lit', 'rtf', 'pdf', 'prc', 'mobi', 'fb2', 'odt']
|
||||
f = open_file('/etc/bash_completion.d/libprs500')
|
||||
f.close()
|
||||
os.remove(f.name)
|
||||
@ -208,6 +211,7 @@ def setup_completion(fatal_errors):
|
||||
f.write(opts_and_exts('imp-meta', metaop, ['imp']))
|
||||
f.write(opts_and_exts('rb-meta', metaop, ['rb']))
|
||||
f.write(opts_and_exts('opf-meta', metaop, ['opf']))
|
||||
f.write(opts_and_exts('odt-meta', metaop, ['odt', 'ods', 'odf', 'odg', 'odp']))
|
||||
f.write(opts_and_exts('epub-meta', epub_meta, ['epub']))
|
||||
f.write(opts_and_exts('lrfviewer', lrfviewerop, ['lrf']))
|
||||
f.write(opts_and_exts('pdfrelow', pdfhtmlop, ['pdf']))
|
||||
@ -220,6 +224,7 @@ def setup_completion(fatal_errors):
|
||||
f.write(opts_and_words('feeds2lrf', feeds2epub, feed_titles))
|
||||
f.write(opts_and_exts('html2epub', html2epub, ['html', 'htm', 'xhtm', 'xhtml', 'opf']))
|
||||
f.write(opts_and_exts('html2oeb', html2oeb, ['html', 'htm', 'xhtm', 'xhtml']))
|
||||
f.write(opts_and_exts('odt2oeb', odt2oeb, ['odt']))
|
||||
f.write('''
|
||||
_prs500_ls()
|
||||
{
|
||||
|
@ -32,6 +32,8 @@ What formats does |app| support conversion to/from?
|
||||
| | | | |
|
||||
| | EPUB | ✔ | ✔ |
|
||||
| | | | |
|
||||
| | ODT | ✔ | ✔ |
|
||||
| | | | |
|
||||
| | HTML | ✔ | ✔ |
|
||||
| | | | |
|
||||
| **Input formats** | CBR | ✔ | ✔ |
|
||||
|
0
src/odf/__init__.py
Normal file
0
src/odf/__init__.py
Normal file
61
src/odf/anim.py
Normal file
61
src/odf/anim.py
Normal file
@ -0,0 +1,61 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import ANIMNS
|
||||
from element import Element
|
||||
|
||||
|
||||
# Autogenerated
|
||||
def Animate(**args):
|
||||
return Element(qname = (ANIMNS,'animate'), **args)
|
||||
|
||||
def Animatecolor(**args):
|
||||
return Element(qname = (ANIMNS,'animateColor'), **args)
|
||||
|
||||
def Animatemotion(**args):
|
||||
return Element(qname = (ANIMNS,'animateMotion'), **args)
|
||||
|
||||
def Animatetransform(**args):
|
||||
return Element(qname = (ANIMNS,'animateTransform'), **args)
|
||||
|
||||
def Audio(**args):
|
||||
return Element(qname = (ANIMNS,'audio'), **args)
|
||||
|
||||
def Command(**args):
|
||||
return Element(qname = (ANIMNS,'command'), **args)
|
||||
|
||||
def Iterate(**args):
|
||||
return Element(qname = (ANIMNS,'iterate'), **args)
|
||||
|
||||
def Par(**args):
|
||||
return Element(qname = (ANIMNS,'par'), **args)
|
||||
|
||||
def Param(**args):
|
||||
return Element(qname = (ANIMNS,'param'), **args)
|
||||
|
||||
def Seq(**args):
|
||||
return Element(qname = (ANIMNS,'seq'), **args)
|
||||
|
||||
def Set(**args):
|
||||
return Element(qname = (ANIMNS,'set'), **args)
|
||||
|
||||
def Transitionfilter(**args):
|
||||
return Element(qname = (ANIMNS,'transitionFilter'), **args)
|
||||
|
1444
src/odf/attrconverters.py
Normal file
1444
src/odf/attrconverters.py
Normal file
File diff suppressed because it is too large
Load Diff
87
src/odf/chart.py
Normal file
87
src/odf/chart.py
Normal file
@ -0,0 +1,87 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import CHARTNS
|
||||
from element import Element
|
||||
|
||||
# Autogenerated
|
||||
def Axis(**args):
|
||||
return Element(qname = (CHARTNS,'axis'), **args)
|
||||
|
||||
def Categories(**args):
|
||||
return Element(qname = (CHARTNS,'categories'), **args)
|
||||
|
||||
def Chart(**args):
|
||||
return Element(qname = (CHARTNS,'chart'), **args)
|
||||
|
||||
def DataPoint(**args):
|
||||
return Element(qname = (CHARTNS,'data-point'), **args)
|
||||
|
||||
def Domain(**args):
|
||||
return Element(qname = (CHARTNS,'domain'), **args)
|
||||
|
||||
def ErrorIndicator(**args):
|
||||
return Element(qname = (CHARTNS,'error-indicator'), **args)
|
||||
|
||||
def Floor(**args):
|
||||
return Element(qname = (CHARTNS,'floor'), **args)
|
||||
|
||||
def Footer(**args):
|
||||
return Element(qname = (CHARTNS,'footer'), **args)
|
||||
|
||||
def Grid(**args):
|
||||
return Element(qname = (CHARTNS,'grid'), **args)
|
||||
|
||||
def Legend(**args):
|
||||
return Element(qname = (CHARTNS,'legend'), **args)
|
||||
|
||||
def MeanValue(**args):
|
||||
return Element(qname = (CHARTNS,'mean-value'), **args)
|
||||
|
||||
def PlotArea(**args):
|
||||
return Element(qname = (CHARTNS,'plot-area'), **args)
|
||||
|
||||
def RegressionCurve(**args):
|
||||
return Element(qname = (CHARTNS,'regression-curve'), **args)
|
||||
|
||||
def Series(**args):
|
||||
return Element(qname = (CHARTNS,'series'), **args)
|
||||
|
||||
def StockGainMarker(**args):
|
||||
return Element(qname = (CHARTNS,'stock-gain-marker'), **args)
|
||||
|
||||
def StockLossMarker(**args):
|
||||
return Element(qname = (CHARTNS,'stock-loss-marker'), **args)
|
||||
|
||||
def StockRangeLine(**args):
|
||||
return Element(qname = (CHARTNS,'stock-range-line'), **args)
|
||||
|
||||
def Subtitle(**args):
|
||||
return Element(qname = (CHARTNS,'subtitle'), **args)
|
||||
|
||||
def SymbolImage(**args):
|
||||
return Element(qname = (CHARTNS,'symbol-image'), **args)
|
||||
|
||||
def Title(**args):
|
||||
return Element(qname = (CHARTNS,'title'), **args)
|
||||
|
||||
def Wall(**args):
|
||||
return Element(qname = (CHARTNS,'wall'), **args)
|
||||
|
39
src/odf/config.py
Normal file
39
src/odf/config.py
Normal file
@ -0,0 +1,39 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import CONFIGNS
|
||||
from element import Element
|
||||
|
||||
# Autogenerated
|
||||
def ConfigItem(**args):
|
||||
return Element(qname = (CONFIGNS, 'config-item'), **args)
|
||||
|
||||
def ConfigItemMapEntry(**args):
|
||||
return Element(qname = (CONFIGNS,'config-item-map-entry'), **args)
|
||||
|
||||
def ConfigItemMapIndexed(**args):
|
||||
return Element(qname = (CONFIGNS,'config-item-map-indexed'), **args)
|
||||
|
||||
def ConfigItemMapNamed(**args):
|
||||
return Element(qname = (CONFIGNS,'config-item-map-named'), **args)
|
||||
|
||||
def ConfigItemSet(**args):
|
||||
return Element(qname = (CONFIGNS, 'config-item-set'), **args)
|
||||
|
72
src/odf/dc.py
Normal file
72
src/odf/dc.py
Normal file
@ -0,0 +1,72 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import DCNS
|
||||
from element import Element
|
||||
|
||||
# Autogenerated
|
||||
def Creator(**args):
|
||||
return Element(qname = (DCNS,'creator'), **args)
|
||||
|
||||
def Date(**args):
|
||||
return Element(qname = (DCNS,'date'), **args)
|
||||
|
||||
def Description(**args):
|
||||
return Element(qname = (DCNS,'description'), **args)
|
||||
|
||||
def Language(**args):
|
||||
return Element(qname = (DCNS,'language'), **args)
|
||||
|
||||
def Subject(**args):
|
||||
return Element(qname = (DCNS,'subject'), **args)
|
||||
|
||||
def Title(**args):
|
||||
return Element(qname = (DCNS,'title'), **args)
|
||||
|
||||
# The following complete the Dublin Core elements, but there is no
|
||||
# guarantee a compliant implementation of OpenDocument will preserve
|
||||
# these elements
|
||||
|
||||
#def Contributor(**args):
|
||||
# return Element(qname = (DCNS,'contributor'), **args)
|
||||
|
||||
#def Coverage(**args):
|
||||
# return Element(qname = (DCNS,'coverage'), **args)
|
||||
|
||||
#def Format(**args):
|
||||
# return Element(qname = (DCNS,'format'), **args)
|
||||
|
||||
#def Identifier(**args):
|
||||
# return Element(qname = (DCNS,'identifier'), **args)
|
||||
|
||||
#def Publisher(**args):
|
||||
# return Element(qname = (DCNS,'publisher'), **args)
|
||||
|
||||
#def Relation(**args):
|
||||
# return Element(qname = (DCNS,'relation'), **args)
|
||||
|
||||
#def Rights(**args):
|
||||
# return Element(qname = (DCNS,'rights'), **args)
|
||||
|
||||
#def Source(**args):
|
||||
# return Element(qname = (DCNS,'source'), **args)
|
||||
|
||||
#def Type(**args):
|
||||
# return Element(qname = (DCNS,'type'), **args)
|
43
src/odf/dr3d.py
Normal file
43
src/odf/dr3d.py
Normal file
@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import DR3DNS
|
||||
from element import Element
|
||||
from draw import StyleRefElement
|
||||
|
||||
# Autogenerated
|
||||
def Cube(**args):
|
||||
return StyleRefElement(qname = (DR3DNS,'cube'), **args)
|
||||
|
||||
def Extrude(**args):
|
||||
return StyleRefElement(qname = (DR3DNS,'extrude'), **args)
|
||||
|
||||
def Light(Element):
|
||||
return StyleRefElement(qname = (DR3DNS,'light'), **args)
|
||||
|
||||
def Rotate(**args):
|
||||
return StyleRefElement(qname = (DR3DNS,'rotate'), **args)
|
||||
|
||||
def Scene(**args):
|
||||
return StyleRefElement(qname = (DR3DNS,'scene'), **args)
|
||||
|
||||
def Sphere(**args):
|
||||
return StyleRefElement(qname = (DR3DNS,'sphere'), **args)
|
||||
|
182
src/odf/draw.py
Normal file
182
src/odf/draw.py
Normal file
@ -0,0 +1,182 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import DRAWNS, STYLENS, PRESENTATIONNS
|
||||
from element import Element
|
||||
|
||||
def StyleRefElement(stylename=None, classnames=None, **args):
|
||||
qattrs = {}
|
||||
if stylename is not None:
|
||||
f = stylename.getAttrNS(STYLENS, 'family')
|
||||
if f == 'graphic':
|
||||
qattrs[(DRAWNS,u'style-name')]= stylename
|
||||
elif f == 'presentation':
|
||||
qattrs[(PRESENTATIONNS,u'style-name')]= stylename
|
||||
else:
|
||||
raise ValueError, "Style's family must be either 'graphic' or 'presentation'"
|
||||
if classnames is not None:
|
||||
f = classnames[0].getAttrNS(STYLENS, 'family')
|
||||
if f == 'graphic':
|
||||
qattrs[(DRAWNS,u'class-names')]= classnames
|
||||
elif f == 'presentation':
|
||||
qattrs[(PRESENTATIONNS,u'class-names')]= classnames
|
||||
else:
|
||||
raise ValueError, "Style's family must be either 'graphic' or 'presentation'"
|
||||
return Element(qattributes=qattrs, **args)
|
||||
|
||||
def DrawElement(name=None, **args):
|
||||
e = Element(name=name, **args)
|
||||
if not args.has_key('displayname'):
|
||||
e.setAttrNS(DRAWNS,'display-name', name)
|
||||
return e
|
||||
|
||||
# Autogenerated
|
||||
def A(**args):
|
||||
return Element(qname = (DRAWNS,'a'), **args)
|
||||
|
||||
def Applet(**args):
|
||||
return Element(qname = (DRAWNS,'applet'), **args)
|
||||
|
||||
def AreaCircle(**args):
|
||||
return Element(qname = (DRAWNS,'area-circle'), **args)
|
||||
|
||||
def AreaPolygon(**args):
|
||||
return Element(qname = (DRAWNS,'area-polygon'), **args)
|
||||
|
||||
def AreaRectangle(**args):
|
||||
return Element(qname = (DRAWNS,'area-rectangle'), **args)
|
||||
|
||||
def Caption(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'caption'), **args)
|
||||
|
||||
def Circle(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'circle'), **args)
|
||||
|
||||
def Connector(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'connector'), **args)
|
||||
|
||||
def ContourPath(**args):
|
||||
return Element(qname = (DRAWNS,'contour-path'), **args)
|
||||
|
||||
def ContourPolygon(**args):
|
||||
return Element(qname = (DRAWNS,'contour-polygon'), **args)
|
||||
|
||||
def Control(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'control'), **args)
|
||||
|
||||
def CustomShape(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'custom-shape'), **args)
|
||||
|
||||
def Ellipse(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'ellipse'), **args)
|
||||
|
||||
def EnhancedGeometry(**args):
|
||||
return Element(qname = (DRAWNS,'enhanced-geometry'), **args)
|
||||
|
||||
def Equation(**args):
|
||||
return Element(qname = (DRAWNS,'equation'), **args)
|
||||
|
||||
def FillImage(**args):
|
||||
return DrawElement(qname = (DRAWNS,'fill-image'), **args)
|
||||
|
||||
def FloatingFrame(**args):
|
||||
return Element(qname = (DRAWNS,'floating-frame'), **args)
|
||||
|
||||
def Frame(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'frame'), **args)
|
||||
|
||||
def G(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'g'), **args)
|
||||
|
||||
def GluePoint(**args):
|
||||
return Element(qname = (DRAWNS,'glue-point'), **args)
|
||||
|
||||
def Gradient(**args):
|
||||
return DrawElement(qname = (DRAWNS,'gradient'), **args)
|
||||
|
||||
def Handle(**args):
|
||||
return Element(qname = (DRAWNS,'handle'), **args)
|
||||
|
||||
def Hatch(**args):
|
||||
return DrawElement(qname = (DRAWNS,'hatch'), **args)
|
||||
|
||||
def Image(**args):
|
||||
return Element(qname = (DRAWNS,'image'), **args)
|
||||
|
||||
def ImageMap(**args):
|
||||
return Element(qname = (DRAWNS,'image-map'), **args)
|
||||
|
||||
def Layer(**args):
|
||||
return Element(qname = (DRAWNS,'layer'), **args)
|
||||
|
||||
def LayerSet(**args):
|
||||
return Element(qname = (DRAWNS,'layer-set'), **args)
|
||||
|
||||
def Line(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'line'), **args)
|
||||
|
||||
def Marker(**args):
|
||||
return DrawElement(qname = (DRAWNS,'marker'), **args)
|
||||
|
||||
def Measure(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'measure'), **args)
|
||||
|
||||
def Object(**args):
|
||||
return Element(qname = (DRAWNS,'object'), **args)
|
||||
|
||||
def ObjectOle(**args):
|
||||
return Element(qname = (DRAWNS,'object-ole'), **args)
|
||||
|
||||
def Opacity(**args):
|
||||
return DrawElement(qname = (DRAWNS,'opacity'), **args)
|
||||
|
||||
def Page(**args):
|
||||
return Element(qname = (DRAWNS,'page'), **args)
|
||||
|
||||
def PageThumbnail(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'page-thumbnail'), **args)
|
||||
|
||||
def Param(**args):
|
||||
return Element(qname = (DRAWNS,'param'), **args)
|
||||
|
||||
def Path(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'path'), **args)
|
||||
|
||||
def Plugin(**args):
|
||||
return Element(qname = (DRAWNS,'plugin'), **args)
|
||||
|
||||
def Polygon(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'polygon'), **args)
|
||||
|
||||
def Polyline(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'polyline'), **args)
|
||||
|
||||
def Rect(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'rect'), **args)
|
||||
|
||||
def RegularPolygon(**args):
|
||||
return StyleRefElement(qname = (DRAWNS,'regular-polygon'), **args)
|
||||
|
||||
def StrokeDash(**args):
|
||||
return DrawElement(qname = (DRAWNS,'stroke-dash'), **args)
|
||||
|
||||
def TextBox(**args):
|
||||
return Element(qname = (DRAWNS,'text-box'), **args)
|
||||
|
103
src/odf/easyliststyle.py
Normal file
103
src/odf/easyliststyle.py
Normal file
@ -0,0 +1,103 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Create a <text:list-style> element from a text string.
|
||||
# Copyright (C) 2008 J. David Eisenberg
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, 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):
|
||||
#
|
||||
|
||||
import re
|
||||
from style import Style, TextProperties, ListLevelProperties
|
||||
from text import ListStyle,ListLevelStyleNumber,ListLevelStyleBullet
|
||||
|
||||
"""
|
||||
Create a <text:list-style> element from a string or array.
|
||||
|
||||
List styles require a lot of code to create one level at a time.
|
||||
These routines take a string and delimiter, or a list of
|
||||
strings, and creates a <text:list-style> element for you.
|
||||
Each item in the string (or array) represents a list level
|
||||
* style for levels 1-10.</p>
|
||||
*
|
||||
* <p>If an item contains <code>1</code>, <code>I</code>,
|
||||
* <code>i</code>, <code>A</code>, or <code>a</code>, then it is presumed
|
||||
* to be a numbering style; otherwise it is a bulleted style.</p>
|
||||
"""
|
||||
|
||||
_MAX_LIST_LEVEL = 10
|
||||
SHOW_ALL_LEVELS = True
|
||||
SHOW_ONE_LEVEL = False
|
||||
|
||||
def styleFromString(name, specifiers, delim, spacing, showAllLevels):
|
||||
specArray = specifiers.split(delim)
|
||||
return styleFromList( name, specArray, spacing, showAllLevels )
|
||||
|
||||
def styleFromList( styleName, specArray, spacing, showAllLevels):
|
||||
bullet = ""
|
||||
numPrefix = ""
|
||||
numSuffix = ""
|
||||
numberFormat = ""
|
||||
cssLengthNum = 0
|
||||
cssLengthUnits = ""
|
||||
numbered = False
|
||||
displayLevels = 0
|
||||
listStyle = ListStyle(name=styleName)
|
||||
numFormatPattern = re.compile("([1IiAa])")
|
||||
cssLengthPattern = re.compile("([^a-z]+)\\s*([a-z]+)?")
|
||||
m = cssLengthPattern.search( spacing )
|
||||
if (m != None):
|
||||
cssLengthNum = float(m.group(1))
|
||||
if (m.lastindex == 2):
|
||||
cssLengthUnits = m.group(2)
|
||||
i = 0
|
||||
while i < len(specArray):
|
||||
specification = specArray[i]
|
||||
m = numFormatPattern.search(specification)
|
||||
if (m != None):
|
||||
numberFormat = m.group(1)
|
||||
numPrefix = specification[0:m.start(1)]
|
||||
numSuffix = specification[m.end(1):]
|
||||
bullet = ""
|
||||
numbered = True
|
||||
if (showAllLevels):
|
||||
displayLevels = i + 1
|
||||
else:
|
||||
displayLevels = 1
|
||||
else: # it's a bullet style
|
||||
bullet = specification
|
||||
numPrefix = ""
|
||||
numSuffix = ""
|
||||
numberFormat = ""
|
||||
displayLevels = 1
|
||||
numbered = False
|
||||
if (numbered):
|
||||
lls = ListLevelStyleNumber(level=(i+1))
|
||||
if (numPrefix != ''):
|
||||
lls.setAttribute('numprefix', numPrefix)
|
||||
if (numSuffix != ''):
|
||||
lls.setAttribute('numsuffix', numSuffix)
|
||||
lls.setAttribute('displaylevels', displayLevels)
|
||||
else:
|
||||
lls = ListLevelStyleBullet(level=(i+1),bulletchar=bullet[0])
|
||||
llp = ListLevelProperties()
|
||||
llp.setAttribute('spacebefore', str(cssLengthNum * (i+1)) + cssLengthUnits)
|
||||
llp.setAttribute('minlabelwidth', str(cssLengthNum) + cssLengthUnits)
|
||||
lls.addElement( llp )
|
||||
listStyle.addElement(lls)
|
||||
i += 1
|
||||
return listStyle
|
||||
|
||||
# vim: set expandtab sw=4 :
|
454
src/odf/element.py
Normal file
454
src/odf/element.py
Normal file
@ -0,0 +1,454 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007-2008 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
# Note: This script has copied a lot of text from xml.dom.minidom.
|
||||
# Whatever license applies to that file also applies to this file.
|
||||
#
|
||||
import xml.dom
|
||||
from xml.dom.minicompat import *
|
||||
from namespaces import nsdict
|
||||
import grammar
|
||||
from attrconverters import AttrConverters
|
||||
|
||||
# The following code is pasted form xml.sax.saxutils
|
||||
# Tt makes it possible to run the code without the xml sax package installed
|
||||
# To make it possible to have <rubbish> in your text elements, it is necessary to escape the texts
|
||||
def _escape(data, entities={}):
|
||||
""" Escape &, <, and > in a string of data.
|
||||
|
||||
You can escape other strings of data by passing a dictionary as
|
||||
the optional entities parameter. The keys and values must all be
|
||||
strings; each key will be replaced with its corresponding value.
|
||||
"""
|
||||
data = data.replace("&", "&")
|
||||
data = data.replace("<", "<")
|
||||
data = data.replace(">", ">")
|
||||
for chars, entity in entities.items():
|
||||
data = data.replace(chars, entity)
|
||||
return data
|
||||
|
||||
def _quoteattr(data, entities={}):
|
||||
""" Escape and quote an attribute value.
|
||||
|
||||
Escape &, <, and > in a string of data, then quote it for use as
|
||||
an attribute value. The \" character will be escaped as well, if
|
||||
necessary.
|
||||
|
||||
You can escape other strings of data by passing a dictionary as
|
||||
the optional entities parameter. The keys and values must all be
|
||||
strings; each key will be replaced with its corresponding value.
|
||||
"""
|
||||
data = _escape(data, entities)
|
||||
if '"' in data:
|
||||
if "'" in data:
|
||||
data = '"%s"' % data.replace('"', """)
|
||||
else:
|
||||
data = "'%s'" % data
|
||||
else:
|
||||
data = '"%s"' % data
|
||||
return data
|
||||
|
||||
def _nssplit(qualifiedName):
|
||||
""" Split a qualified name into namespace part and local part. """
|
||||
fields = qualifiedName.split(':', 1)
|
||||
if len(fields) == 2:
|
||||
return fields
|
||||
else:
|
||||
return (None, fields[0])
|
||||
|
||||
def _nsassign(namespace):
|
||||
return nsdict.setdefault(namespace,"ns" + str(len(nsdict)))
|
||||
|
||||
# Exceptions
|
||||
class IllegalChild(StandardError):
|
||||
""" Complains if you add an element to a parent where it is not allowed """
|
||||
class IllegalText(StandardError):
|
||||
""" Complains if you add text or cdata to an element where it is not allowed """
|
||||
|
||||
class Node(xml.dom.Node):
|
||||
""" super class for more specific nodes """
|
||||
parentNode = None
|
||||
nextSibling = None
|
||||
previousSibling = None
|
||||
|
||||
def hasChildNodes(self):
|
||||
""" Tells whether this element has any children; text nodes,
|
||||
subelements, whatever.
|
||||
"""
|
||||
if self.childNodes:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def _get_childNodes(self):
|
||||
return self.childNodes
|
||||
|
||||
def _get_firstChild(self):
|
||||
if self.childNodes:
|
||||
return self.childNodes[0]
|
||||
|
||||
def _get_lastChild(self):
|
||||
if self.childNodes:
|
||||
return self.childNodes[-1]
|
||||
|
||||
def insertBefore(self, newChild, refChild):
|
||||
if newChild.nodeType not in self._child_node_types:
|
||||
raise IllegalChild, "%s cannot be child of %s" % (newChild.tagName, self.tagName)
|
||||
if newChild.parentNode is not None:
|
||||
newChild.parentNode.removeChild(newChild)
|
||||
if refChild is None:
|
||||
self.appendChild(newChild)
|
||||
else:
|
||||
try:
|
||||
index = self.childNodes.index(refChild)
|
||||
except ValueError:
|
||||
raise xml.dom.NotFoundErr()
|
||||
self.childNodes.insert(index, newChild)
|
||||
newChild.nextSibling = refChild
|
||||
refChild.previousSibling = newChild
|
||||
if index:
|
||||
node = self.childNodes[index-1]
|
||||
node.nextSibling = newChild
|
||||
newChild.previousSibling = node
|
||||
else:
|
||||
newChild.previousSibling = None
|
||||
newChild.parentNode = self
|
||||
return newChild
|
||||
|
||||
def appendChild(self, node):
|
||||
if node.nodeType == self.DOCUMENT_FRAGMENT_NODE:
|
||||
for c in tuple(node.childNodes):
|
||||
self.appendChild(c)
|
||||
### The DOM does not clearly specify what to return in this case
|
||||
return node
|
||||
if node.nodeType not in self._child_node_types:
|
||||
raise IllegalChild, "<%s> is not allowed in %s" % ( node.tagName, self.tagName)
|
||||
if node.parentNode is not None:
|
||||
node.parentNode.removeChild(node)
|
||||
_append_child(self, node)
|
||||
node.nextSibling = None
|
||||
return node
|
||||
|
||||
def removeChild(self, oldChild):
|
||||
#FIXME: update ownerDocument.element_dict or find other solution
|
||||
try:
|
||||
self.childNodes.remove(oldChild)
|
||||
except ValueError:
|
||||
raise xml.dom.NotFoundErr()
|
||||
if oldChild.nextSibling is not None:
|
||||
oldChild.nextSibling.previousSibling = oldChild.previousSibling
|
||||
if oldChild.previousSibling is not None:
|
||||
oldChild.previousSibling.nextSibling = oldChild.nextSibling
|
||||
oldChild.nextSibling = oldChild.previousSibling = None
|
||||
if self.ownerDocument:
|
||||
self.ownerDocument.clear_caches()
|
||||
oldChild.parentNode = None
|
||||
return oldChild
|
||||
|
||||
defproperty(Node, "firstChild", doc="First child node, or None.")
|
||||
defproperty(Node, "lastChild", doc="Last child node, or None.")
|
||||
|
||||
def _append_child(self, node):
|
||||
# fast path with less checks; usable by DOM builders if careful
|
||||
childNodes = self.childNodes
|
||||
if childNodes:
|
||||
last = childNodes[-1]
|
||||
node.__dict__["previousSibling"] = last
|
||||
last.__dict__["nextSibling"] = node
|
||||
childNodes.append(node)
|
||||
node.__dict__["parentNode"] = self
|
||||
|
||||
class Childless:
|
||||
"""Mixin that makes childless-ness easy to implement and avoids
|
||||
the complexity of the Node methods that deal with children.
|
||||
"""
|
||||
|
||||
attributes = None
|
||||
childNodes = EmptyNodeList()
|
||||
firstChild = None
|
||||
lastChild = None
|
||||
|
||||
def _get_firstChild(self):
|
||||
return None
|
||||
|
||||
def _get_lastChild(self):
|
||||
return None
|
||||
|
||||
def appendChild(self, node):
|
||||
raise xml.dom.HierarchyRequestErr(
|
||||
self.tagName + " nodes cannot have children")
|
||||
|
||||
def hasChildNodes(self):
|
||||
return False
|
||||
|
||||
def insertBefore(self, newChild, refChild):
|
||||
raise xml.dom.HierarchyRequestErr(
|
||||
self.tagName + " nodes do not have children")
|
||||
|
||||
def removeChild(self, oldChild):
|
||||
raise xml.dom.NotFoundErr(
|
||||
self.tagName + " nodes do not have children")
|
||||
|
||||
def replaceChild(self, newChild, oldChild):
|
||||
raise xml.dom.HierarchyRequestErr(
|
||||
self.tagName + " nodes do not have children")
|
||||
|
||||
class Text(Childless, Node):
|
||||
nodeType = Node.TEXT_NODE
|
||||
tagName = "Text"
|
||||
|
||||
def __init__(self, data):
|
||||
self.data = data
|
||||
|
||||
def __str__(self):
|
||||
return self.data
|
||||
|
||||
def toXml(self,level,f):
|
||||
""" Write XML in UTF-8 """
|
||||
if self.data:
|
||||
f.write(_escape(unicode(self.data).encode('utf-8')))
|
||||
|
||||
class CDATASection(Childless, Text):
|
||||
nodeType = Node.CDATA_SECTION_NODE
|
||||
|
||||
def toXml(self,level,f):
|
||||
if self.data:
|
||||
f.write('<![CDATA[%s]]>' % self.data)
|
||||
|
||||
class Element(Node):
|
||||
""" Creates a arbitrary element and is intended to be subclassed not used on its own.
|
||||
This element is the base of every element it defines a class which resembles
|
||||
a xml-element. The main advantage of this kind of implementation is that you don't
|
||||
have to create a toXML method for every different object. Every element
|
||||
consists of an attribute, optional subelements, optional text and optional cdata.
|
||||
"""
|
||||
|
||||
nodeType = Node.ELEMENT_NODE
|
||||
namespaces = {} # Due to shallow copy this is a static variable
|
||||
|
||||
_child_node_types = (Node.ELEMENT_NODE,
|
||||
Node.PROCESSING_INSTRUCTION_NODE,
|
||||
Node.COMMENT_NODE,
|
||||
Node.TEXT_NODE,
|
||||
Node.CDATA_SECTION_NODE,
|
||||
Node.ENTITY_REFERENCE_NODE)
|
||||
|
||||
def __init__(self, attributes=None, text=None, cdata=None, qname=None, qattributes=None, check_grammar=True, **args):
|
||||
if qname is not None:
|
||||
self.qname = qname
|
||||
assert(hasattr(self, 'qname'))
|
||||
self.ownerDocument = None
|
||||
self.childNodes=[]
|
||||
self.allowed_children = grammar.allowed_children.get(self.qname)
|
||||
namespace = self.qname[0]
|
||||
prefix = _nsassign(namespace)
|
||||
if not self.namespaces.has_key(namespace):
|
||||
self.namespaces[namespace] = prefix
|
||||
self.tagName = prefix + ":" + self.qname[1]
|
||||
if text is not None:
|
||||
self.addText(text)
|
||||
if cdata is not None:
|
||||
self.addCDATA(cdata)
|
||||
|
||||
allowed_attrs = self.allowed_attributes()
|
||||
if allowed_attrs is not None:
|
||||
allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
|
||||
self.attributes={}
|
||||
# Load the attributes from the 'attributes' argument
|
||||
if attributes:
|
||||
for attr, value in attributes.items():
|
||||
self.setAttribute(attr, value)
|
||||
# Load the qualified attributes
|
||||
if qattributes:
|
||||
for attr, value in qattributes.items():
|
||||
self.setAttrNS(attr[0], attr[1], value)
|
||||
if allowed_attrs is not None:
|
||||
# Load the attributes from the 'args' argument
|
||||
for arg in args.keys():
|
||||
self.setAttribute(arg, args[arg])
|
||||
else:
|
||||
for arg in args.keys(): # If any attribute is allowed
|
||||
self.attributes[arg]=args[arg]
|
||||
if not check_grammar:
|
||||
return
|
||||
# Test that all mandatory attributes have been added.
|
||||
required = grammar.required_attributes.get(self.qname)
|
||||
if required:
|
||||
for r in required:
|
||||
if self.getAttrNS(r[0],r[1]) is None:
|
||||
raise AttributeError, "Required attribute missing: %s in <%s>" % (r[1].lower().replace('-',''), self.tagName)
|
||||
|
||||
def allowed_attributes(self):
|
||||
return grammar.allowed_attributes.get(self.qname)
|
||||
|
||||
def _setOwnerDoc(self, element):
|
||||
element.ownerDocument = self.ownerDocument
|
||||
for child in element.childNodes:
|
||||
self._setOwnerDoc(child)
|
||||
|
||||
def addElement(self, element, check_grammar=True):
|
||||
""" adds an element to an Element
|
||||
|
||||
Element.addElement(Element)
|
||||
"""
|
||||
if check_grammar and self.allowed_children is not None:
|
||||
if element.qname not in self.allowed_children:
|
||||
raise IllegalChild, "<%s> is not allowed in <%s>" % ( element.tagName, self.tagName)
|
||||
self.appendChild(element)
|
||||
self._setOwnerDoc(element)
|
||||
if self.ownerDocument:
|
||||
self.ownerDocument.rebuild_caches(element)
|
||||
|
||||
def addText(self, text, check_grammar=True):
|
||||
if check_grammar and self.qname not in grammar.allows_text:
|
||||
raise IllegalText, "The <%s> element does not allow text" % self.tagName
|
||||
else:
|
||||
if text != '':
|
||||
self.appendChild(Text(text))
|
||||
|
||||
def addCDATA(self, cdata, check_grammar=True):
|
||||
if check_grammar and self.qname not in grammar.allows_text:
|
||||
raise IllegalText, "The <%s> element does not allow text" % self.tagName
|
||||
else:
|
||||
self.appendChild(CDATASection(cdata))
|
||||
|
||||
def removeAttribute(self, attr, check_grammar=True):
|
||||
""" Removes an attribute by name. """
|
||||
allowed_attrs = self.allowed_attributes()
|
||||
if allowed_attrs is None:
|
||||
if type(attr) == type(()):
|
||||
prefix, localname = attr
|
||||
self.removeAttrNS(prefix, localname)
|
||||
else:
|
||||
raise AttributeError, "Unable to add simple attribute - use (namespace, localpart)"
|
||||
else:
|
||||
# Construct a list of allowed arguments
|
||||
allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
|
||||
if check_grammar and attr not in allowed_args:
|
||||
raise AttributeError, "Attribute %s is not allowed in <%s>" % ( attr, self.tagName)
|
||||
i = allowed_args.index(attr)
|
||||
self.removeAttrNS(allowed_attrs[i][0], allowed_attrs[i][1])
|
||||
|
||||
def setAttribute(self, attr, value, check_grammar=True):
|
||||
""" Add an attribute to the element
|
||||
This is sort of a convenience method. All attributes in ODF have
|
||||
namespaces. The library knows what attributes are legal and then allows
|
||||
the user to provide the attribute as a keyword argument and the
|
||||
library will add the correct namespace.
|
||||
Must overwrite, If attribute already exists.
|
||||
"""
|
||||
allowed_attrs = self.allowed_attributes()
|
||||
if allowed_attrs is None:
|
||||
if type(attr) == type(()):
|
||||
prefix, localname = attr
|
||||
self.setAttrNS(prefix, localname, value)
|
||||
else:
|
||||
raise AttributeError, "Unable to add simple attribute - use (namespace, localpart)"
|
||||
else:
|
||||
# Construct a list of allowed arguments
|
||||
allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
|
||||
if check_grammar and attr not in allowed_args:
|
||||
raise AttributeError, "Attribute %s is not allowed in <%s>" % ( attr, self.tagName)
|
||||
i = allowed_args.index(attr)
|
||||
self.setAttrNS(allowed_attrs[i][0], allowed_attrs[i][1], value)
|
||||
|
||||
def setAttrNS(self, namespace, localpart, value):
|
||||
""" Add an attribute to the element
|
||||
In case you need to add an attribute the library doesn't know about
|
||||
then you must provide the full qualified name
|
||||
It will not check that the attribute is legal according to the schema.
|
||||
Must overwrite, If attribute already exists.
|
||||
"""
|
||||
allowed_attrs = self.allowed_attributes()
|
||||
prefix = _nsassign(namespace)
|
||||
if not self.namespaces.has_key(namespace):
|
||||
self.namespaces[namespace] = prefix
|
||||
# if allowed_attrs and (namespace, localpart) not in allowed_attrs:
|
||||
# raise AttributeError, "Attribute %s:%s is not allowed in element <%s>" % ( prefix, localpart, self.tagName)
|
||||
c = AttrConverters()
|
||||
self.attributes[prefix + ":" + localpart] = c.convert((namespace, localpart), value, self.qname)
|
||||
|
||||
def getAttrNS(self, namespace, localpart):
|
||||
prefix = _nsassign(namespace)
|
||||
if not self.namespaces.has_key(namespace):
|
||||
self.namespaces[namespace] = prefix
|
||||
return self.attributes.get(prefix + ":" + localpart)
|
||||
|
||||
def removeAttrNS(self, namespace, localpart):
|
||||
prefix = _nsassign(namespace)
|
||||
if not self.namespaces.has_key(namespace):
|
||||
self.namespaces[namespace] = prefix
|
||||
del self.attributes[prefix + ":" + localpart]
|
||||
|
||||
def getAttribute(self, attr):
|
||||
allowed_attrs = self.allowed_attributes()
|
||||
if allowed_attrs is None:
|
||||
if type(attr) == type(()):
|
||||
prefix, localname = attr
|
||||
return self.getAttrNS(prefix, localname)
|
||||
else:
|
||||
raise AttributeError, "Unable to get simple attribute - use (namespace, localpart)"
|
||||
else:
|
||||
# Construct a list of allowed arguments
|
||||
allowed_args = [ a[1].lower().replace('-','') for a in allowed_attrs]
|
||||
i = allowed_args.index(attr)
|
||||
return self.getAttrNS(allowed_attrs[i][0], allowed_attrs[i][1])
|
||||
|
||||
def write_open_tag(self, level, f):
|
||||
f.write('<'+self.tagName)
|
||||
if level == 0:
|
||||
for namespace, prefix in self.namespaces.items():
|
||||
f.write(' xmlns:' + prefix + '="'+ _escape(str(namespace))+'"')
|
||||
for attkey in self.attributes.keys():
|
||||
f.write(' '+_escape(str(attkey))+'='+_quoteattr(unicode(self.attributes[attkey]).encode('utf-8')))
|
||||
f.write('>')
|
||||
|
||||
def write_close_tag(self, level, f):
|
||||
f.write('</'+self.tagName+'>')
|
||||
|
||||
def toXml(self, level, f):
|
||||
""" Generate XML stream out of the tree structure """
|
||||
f.write('<'+self.tagName)
|
||||
if level == 0:
|
||||
for namespace, prefix in self.namespaces.items():
|
||||
f.write(' xmlns:' + prefix + '="'+ _escape(str(namespace))+'"')
|
||||
for attkey in self.attributes.keys():
|
||||
f.write(' '+_escape(str(attkey))+'='+_quoteattr(unicode(self.attributes[attkey]).encode('utf-8')))
|
||||
if self.childNodes:
|
||||
f.write('>')
|
||||
for element in self.childNodes:
|
||||
element.toXml(level+1,f)
|
||||
f.write('</'+self.tagName+'>')
|
||||
else:
|
||||
f.write('/>')
|
||||
|
||||
def _getElementsByObj(self, obj, accumulator):
|
||||
if self.qname == obj.qname:
|
||||
accumulator.append(self)
|
||||
for e in self.childNodes:
|
||||
if e.nodeType == Node.ELEMENT_NODE:
|
||||
accumulator = e._getElementsByObj(obj, accumulator)
|
||||
return accumulator
|
||||
|
||||
def getElementsByType(self, element):
|
||||
obj = element(check_grammar=False)
|
||||
return self._getElementsByObj(obj,[])
|
||||
|
330
src/odf/elementtypes.py
Normal file
330
src/odf/elementtypes.py
Normal file
@ -0,0 +1,330 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2008 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import *
|
||||
|
||||
# Inline element don't cause a box
|
||||
# They are analogous to the HTML elements SPAN, B, I etc.
|
||||
inline_elements = (
|
||||
(TEXTNS,u'a'),
|
||||
(TEXTNS,u'author-initials'),
|
||||
(TEXTNS,u'author-name'),
|
||||
(TEXTNS,u'bibliography-mark'),
|
||||
(TEXTNS,u'bookmark-ref'),
|
||||
(TEXTNS,u'chapter'),
|
||||
(TEXTNS,u'character-count'),
|
||||
(TEXTNS,u'conditional-text'),
|
||||
(TEXTNS,u'creation-date'),
|
||||
(TEXTNS,u'creation-time'),
|
||||
(TEXTNS,u'creator'),
|
||||
(TEXTNS,u'database-display'),
|
||||
(TEXTNS,u'database-name'),
|
||||
(TEXTNS,u'database-next'),
|
||||
(TEXTNS,u'database-row-number'),
|
||||
(TEXTNS,u'database-row-select'),
|
||||
(TEXTNS,u'date'),
|
||||
(TEXTNS,u'dde-connection'),
|
||||
(TEXTNS,u'description'),
|
||||
(TEXTNS,u'editing-cycles'),
|
||||
(TEXTNS,u'editing-duration'),
|
||||
(TEXTNS,u'execute-macro'),
|
||||
(TEXTNS,u'expression'),
|
||||
(TEXTNS,u'file-name'),
|
||||
(TEXTNS,u'hidden-paragraph'),
|
||||
(TEXTNS,u'hidden-text'),
|
||||
(TEXTNS,u'image-count'),
|
||||
(TEXTNS,u'initial-creator'),
|
||||
(TEXTNS,u'keywords'),
|
||||
(TEXTNS,u'measure'),
|
||||
(TEXTNS,u'modification-date'),
|
||||
(TEXTNS,u'modification-time'),
|
||||
(TEXTNS,u'note-ref'),
|
||||
(TEXTNS,u'object-count'),
|
||||
(TEXTNS,u'page-continuation'),
|
||||
(TEXTNS,u'page-count'),
|
||||
(TEXTNS,u'page-number'),
|
||||
(TEXTNS,u'page-variable-get'),
|
||||
(TEXTNS,u'page-variable-set'),
|
||||
(TEXTNS,u'paragraph-count'),
|
||||
(TEXTNS,u'placeholder'),
|
||||
(TEXTNS,u'print-date'),
|
||||
(TEXTNS,u'printed-by'),
|
||||
(TEXTNS,u'print-time'),
|
||||
(TEXTNS,u'reference-ref'),
|
||||
(TEXTNS,u'ruby'),
|
||||
(TEXTNS,u'ruby-base'),
|
||||
(TEXTNS,u'ruby-text'),
|
||||
(TEXTNS,u'script'),
|
||||
(TEXTNS,u'sender-city'),
|
||||
(TEXTNS,u'sender-company'),
|
||||
(TEXTNS,u'sender-country'),
|
||||
(TEXTNS,u'sender-email'),
|
||||
(TEXTNS,u'sender-fax'),
|
||||
(TEXTNS,u'sender-firstname'),
|
||||
(TEXTNS,u'sender-initials'),
|
||||
(TEXTNS,u'sender-lastname'),
|
||||
(TEXTNS,u'sender-phone-private'),
|
||||
(TEXTNS,u'sender-phone-work'),
|
||||
(TEXTNS,u'sender-position'),
|
||||
(TEXTNS,u'sender-postal-code'),
|
||||
(TEXTNS,u'sender-state-or-province'),
|
||||
(TEXTNS,u'sender-street'),
|
||||
(TEXTNS,u'sender-title'),
|
||||
(TEXTNS,u'sequence'),
|
||||
(TEXTNS,u'sequence-ref'),
|
||||
(TEXTNS,u'sheet-name'),
|
||||
(TEXTNS,u'span'),
|
||||
(TEXTNS,u'subject'),
|
||||
(TEXTNS,u'table-count'),
|
||||
(TEXTNS,u'table-formula'),
|
||||
(TEXTNS,u'template-name'),
|
||||
(TEXTNS,u'text-input'),
|
||||
(TEXTNS,u'time'),
|
||||
(TEXTNS,u'title'),
|
||||
(TEXTNS,u'user-defined'),
|
||||
(TEXTNS,u'user-field-get'),
|
||||
(TEXTNS,u'user-field-input'),
|
||||
(TEXTNS,u'variable-get'),
|
||||
(TEXTNS,u'variable-input'),
|
||||
(TEXTNS,u'variable-set'),
|
||||
(TEXTNS,u'word-count'),
|
||||
)
|
||||
|
||||
|
||||
struct_elements = (
|
||||
(CONFIGNS,'config-item-set'),
|
||||
(TABLENS,u'table-cell'),
|
||||
)
|
||||
|
||||
# It is almost impossible to determine what elements are block elements.
|
||||
# There are so many that don't fit the form
|
||||
block_elements = (
|
||||
(TEXTNS,u'h'),
|
||||
(TEXTNS,u'p'),
|
||||
(TEXTNS,u'list'),
|
||||
(TEXTNS,u'list-item'),
|
||||
(TEXTNS,u'section'),
|
||||
)
|
||||
|
||||
declarative_elements = (
|
||||
(OFFICENS,u'font-face-decls'),
|
||||
(PRESENTATIONNS,u'date-time-decl'),
|
||||
(PRESENTATIONNS,u'footer-decl'),
|
||||
(PRESENTATIONNS,u'header-decl'),
|
||||
(TABLENS,u'table-template'),
|
||||
(TEXTNS,u'alphabetical-index-entry-template'),
|
||||
(TEXTNS,u'alphabetical-index-source'),
|
||||
(TEXTNS,u'bibliography-entry-template'),
|
||||
(TEXTNS,u'bibliography-source'),
|
||||
(TEXTNS,u'dde-connection-decls'),
|
||||
(TEXTNS,u'illustration-index-entry-template'),
|
||||
(TEXTNS,u'illustration-index-source'),
|
||||
(TEXTNS,u'index-source-styles'),
|
||||
(TEXTNS,u'index-title-template'),
|
||||
(TEXTNS,u'note-continuation-notice-backward'),
|
||||
(TEXTNS,u'note-continuation-notice-forward'),
|
||||
(TEXTNS,u'notes-configuration'),
|
||||
(TEXTNS,u'object-index-entry-template'),
|
||||
(TEXTNS,u'object-index-source'),
|
||||
(TEXTNS,u'sequence-decls'),
|
||||
(TEXTNS,u'table-index-entry-template'),
|
||||
(TEXTNS,u'table-index-source'),
|
||||
(TEXTNS,u'table-of-content-entry-template'),
|
||||
(TEXTNS,u'table-of-content-source'),
|
||||
(TEXTNS,u'user-field-decls'),
|
||||
(TEXTNS,u'user-index-entry-template'),
|
||||
(TEXTNS,u'user-index-source'),
|
||||
(TEXTNS,u'variable-decls'),
|
||||
)
|
||||
|
||||
empty_elements = (
|
||||
(ANIMNS,u'animate'),
|
||||
(ANIMNS,u'animateColor'),
|
||||
(ANIMNS,u'animateMotion'),
|
||||
(ANIMNS,u'animateTransform'),
|
||||
(ANIMNS,u'audio'),
|
||||
(ANIMNS,u'param'),
|
||||
(ANIMNS,u'set'),
|
||||
(ANIMNS,u'transitionFilter'),
|
||||
(CHARTNS,u'categories'),
|
||||
(CHARTNS,u'data-point'),
|
||||
(CHARTNS,u'domain'),
|
||||
(CHARTNS,u'error-indicator'),
|
||||
(CHARTNS,u'floor'),
|
||||
(CHARTNS,u'grid'),
|
||||
(CHARTNS,u'legend'),
|
||||
(CHARTNS,u'mean-value'),
|
||||
(CHARTNS,u'regression-curve'),
|
||||
(CHARTNS,u'stock-gain-marker'),
|
||||
(CHARTNS,u'stock-loss-marker'),
|
||||
(CHARTNS,u'stock-range-line'),
|
||||
(CHARTNS,u'symbol-image'),
|
||||
(CHARTNS,u'wall'),
|
||||
(DR3DNS,u'cube'),
|
||||
(DR3DNS,u'extrude'),
|
||||
(DR3DNS,u'light'),
|
||||
(DR3DNS,u'rotate'),
|
||||
(DR3DNS,u'sphere'),
|
||||
(DRAWNS,u'contour-path'),
|
||||
(DRAWNS,u'contour-polygon'),
|
||||
(DRAWNS,u'equation'),
|
||||
(DRAWNS,u'fill-image'),
|
||||
(DRAWNS,u'floating-frame'),
|
||||
(DRAWNS,u'glue-point'),
|
||||
(DRAWNS,u'gradient'),
|
||||
(DRAWNS,u'handle'),
|
||||
(DRAWNS,u'hatch'),
|
||||
(DRAWNS,u'layer'),
|
||||
(DRAWNS,u'marker'),
|
||||
(DRAWNS,u'opacity'),
|
||||
(DRAWNS,u'page-thumbnail'),
|
||||
(DRAWNS,u'param'),
|
||||
(DRAWNS,u'stroke-dash'),
|
||||
(FORMNS,u'connection-resource'),
|
||||
(FORMNS,u'list-value'),
|
||||
(FORMNS,u'property'),
|
||||
(MANIFESTNS,u'algorithm'),
|
||||
(MANIFESTNS,u'key-derivation'),
|
||||
(METANS,u'auto-reload'),
|
||||
(METANS,u'document-statistic'),
|
||||
(METANS,u'hyperlink-behaviour'),
|
||||
(METANS,u'template'),
|
||||
(NUMBERNS,u'am-pm'),
|
||||
(NUMBERNS,u'boolean'),
|
||||
(NUMBERNS,u'day'),
|
||||
(NUMBERNS,u'day-of-week'),
|
||||
(NUMBERNS,u'era'),
|
||||
(NUMBERNS,u'fraction'),
|
||||
(NUMBERNS,u'hours'),
|
||||
(NUMBERNS,u'minutes'),
|
||||
(NUMBERNS,u'month'),
|
||||
(NUMBERNS,u'quarter'),
|
||||
(NUMBERNS,u'scientific-number'),
|
||||
(NUMBERNS,u'seconds'),
|
||||
(NUMBERNS,u'text-content'),
|
||||
(NUMBERNS,u'week-of-year'),
|
||||
(NUMBERNS,u'year'),
|
||||
(OFFICENS,u'dde-source'),
|
||||
(PRESENTATIONNS,u'date-time'),
|
||||
(PRESENTATIONNS,u'footer'),
|
||||
(PRESENTATIONNS,u'header'),
|
||||
(PRESENTATIONNS,u'placeholder'),
|
||||
(PRESENTATIONNS,u'play'),
|
||||
(PRESENTATIONNS,u'show'),
|
||||
(PRESENTATIONNS,u'sound'),
|
||||
(SCRIPTNS,u'event-listener'),
|
||||
(STYLENS,u'column'),
|
||||
(STYLENS,u'column-sep'),
|
||||
(STYLENS,u'drop-cap'),
|
||||
(STYLENS,u'footnote-sep'),
|
||||
(STYLENS,u'list-level-properties'),
|
||||
(STYLENS,u'map'),
|
||||
(STYLENS,u'ruby-properties'),
|
||||
(STYLENS,u'table-column-properties'),
|
||||
(STYLENS,u'tab-stop'),
|
||||
(STYLENS,u'text-properties'),
|
||||
(SVGNS,u'definition-src'),
|
||||
(SVGNS,u'font-face-format'),
|
||||
(SVGNS,u'font-face-name'),
|
||||
(SVGNS,u'stop'),
|
||||
(TABLENS,u'body'),
|
||||
(TABLENS,u'cell-address'),
|
||||
(TABLENS,u'cell-range-source'),
|
||||
(TABLENS,u'change-deletion'),
|
||||
(TABLENS,u'consolidation'),
|
||||
(TABLENS,u'database-source-query'),
|
||||
(TABLENS,u'database-source-sql'),
|
||||
(TABLENS,u'database-source-table'),
|
||||
(TABLENS,u'data-pilot-display-info'),
|
||||
(TABLENS,u'data-pilot-field-reference'),
|
||||
(TABLENS,u'data-pilot-group-member'),
|
||||
(TABLENS,u'data-pilot-layout-info'),
|
||||
(TABLENS,u'data-pilot-member'),
|
||||
(TABLENS,u'data-pilot-sort-info'),
|
||||
(TABLENS,u'data-pilot-subtotal'),
|
||||
(TABLENS,u'dependency'),
|
||||
(TABLENS,u'error-macro'),
|
||||
(TABLENS,u'even-columns'),
|
||||
(TABLENS,u'even-rows'),
|
||||
(TABLENS,u'filter-condition'),
|
||||
(TABLENS,u'first-column'),
|
||||
(TABLENS,u'first-row'),
|
||||
(TABLENS,u'highlighted-range'),
|
||||
(TABLENS,u'insertion-cut-off'),
|
||||
(TABLENS,u'iteration'),
|
||||
(TABLENS,u'label-range'),
|
||||
(TABLENS,u'last-column'),
|
||||
(TABLENS,u'last-row'),
|
||||
(TABLENS,u'movement-cut-off'),
|
||||
(TABLENS,u'named-expression'),
|
||||
(TABLENS,u'named-range'),
|
||||
(TABLENS,u'null-date'),
|
||||
(TABLENS,u'odd-columns'),
|
||||
(TABLENS,u'odd-rows'),
|
||||
(TABLENS,u'operation'),
|
||||
(TABLENS,u'scenario'),
|
||||
(TABLENS,u'sort-by'),
|
||||
(TABLENS,u'sort-groups'),
|
||||
(TABLENS,u'source-range-address'),
|
||||
(TABLENS,u'source-service'),
|
||||
(TABLENS,u'subtotal-field'),
|
||||
(TABLENS,u'table-column'),
|
||||
(TABLENS,u'table-source'),
|
||||
(TABLENS,u'target-range-address'),
|
||||
(TEXTNS,u'alphabetical-index-auto-mark-file'),
|
||||
(TEXTNS,u'alphabetical-index-mark'),
|
||||
(TEXTNS,u'alphabetical-index-mark-end'),
|
||||
(TEXTNS,u'alphabetical-index-mark-start'),
|
||||
(TEXTNS,u'bookmark'),
|
||||
(TEXTNS,u'bookmark-end'),
|
||||
(TEXTNS,u'bookmark-start'),
|
||||
(TEXTNS,u'change'),
|
||||
(TEXTNS,u'change-end'),
|
||||
(TEXTNS,u'change-start'),
|
||||
(TEXTNS,u'dde-connection-decl'),
|
||||
(TEXTNS,u'index-entry-bibliography'),
|
||||
(TEXTNS,u'index-entry-chapter'),
|
||||
(TEXTNS,u'index-entry-link-end'),
|
||||
(TEXTNS,u'index-entry-link-start'),
|
||||
(TEXTNS,u'index-entry-page-number'),
|
||||
(TEXTNS,u'index-entry-tab-stop'),
|
||||
(TEXTNS,u'index-entry-text'),
|
||||
(TEXTNS,u'index-source-style'),
|
||||
(TEXTNS,u'line-break'),
|
||||
(TEXTNS,u'page'),
|
||||
(TEXTNS,u'reference-mark'),
|
||||
(TEXTNS,u'reference-mark-end'),
|
||||
(TEXTNS,u'reference-mark-start'),
|
||||
(TEXTNS,u's'),
|
||||
(TEXTNS,u'section-source'),
|
||||
(TEXTNS,u'sequence-decl'),
|
||||
(TEXTNS,u'soft-page-break'),
|
||||
(TEXTNS,u'sort-key'),
|
||||
(TEXTNS,u'tab'),
|
||||
(TEXTNS,u'toc-mark'),
|
||||
(TEXTNS,u'toc-mark-end'),
|
||||
(TEXTNS,u'toc-mark-start'),
|
||||
(TEXTNS,u'user-field-decl'),
|
||||
(TEXTNS,u'user-index-mark'),
|
||||
(TEXTNS,u'user-index-mark-end'),
|
||||
(TEXTNS,u'user-index-mark-start'),
|
||||
(TEXTNS,u'variable-decl')
|
||||
)
|
115
src/odf/form.py
Normal file
115
src/odf/form.py
Normal file
@ -0,0 +1,115 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import FORMNS
|
||||
from element import Element
|
||||
|
||||
|
||||
# Autogenerated
|
||||
def Button(**args):
|
||||
return Element(qname = (FORMNS,'button'), **args)
|
||||
|
||||
def Checkbox(**args):
|
||||
return Element(qname = (FORMNS,'checkbox'), **args)
|
||||
|
||||
def Column(**args):
|
||||
return Element(qname = (FORMNS,'column'), **args)
|
||||
|
||||
def Combobox(**args):
|
||||
return Element(qname = (FORMNS,'combobox'), **args)
|
||||
|
||||
def ConnectionResource(**args):
|
||||
return Element(qname = (FORMNS,'connection-resource'), **args)
|
||||
|
||||
def Date(**args):
|
||||
return Element(qname = (FORMNS,'date'), **args)
|
||||
|
||||
def File(**args):
|
||||
return Element(qname = (FORMNS,'file'), **args)
|
||||
|
||||
def FixedText(**args):
|
||||
return Element(qname = (FORMNS,'fixed-text'), **args)
|
||||
|
||||
def Form(**args):
|
||||
return Element(qname = (FORMNS,'form'), **args)
|
||||
|
||||
def FormattedText(**args):
|
||||
return Element(qname = (FORMNS,'formatted-text'), **args)
|
||||
|
||||
def Frame(**args):
|
||||
return Element(qname = (FORMNS,'frame'), **args)
|
||||
|
||||
def GenericControl(**args):
|
||||
return Element(qname = (FORMNS,'generic-control'), **args)
|
||||
|
||||
def Grid(**args):
|
||||
return Element(qname = (FORMNS,'grid'), **args)
|
||||
|
||||
def Hidden(**args):
|
||||
return Element(qname = (FORMNS,'hidden'), **args)
|
||||
|
||||
def Image(**args):
|
||||
return Element(qname = (FORMNS,'image'), **args)
|
||||
|
||||
def ImageFrame(**args):
|
||||
return Element(qname = (FORMNS,'image-frame'), **args)
|
||||
|
||||
def Item(**args):
|
||||
return Element(qname = (FORMNS,'item'), **args)
|
||||
|
||||
def ListProperty(**args):
|
||||
return Element(qname = (FORMNS,'list-property'), **args)
|
||||
|
||||
def ListValue(**args):
|
||||
return Element(qname = (FORMNS,'list-value'), **args)
|
||||
|
||||
def Listbox(**args):
|
||||
return Element(qname = (FORMNS,'listbox'), **args)
|
||||
|
||||
def Number(**args):
|
||||
return Element(qname = (FORMNS,'number'), **args)
|
||||
|
||||
def Option(**args):
|
||||
return Element(qname = (FORMNS,'option'), **args)
|
||||
|
||||
def Password(**args):
|
||||
return Element(qname = (FORMNS,'password'), **args)
|
||||
|
||||
def Properties(**args):
|
||||
return Element(qname = (FORMNS,'properties'), **args)
|
||||
|
||||
def Property(**args):
|
||||
return Element(qname = (FORMNS,'property'), **args)
|
||||
|
||||
def Radio(**args):
|
||||
return Element(qname = (FORMNS,'radio'), **args)
|
||||
|
||||
def Text(**args):
|
||||
return Element(qname = (FORMNS,'text'), **args)
|
||||
|
||||
def Textarea(**args):
|
||||
return Element(qname = (FORMNS,'textarea'), **args)
|
||||
|
||||
def Time(**args):
|
||||
return Element(qname = (FORMNS,'time'), **args)
|
||||
|
||||
def ValueRange(**args):
|
||||
return Element(qname = (FORMNS,'value-range'), **args)
|
||||
|
8150
src/odf/grammar.py
Normal file
8150
src/odf/grammar.py
Normal file
File diff suppressed because it is too large
Load Diff
117
src/odf/load.py
Normal file
117
src/odf/load.py
Normal file
@ -0,0 +1,117 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007-2008 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
# This script is to be embedded in opendocument.py later
|
||||
# The purpose is to read an ODT/ODP/ODS file and create the datastructure
|
||||
# in memory. The user should then be able to make operations and then save
|
||||
# the structure again.
|
||||
|
||||
from xml.sax import make_parser,handler
|
||||
from xml.sax.xmlreader import InputSource
|
||||
import xml.sax.saxutils
|
||||
from element import Element
|
||||
from namespaces import OFFICENS
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
|
||||
|
||||
#
|
||||
# Parse the XML files
|
||||
#
|
||||
class LoadParser(handler.ContentHandler):
|
||||
""" Extract headings from content.xml of an ODT file """
|
||||
triggers = (
|
||||
(OFFICENS, 'automatic-styles'), (OFFICENS, 'body'),
|
||||
(OFFICENS, 'font-face-decls'), (OFFICENS, 'master-styles'),
|
||||
(OFFICENS, 'meta'), (OFFICENS, 'scripts'),
|
||||
(OFFICENS, 'settings'), (OFFICENS, 'styles') )
|
||||
|
||||
def __init__(self, document):
|
||||
self.doc = document
|
||||
self.data = []
|
||||
self.level = 0
|
||||
self.parse = False
|
||||
|
||||
def characters(self, data):
|
||||
if self.parse == False:
|
||||
return
|
||||
self.data.append(data)
|
||||
|
||||
def startElementNS(self, tag, qname, attrs):
|
||||
if tag in self.triggers:
|
||||
self.parse = True
|
||||
if self.doc._parsing != "styles.xml" and tag == (OFFICENS, 'font-face-decls'):
|
||||
self.parse = False
|
||||
if self.parse == False:
|
||||
return
|
||||
|
||||
self.level = self.level + 1
|
||||
# Add any accumulated text content
|
||||
content = ''.join(self.data).strip()
|
||||
if len(content) > 0:
|
||||
self.parent.addText(content)
|
||||
self.data = []
|
||||
# Create the element
|
||||
attrdict = {}
|
||||
for (att,value) in attrs.items():
|
||||
attrdict[att] = value
|
||||
try:
|
||||
e = Element(qname = tag, qattributes=attrdict, check_grammar=False)
|
||||
self.curr = e
|
||||
except AttributeError, v:
|
||||
print "Error: %s" % v
|
||||
|
||||
if tag == (OFFICENS, 'automatic-styles'):
|
||||
e = self.doc.automaticstyles
|
||||
elif tag == (OFFICENS, 'body'):
|
||||
e = self.doc.body
|
||||
elif tag == (OFFICENS, 'master-styles'):
|
||||
e = self.doc.masterstyles
|
||||
elif tag == (OFFICENS, 'meta'):
|
||||
e = self.doc.meta
|
||||
elif tag == (OFFICENS,'scripts'):
|
||||
e = self.doc.scripts
|
||||
elif tag == (OFFICENS,'settings'):
|
||||
e = self.doc.settings
|
||||
elif tag == (OFFICENS,'styles'):
|
||||
e = self.doc.styles
|
||||
elif self.doc._parsing == "styles.xml" and tag == (OFFICENS, 'font-face-decls'):
|
||||
e = self.doc.fontfacedecls
|
||||
elif hasattr(self,'parent'):
|
||||
self.parent.addElement(e, check_grammar=False)
|
||||
self.parent = e
|
||||
|
||||
|
||||
def endElementNS(self, tag, qname):
|
||||
if self.parse == False:
|
||||
return
|
||||
self.level = self.level - 1
|
||||
str = ''.join(self.data)
|
||||
if len(str.strip()) > 0:
|
||||
self.curr.addText(str)
|
||||
self.data = []
|
||||
self.curr = self.curr.parentNode
|
||||
self.parent = self.curr
|
||||
if tag in self.triggers:
|
||||
self.parse = False
|
53
src/odf/manifest.py
Normal file
53
src/odf/manifest.py
Normal file
@ -0,0 +1,53 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
#
|
||||
|
||||
from namespaces import MANIFESTNS
|
||||
from element import Element
|
||||
|
||||
# Autogenerated
|
||||
def Manifest(**args):
|
||||
return Element(qname = (MANIFESTNS,'manifest'), **args)
|
||||
|
||||
def FileEntry(**args):
|
||||
return Element(qname = (MANIFESTNS,'file-entry'), **args)
|
||||
|
||||
def EncryptionData(**args):
|
||||
return Element(qname = (MANIFESTNS,'encryption-data'), **args)
|
||||
|
||||
def Algorithm(**args):
|
||||
return Element(qname = (MANIFESTNS,'algorithm'), **args)
|
||||
|
||||
def KeyDerivation(**args):
|
||||
return Element(qname = (MANIFESTNS,'key-derivation'), **args)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
import cStringIO
|
||||
xml=cStringIO.StringIO()
|
||||
m = Manifest()
|
||||
f = FileEntry(mediatype="text/xml", fullpath="content.xml")
|
||||
m.addElement(f)
|
||||
|
||||
m.toXml(0,xml)
|
||||
print xml.getvalue()
|
||||
|
30
src/odf/math.py
Normal file
30
src/odf/math.py
Normal file
@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import MATHNS
|
||||
from element import Element
|
||||
|
||||
# ODF 1.0 section 12.5
|
||||
# Mathematical content is represented by MathML 2.0
|
||||
|
||||
# Autogenerated
|
||||
def Math(**args):
|
||||
return Element(qname = (MATHNS,'math'), **args)
|
||||
|
66
src/odf/meta.py
Normal file
66
src/odf/meta.py
Normal file
@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import METANS
|
||||
from element import Element
|
||||
|
||||
# Autogenerated
|
||||
def AutoReload(**args):
|
||||
return Element(qname = (METANS,'auto-reload'), **args)
|
||||
|
||||
def CreationDate(**args):
|
||||
return Element(qname = (METANS,'creation-date'), **args)
|
||||
|
||||
def DateString(**args):
|
||||
return Element(qname = (METANS,'date-string'), **args)
|
||||
|
||||
def DocumentStatistic(**args):
|
||||
return Element(qname = (METANS,'document-statistic'), **args)
|
||||
|
||||
def EditingCycles(**args):
|
||||
return Element(qname = (METANS,'editing-cycles'), **args)
|
||||
|
||||
def EditingDuration(**args):
|
||||
return Element(qname = (METANS,'editing-duration'), **args)
|
||||
|
||||
def Generator(**args):
|
||||
return Element(qname = (METANS,'generator'), **args)
|
||||
|
||||
def HyperlinkBehaviour(**args):
|
||||
return Element(qname = (METANS,'hyperlink-behaviour'), **args)
|
||||
|
||||
def InitialCreator(**args):
|
||||
return Element(qname = (METANS,'initial-creator'), **args)
|
||||
|
||||
def Keyword(**args):
|
||||
return Element(qname = (METANS,'keyword'), **args)
|
||||
|
||||
def PrintDate(**args):
|
||||
return Element(qname = (METANS,'print-date'), **args)
|
||||
|
||||
def PrintedBy(**args):
|
||||
return Element(qname = (METANS,'printed-by'), **args)
|
||||
|
||||
def Template(**args):
|
||||
return Element(qname = (METANS,'template'), **args)
|
||||
|
||||
def UserDefined(**args):
|
||||
return Element(qname = (METANS,'user-defined'), **args)
|
||||
|
81
src/odf/namespaces.py
Normal file
81
src/odf/namespaces.py
Normal file
@ -0,0 +1,81 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
TOOLSVERSION = u"ODFPY/0.8.1dev"
|
||||
|
||||
ANIMNS = u"urn:oasis:names:tc:opendocument:xmlns:animation:1.0"
|
||||
CHARTNS = u"urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
|
||||
CONFIGNS = u"urn:oasis:names:tc:opendocument:xmlns:config:1.0"
|
||||
DBNS = u"http://openoffice.org/2004/database"
|
||||
DCNS = u"http://purl.org/dc/elements/1.1/"
|
||||
DOMNS = u"http://www.w3.org/2001/xml-events"
|
||||
DR3DNS = u"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
|
||||
DRAWNS = u"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
|
||||
FONS = u"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
|
||||
FORMNS = u"urn:oasis:names:tc:opendocument:xmlns:form:1.0"
|
||||
KOFFICENS = u"http://www.koffice.org/2005/"
|
||||
MANIFESTNS = u"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"
|
||||
MATHNS = u"http://www.w3.org/1998/Math/MathML"
|
||||
METANS = u"urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
|
||||
NUMBERNS = u"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
|
||||
OFFICENS = u"urn:oasis:names:tc:opendocument:xmlns:office:1.0"
|
||||
OOONS = u"http://openoffice.org/2004/office"
|
||||
OOOWNS = u"http://openoffice.org/2004/writer"
|
||||
OOOCNS = u"http://openoffice.org/2004/calc"
|
||||
PRESENTATIONNS = u"urn:oasis:names:tc:opendocument:xmlns:presentation:1.0"
|
||||
SCRIPTNS = u"urn:oasis:names:tc:opendocument:xmlns:script:1.0"
|
||||
SMILNS = u"urn:oasis:names:tc:opendocument:xmlns:smil-compatible:1.0"
|
||||
STYLENS = u"urn:oasis:names:tc:opendocument:xmlns:style:1.0"
|
||||
SVGNS = u"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
|
||||
TABLENS = u"urn:oasis:names:tc:opendocument:xmlns:table:1.0"
|
||||
TEXTNS = u"urn:oasis:names:tc:opendocument:xmlns:text:1.0"
|
||||
XFORMSNS = u"http://www.w3.org/2002/xforms"
|
||||
XLINKNS = u"http://www.w3.org/1999/xlink"
|
||||
|
||||
|
||||
nsdict = {
|
||||
ANIMNS: u'anim',
|
||||
CHARTNS: u'chart',
|
||||
CONFIGNS: u'config',
|
||||
DBNS: u'db',
|
||||
DCNS: u'dc',
|
||||
DOMNS: u'dom',
|
||||
DR3DNS: u'dr3d',
|
||||
DRAWNS: u'draw',
|
||||
FONS: u'fo',
|
||||
FORMNS: u'form',
|
||||
KOFFICENS: u'koffice',
|
||||
MANIFESTNS: u'manifest',
|
||||
MATHNS: u'math',
|
||||
METANS: u'meta',
|
||||
NUMBERNS: u'number',
|
||||
OFFICENS: u'office',
|
||||
OOONS: u'ooo',
|
||||
OOOWNS: u'ooow',
|
||||
OOOCNS: u'ooc',
|
||||
PRESENTATIONNS: u'presentation',
|
||||
SCRIPTNS: u'script',
|
||||
SMILNS: u'smil',
|
||||
STYLENS: u'style',
|
||||
SVGNS: u'svg',
|
||||
TABLENS: u'table',
|
||||
TEXTNS: u'text',
|
||||
XFORMSNS: u'xforms',
|
||||
XLINKNS: u'xlink',
|
||||
}
|
104
src/odf/number.py
Normal file
104
src/odf/number.py
Normal file
@ -0,0 +1,104 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import NUMBERNS
|
||||
from element import Element
|
||||
from style import StyleElement
|
||||
|
||||
|
||||
# Autogenerated
|
||||
def AmPm(**args):
|
||||
return Element(qname = (NUMBERNS,'am-pm'), **args)
|
||||
|
||||
def Boolean(**args):
|
||||
return Element(qname = (NUMBERNS,'boolean'), **args)
|
||||
|
||||
def BooleanStyle(**args):
|
||||
return StyleElement(qname = (NUMBERNS,'boolean-style'), **args)
|
||||
|
||||
def CurrencyStyle(**args):
|
||||
return StyleElement(qname = (NUMBERNS,'currency-style'), **args)
|
||||
|
||||
def CurrencySymbol(**args):
|
||||
return Element(qname = (NUMBERNS,'currency-symbol'), **args)
|
||||
|
||||
def DateStyle(**args):
|
||||
return StyleElement(qname = (NUMBERNS,'date-style'), **args)
|
||||
|
||||
def Day(**args):
|
||||
return Element(qname = (NUMBERNS,'day'), **args)
|
||||
|
||||
def DayOfWeek(**args):
|
||||
return Element(qname = (NUMBERNS,'day-of-week'), **args)
|
||||
|
||||
def EmbeddedText(**args):
|
||||
return Element(qname = (NUMBERNS,'embedded-text'), **args)
|
||||
|
||||
def Era(**args):
|
||||
return Element(qname = (NUMBERNS,'era'), **args)
|
||||
|
||||
def Fraction(**args):
|
||||
return Element(qname = (NUMBERNS,'fraction'), **args)
|
||||
|
||||
def Hours(**args):
|
||||
return Element(qname = (NUMBERNS,'hours'), **args)
|
||||
|
||||
def Minutes(**args):
|
||||
return Element(qname = (NUMBERNS,'minutes'), **args)
|
||||
|
||||
def Month(**args):
|
||||
return Element(qname = (NUMBERNS,'month'), **args)
|
||||
|
||||
def Number(**args):
|
||||
return Element(qname = (NUMBERNS,'number'), **args)
|
||||
|
||||
def NumberStyle(**args):
|
||||
return StyleElement(qname = (NUMBERNS,'number-style'), **args)
|
||||
|
||||
def PercentageStyle(**args):
|
||||
return StyleElement(qname = (NUMBERNS,'percentage-style'), **args)
|
||||
|
||||
def Quarter(**args):
|
||||
return Element(qname = (NUMBERNS,'quarter'), **args)
|
||||
|
||||
def ScientificNumber(**args):
|
||||
return Element(qname = (NUMBERNS,'scientific-number'), **args)
|
||||
|
||||
def Seconds(**args):
|
||||
return Element(qname = (NUMBERNS,'seconds'), **args)
|
||||
|
||||
def Text(**args):
|
||||
return Element(qname = (NUMBERNS,'text'), **args)
|
||||
|
||||
def TextContent(**args):
|
||||
return Element(qname = (NUMBERNS,'text-content'), **args)
|
||||
|
||||
def TextStyle(**args):
|
||||
return StyleElement(qname = (NUMBERNS,'text-style'), **args)
|
||||
|
||||
def TimeStyle(**args):
|
||||
return StyleElement(qname = (NUMBERNS,'time-style'), **args)
|
||||
|
||||
def WeekOfYear(**args):
|
||||
return Element(qname = (NUMBERNS,'week-of-year'), **args)
|
||||
|
||||
def Year(**args):
|
||||
return Element(qname = (NUMBERNS,'year'), **args)
|
||||
|
579
src/odf/odf2moinmoin.py
Normal file
579
src/odf/odf2moinmoin.py
Normal file
@ -0,0 +1,579 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2008 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# See http://trac.edgewall.org/wiki/WikiFormatting
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
import sys, zipfile, xml.dom.minidom
|
||||
from namespaces import nsdict
|
||||
from elementtypes import *
|
||||
|
||||
IGNORED_TAGS = [
|
||||
'draw:a'
|
||||
'draw:g',
|
||||
'draw:line',
|
||||
'draw:object-ole',
|
||||
'office:annotation',
|
||||
'presentation:notes',
|
||||
'svg:desc',
|
||||
] + [ nsdict[item[0]]+":"+item[1] for item in empty_elements]
|
||||
|
||||
INLINE_TAGS = [ nsdict[item[0]]+":"+item[1] for item in inline_elements]
|
||||
|
||||
|
||||
class TextProps:
|
||||
""" Holds properties for a text style. """
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.italic = False
|
||||
self.bold = False
|
||||
self.fixed = False
|
||||
self.underlined = False
|
||||
self.strikethrough = False
|
||||
self.superscript = False
|
||||
self.subscript = False
|
||||
|
||||
def setItalic(self, value):
|
||||
if value == "italic":
|
||||
self.italic = True
|
||||
elif value == "normal":
|
||||
self.italic = False
|
||||
|
||||
def setBold(self, value):
|
||||
if value == "bold":
|
||||
self.bold = True
|
||||
elif value == "normal":
|
||||
self.bold = False
|
||||
|
||||
def setFixed(self, value):
|
||||
self.fixed = value
|
||||
|
||||
def setUnderlined(self, value):
|
||||
if value and value != "none":
|
||||
self.underlined = True
|
||||
|
||||
def setStrikethrough(self, value):
|
||||
if value and value != "none":
|
||||
self.strikethrough = True
|
||||
|
||||
def setPosition(self, value):
|
||||
if value is None or value == '':
|
||||
return
|
||||
posisize = value.split(' ')
|
||||
textpos = posisize[0]
|
||||
if textpos.find('%') == -1:
|
||||
if textpos == "sub":
|
||||
self.superscript = False
|
||||
self.subscript = True
|
||||
elif textpos == "super":
|
||||
self.superscript = True
|
||||
self.subscript = False
|
||||
else:
|
||||
itextpos = int(textpos[:textpos.find('%')])
|
||||
if itextpos > 10:
|
||||
self.superscript = False
|
||||
self.subscript = True
|
||||
elif itextpos < -10:
|
||||
self.superscript = True
|
||||
self.subscript = False
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return "[italic=%s, bold=i%s, fixed=%s]" % (str(self.italic),
|
||||
str(self.bold),
|
||||
str(self.fixed))
|
||||
|
||||
class ParagraphProps:
|
||||
""" Holds properties of a paragraph style. """
|
||||
|
||||
def __init__(self):
|
||||
|
||||
self.blockquote = False
|
||||
self.headingLevel = 0
|
||||
self.code = False
|
||||
self.title = False
|
||||
self.indented = 0
|
||||
|
||||
def setIndented(self, value):
|
||||
self.indented = value
|
||||
|
||||
def setHeading(self, level):
|
||||
self.headingLevel = level
|
||||
|
||||
def setTitle(self, value):
|
||||
self.title = value
|
||||
|
||||
def setCode(self, value):
|
||||
self.code = value
|
||||
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return "[bq=%s, h=%d, code=%s]" % (str(self.blockquote),
|
||||
self.headingLevel,
|
||||
str(self.code))
|
||||
|
||||
|
||||
class ListProperties:
|
||||
""" Holds properties for a list style. """
|
||||
|
||||
def __init__(self):
|
||||
self.ordered = False
|
||||
|
||||
def setOrdered(self, value):
|
||||
self.ordered = value
|
||||
|
||||
|
||||
|
||||
class ODF2MoinMoin(object):
|
||||
|
||||
|
||||
def __init__(self, filepath):
|
||||
self.footnotes = []
|
||||
self.footnoteCounter = 0
|
||||
self.textStyles = {"Standard": TextProps()}
|
||||
self.paragraphStyles = {"Standard": ParagraphProps()}
|
||||
self.listStyles = {}
|
||||
self.fixedFonts = []
|
||||
self.hasTitle = 0
|
||||
self.lastsegment = None
|
||||
|
||||
# Tags
|
||||
self.elements = {
|
||||
'draw:page': self.textToString,
|
||||
'draw:frame': self.textToString,
|
||||
'draw:image': self.draw_image,
|
||||
'draw:text-box': self.textToString,
|
||||
'text:a': self.text_a,
|
||||
'text:note': self.text_note,
|
||||
}
|
||||
for tag in IGNORED_TAGS:
|
||||
self.elements[tag] = self.do_nothing
|
||||
|
||||
for tag in INLINE_TAGS:
|
||||
self.elements[tag] = self.inline_markup
|
||||
self.elements['text:line-break'] = self.text_line_break
|
||||
self.elements['text:s'] = self.text_s
|
||||
self.elements['text:tab'] = self.text_tab
|
||||
|
||||
self.load(filepath)
|
||||
|
||||
def processFontDeclarations(self, fontDecl):
|
||||
""" Extracts necessary font information from a font-declaration
|
||||
element.
|
||||
"""
|
||||
for fontFace in fontDecl.getElementsByTagName("style:font-face"):
|
||||
if fontFace.getAttribute("style:font-pitch") == "fixed":
|
||||
self.fixedFonts.append(fontFace.getAttribute("style:name"))
|
||||
|
||||
|
||||
|
||||
def extractTextProperties(self, style, parent=None):
|
||||
""" Extracts text properties from a style element. """
|
||||
|
||||
textProps = TextProps()
|
||||
|
||||
if parent:
|
||||
parentProp = self.textStyles.get(parent, None)
|
||||
if parentProp:
|
||||
textProp = parentProp
|
||||
|
||||
textPropEl = style.getElementsByTagName("style:text-properties")
|
||||
if not textPropEl: return textProps
|
||||
|
||||
textPropEl = textPropEl[0]
|
||||
|
||||
textProps.setItalic(textPropEl.getAttribute("fo:font-style"))
|
||||
textProps.setBold(textPropEl.getAttribute("fo:font-weight"))
|
||||
textProps.setUnderlined(textPropEl.getAttribute("style:text-underline-style"))
|
||||
textProps.setStrikethrough(textPropEl.getAttribute("style:text-line-through-style"))
|
||||
textProps.setPosition(textPropEl.getAttribute("style:text-position"))
|
||||
|
||||
if textPropEl.getAttribute("style:font-name") in self.fixedFonts:
|
||||
textProps.setFixed(True)
|
||||
|
||||
return textProps
|
||||
|
||||
def extractParagraphProperties(self, style, parent=None):
|
||||
""" Extracts paragraph properties from a style element. """
|
||||
|
||||
paraProps = ParagraphProps()
|
||||
|
||||
name = style.getAttribute("style:name")
|
||||
|
||||
if name.startswith("Heading_20_"):
|
||||
level = name[11:]
|
||||
try:
|
||||
level = int(level)
|
||||
paraProps.setHeading(level)
|
||||
except:
|
||||
level = 0
|
||||
|
||||
if name == "Title":
|
||||
paraProps.setTitle(True)
|
||||
|
||||
paraPropEl = style.getElementsByTagName("style:paragraph-properties")
|
||||
if paraPropEl:
|
||||
paraPropEl = paraPropEl[0]
|
||||
leftMargin = paraPropEl.getAttribute("fo:margin-left")
|
||||
if leftMargin:
|
||||
try:
|
||||
leftMargin = float(leftMargin[:-2])
|
||||
if leftMargin > 0.01:
|
||||
paraProps.setIndented(True)
|
||||
except:
|
||||
pass
|
||||
|
||||
textProps = self.extractTextProperties(style)
|
||||
if textProps.fixed:
|
||||
paraProps.setCode(True)
|
||||
|
||||
return paraProps
|
||||
|
||||
|
||||
def processStyles(self, styleElements):
|
||||
""" Runs through "style" elements extracting necessary information.
|
||||
"""
|
||||
|
||||
for style in styleElements:
|
||||
|
||||
name = style.getAttribute("style:name")
|
||||
|
||||
if name == "Standard": continue
|
||||
|
||||
family = style.getAttribute("style:family")
|
||||
parent = style.getAttribute("style:parent-style-name")
|
||||
|
||||
if family == "text":
|
||||
self.textStyles[name] = self.extractTextProperties(style, parent)
|
||||
|
||||
elif family == "paragraph":
|
||||
self.paragraphStyles[name] = \
|
||||
self.extractParagraphProperties(style, parent)
|
||||
self.textStyles[name] = self.extractTextProperties(style, parent)
|
||||
|
||||
def processListStyles(self, listStyleElements):
|
||||
|
||||
for style in listStyleElements:
|
||||
name = style.getAttribute("style:name")
|
||||
|
||||
prop = ListProperties()
|
||||
if style.hasChildNodes():
|
||||
subitems = [el for el in style.childNodes
|
||||
if el.nodeType == xml.dom.Node.ELEMENT_NODE
|
||||
and el.tagName == "text:list-level-style-number"]
|
||||
if len(subitems) > 0:
|
||||
prop.setOrdered(True)
|
||||
|
||||
self.listStyles[name] = prop
|
||||
|
||||
|
||||
def load(self, filepath):
|
||||
""" Loads an ODT file. """
|
||||
|
||||
zip = zipfile.ZipFile(filepath)
|
||||
|
||||
styles_doc = xml.dom.minidom.parseString(zip.read("styles.xml"))
|
||||
fontfacedecls = styles_doc.getElementsByTagName("office:font-face-decls")
|
||||
if fontfacedecls:
|
||||
self.processFontDeclarations(fontfacedecls[0])
|
||||
self.processStyles(styles_doc.getElementsByTagName("style:style"))
|
||||
self.processListStyles(styles_doc.getElementsByTagName("text:list-style"))
|
||||
|
||||
self.content = xml.dom.minidom.parseString(zip.read("content.xml"))
|
||||
fontfacedecls = self.content.getElementsByTagName("office:font-face-decls")
|
||||
if fontfacedecls:
|
||||
self.processFontDeclarations(fontfacedecls[0])
|
||||
|
||||
self.processStyles(self.content.getElementsByTagName("style:style"))
|
||||
self.processListStyles(self.content.getElementsByTagName("text:list-style"))
|
||||
|
||||
def compressCodeBlocks(self, text):
|
||||
""" Removes extra blank lines from code blocks. """
|
||||
|
||||
return text
|
||||
lines = text.split("\n")
|
||||
buffer = []
|
||||
numLines = len(lines)
|
||||
for i in range(numLines):
|
||||
|
||||
if (lines[i].strip() or i == numLines-1 or i == 0 or
|
||||
not ( lines[i-1].startswith(" ")
|
||||
and lines[i+1].startswith(" ") ) ):
|
||||
buffer.append("\n" + lines[i])
|
||||
|
||||
return ''.join(buffer)
|
||||
|
||||
#-----------------------------------
|
||||
def do_nothing(self, node):
|
||||
return ''
|
||||
|
||||
def draw_image(self, node):
|
||||
"""
|
||||
"""
|
||||
|
||||
link = node.getAttribute("xlink:href")
|
||||
if link and link[:2] == './': # Indicates a sub-object, which isn't supported
|
||||
return "%s\n" % link
|
||||
if link and link[:9] == 'Pictures/':
|
||||
link = link[9:]
|
||||
return "[[Image(%s)]]\n" % link
|
||||
|
||||
def text_a(self, node):
|
||||
text = self.textToString(node)
|
||||
link = node.getAttribute("xlink:href")
|
||||
if link.strip() == text.strip():
|
||||
return "[%s] " % link.strip()
|
||||
else:
|
||||
return "[%s %s] " % (link.strip(), text.strip())
|
||||
|
||||
|
||||
def text_line_break(self, node):
|
||||
return "[[BR]]"
|
||||
|
||||
def text_note(self, node):
|
||||
cite = (node.getElementsByTagName("text:note-citation")[0]
|
||||
.childNodes[0].nodeValue)
|
||||
body = (node.getElementsByTagName("text:note-body")[0]
|
||||
.childNodes[0])
|
||||
self.footnotes.append((cite, self.textToString(body)))
|
||||
return "^%s^" % cite
|
||||
|
||||
def text_s(self, node):
|
||||
try:
|
||||
num = int(node.getAttribute("text:c"))
|
||||
return " "*num
|
||||
except:
|
||||
return " "
|
||||
|
||||
def text_tab(self, node):
|
||||
return " "
|
||||
|
||||
def inline_markup(self, node):
|
||||
text = self.textToString(node)
|
||||
|
||||
if not text.strip():
|
||||
return '' # don't apply styles to white space
|
||||
|
||||
styleName = node.getAttribute("text:style-name")
|
||||
style = self.textStyles.get(styleName, TextProps())
|
||||
|
||||
if style.fixed:
|
||||
return "`" + text + "`"
|
||||
|
||||
mark = []
|
||||
if style:
|
||||
if style.italic:
|
||||
mark.append("''")
|
||||
if style.bold:
|
||||
mark.append("'''")
|
||||
if style.underlined:
|
||||
mark.append("__")
|
||||
if style.strikethrough:
|
||||
mark.append("~~")
|
||||
if style.superscript:
|
||||
mark.append("^")
|
||||
if style.subscript:
|
||||
mark.append(",,")
|
||||
revmark = mark[:]
|
||||
revmark.reverse()
|
||||
return "%s%s%s" % (''.join(mark), text, ''.join(revmark))
|
||||
|
||||
#-----------------------------------
|
||||
def listToString(self, listElement, indent = 0):
|
||||
|
||||
self.lastsegment = listElement.tagName
|
||||
buffer = []
|
||||
|
||||
styleName = listElement.getAttribute("text:style-name")
|
||||
props = self.listStyles.get(styleName, ListProperties())
|
||||
|
||||
i = 0
|
||||
for item in listElement.childNodes:
|
||||
buffer.append(" "*indent)
|
||||
i += 1
|
||||
if props.ordered:
|
||||
number = str(i)
|
||||
number = " " + number + ". "
|
||||
buffer.append(" 1. ")
|
||||
else:
|
||||
buffer.append(" * ")
|
||||
subitems = [el for el in item.childNodes
|
||||
if el.tagName in ["text:p", "text:h", "text:list"]]
|
||||
for subitem in subitems:
|
||||
if subitem.tagName == "text:list":
|
||||
buffer.append("\n")
|
||||
buffer.append(self.listToString(subitem, indent+3))
|
||||
else:
|
||||
buffer.append(self.paragraphToString(subitem, indent+3))
|
||||
self.lastsegment = subitem.tagName
|
||||
self.lastsegment = item.tagName
|
||||
buffer.append("\n")
|
||||
|
||||
return ''.join(buffer)
|
||||
|
||||
def tableToString(self, tableElement):
|
||||
""" MoinMoin uses || to delimit table cells
|
||||
"""
|
||||
|
||||
self.lastsegment = tableElement.tagName
|
||||
buffer = []
|
||||
|
||||
for item in tableElement.childNodes:
|
||||
self.lastsegment = item.tagName
|
||||
if item.tagName == "table:table-header-rows":
|
||||
buffer.append(self.tableToString(item))
|
||||
if item.tagName == "table:table-row":
|
||||
buffer.append("\n||")
|
||||
for cell in item.childNodes:
|
||||
buffer.append(self.inline_markup(cell))
|
||||
buffer.append("||")
|
||||
self.lastsegment = cell.tagName
|
||||
return ''.join(buffer)
|
||||
|
||||
|
||||
def toString(self):
|
||||
""" Converts the document to a string.
|
||||
FIXME: Result from second call differs from first call
|
||||
"""
|
||||
body = self.content.getElementsByTagName("office:body")[0]
|
||||
text = body.childNodes[0]
|
||||
|
||||
buffer = []
|
||||
|
||||
paragraphs = [el for el in text.childNodes
|
||||
if el.tagName in ["draw:page", "text:p", "text:h","text:section",
|
||||
"text:list", "table:table"]]
|
||||
|
||||
for paragraph in paragraphs:
|
||||
if paragraph.tagName == "text:list":
|
||||
text = self.listToString(paragraph)
|
||||
elif paragraph.tagName == "text:section":
|
||||
text = self.textToString(paragraph)
|
||||
elif paragraph.tagName == "table:table":
|
||||
text = self.tableToString(paragraph)
|
||||
else:
|
||||
text = self.paragraphToString(paragraph)
|
||||
if text:
|
||||
buffer.append(text)
|
||||
|
||||
if self.footnotes:
|
||||
|
||||
buffer.append("----")
|
||||
for cite, body in self.footnotes:
|
||||
buffer.append("%s: %s" % (cite, body))
|
||||
|
||||
|
||||
buffer.append("")
|
||||
return self.compressCodeBlocks('\n'.join(buffer))
|
||||
|
||||
|
||||
def textToString(self, element):
|
||||
|
||||
buffer = []
|
||||
|
||||
for node in element.childNodes:
|
||||
|
||||
if node.nodeType == xml.dom.Node.TEXT_NODE:
|
||||
buffer.append(node.nodeValue)
|
||||
|
||||
elif node.nodeType == xml.dom.Node.ELEMENT_NODE:
|
||||
tag = node.tagName
|
||||
|
||||
if tag in ("draw:text-box", "draw:frame"):
|
||||
buffer.append(self.textToString(node))
|
||||
|
||||
elif tag in ("text:p", "text:h"):
|
||||
text = self.paragraphToString(node)
|
||||
if text:
|
||||
buffer.append(text)
|
||||
elif tag == "text:list":
|
||||
buffer.append(self.listToString(node))
|
||||
else:
|
||||
method = self.elements.get(tag)
|
||||
if method:
|
||||
buffer.append(method(node))
|
||||
else:
|
||||
buffer.append(" {" + tag + "} ")
|
||||
|
||||
return ''.join(buffer)
|
||||
|
||||
def paragraphToString(self, paragraph, indent = 0):
|
||||
|
||||
dummyParaProps = ParagraphProps()
|
||||
|
||||
style_name = paragraph.getAttribute("text:style-name")
|
||||
paraProps = self.paragraphStyles.get(style_name, dummyParaProps)
|
||||
text = self.inline_markup(paragraph)
|
||||
|
||||
if paraProps and not paraProps.code:
|
||||
text = text.strip()
|
||||
|
||||
if paragraph.tagName == "text:p" and self.lastsegment == "text:p":
|
||||
text = "\n" + text
|
||||
|
||||
self.lastsegment = paragraph.tagName
|
||||
|
||||
if paraProps.title:
|
||||
self.hasTitle = 1
|
||||
return "= " + text + " =\n"
|
||||
|
||||
outlinelevel = paragraph.getAttribute("text:outline-level")
|
||||
if outlinelevel:
|
||||
|
||||
level = int(outlinelevel)
|
||||
if self.hasTitle: level += 1
|
||||
|
||||
if level >= 1:
|
||||
return "=" * level + " " + text + " " + "=" * level + "\n"
|
||||
|
||||
elif paraProps.code:
|
||||
return "{{{\n" + text + "\n}}}\n"
|
||||
|
||||
if paraProps.indented:
|
||||
return self.wrapParagraph(text, indent = indent, blockquote = True)
|
||||
|
||||
else:
|
||||
return self.wrapParagraph(text, indent = indent)
|
||||
|
||||
|
||||
def wrapParagraph(self, text, indent = 0, blockquote=False):
|
||||
|
||||
counter = 0
|
||||
buffer = []
|
||||
LIMIT = 50
|
||||
|
||||
if blockquote:
|
||||
buffer.append(" ")
|
||||
|
||||
return ''.join(buffer) + text
|
||||
# Unused from here
|
||||
for token in text.split():
|
||||
|
||||
if counter > LIMIT - indent:
|
||||
buffer.append("\n" + " "*indent)
|
||||
if blockquote:
|
||||
buffer.append(" ")
|
||||
counter = 0
|
||||
|
||||
buffer.append(token + " ")
|
||||
counter += len(token)
|
||||
|
||||
return ''.join(buffer)
|
1264
src/odf/odf2xhtml.py
Normal file
1264
src/odf/odf2xhtml.py
Normal file
File diff suppressed because it is too large
Load Diff
120
src/odf/odfmanifest.py
Normal file
120
src/odf/odfmanifest.py
Normal file
@ -0,0 +1,120 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
# This script lists the content of the manifest.xml file
|
||||
import zipfile
|
||||
from xml.sax import make_parser,handler
|
||||
from xml.sax.xmlreader import InputSource
|
||||
import xml.sax.saxutils
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
|
||||
|
||||
MANIFESTNS="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# ODFMANIFESTHANDLER
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
class ODFManifestHandler(handler.ContentHandler):
|
||||
""" The ODFManifestHandler parses a manifest file and produces a list of
|
||||
content """
|
||||
|
||||
def __init__(self):
|
||||
self.manifest = {}
|
||||
|
||||
# Tags
|
||||
# FIXME: Also handle encryption data
|
||||
self.elements = {
|
||||
(MANIFESTNS, 'file-entry'): (self.s_file_entry, self.donothing),
|
||||
}
|
||||
|
||||
def handle_starttag(self, tag, method, attrs):
|
||||
method(tag,attrs)
|
||||
|
||||
def handle_endtag(self, tag, method):
|
||||
method(tag)
|
||||
|
||||
def startElementNS(self, tag, qname, attrs):
|
||||
method = self.elements.get(tag, (None, None))[0]
|
||||
if method:
|
||||
self.handle_starttag(tag, method, attrs)
|
||||
else:
|
||||
self.unknown_starttag(tag,attrs)
|
||||
|
||||
def endElementNS(self, tag, qname):
|
||||
method = self.elements.get(tag, (None, None))[1]
|
||||
if method:
|
||||
self.handle_endtag(tag, method)
|
||||
else:
|
||||
self.unknown_endtag(tag)
|
||||
|
||||
def unknown_starttag(self, tag, attrs):
|
||||
pass
|
||||
|
||||
def unknown_endtag(self, tag):
|
||||
pass
|
||||
|
||||
def donothing(self, tag, attrs=None):
|
||||
pass
|
||||
|
||||
def s_file_entry(self, tag, attrs):
|
||||
m = attrs.get((MANIFESTNS, 'media-type'),"application/octet-stream")
|
||||
p = attrs.get((MANIFESTNS, 'full-path'))
|
||||
self.manifest[p] = { 'media-type':m, 'full-path':p }
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
# Reading the file
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
|
||||
def manifestlist(manifestxml):
|
||||
odhandler = ODFManifestHandler()
|
||||
parser = make_parser()
|
||||
parser.setFeature(handler.feature_namespaces, 1)
|
||||
parser.setContentHandler(odhandler)
|
||||
parser.setErrorHandler(handler.ErrorHandler())
|
||||
|
||||
inpsrc = InputSource()
|
||||
inpsrc.setByteStream(StringIO(manifestxml))
|
||||
parser.parse(inpsrc)
|
||||
|
||||
return odhandler.manifest
|
||||
|
||||
def odfmanifest(odtfile):
|
||||
z = zipfile.ZipFile(odtfile)
|
||||
manifest = z.read('META-INF/manifest.xml')
|
||||
z.close()
|
||||
return manifestlist(manifest)
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
result = odfmanifest(sys.argv[1])
|
||||
for file in result.values():
|
||||
print "%-40s %-40s" % (file['media-type'], file['full-path'])
|
||||
|
104
src/odf/office.py
Normal file
104
src/odf/office.py
Normal file
@ -0,0 +1,104 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import OFFICENS
|
||||
from element import Element
|
||||
from draw import StyleRefElement
|
||||
|
||||
# Autogenerated
|
||||
def Annotation(**args):
|
||||
return StyleRefElement(qname = (OFFICENS,'annotation'), **args)
|
||||
|
||||
def AutomaticStyles(**args):
|
||||
return Element(qname = (OFFICENS, 'automatic-styles'), **args)
|
||||
|
||||
def BinaryData(**args):
|
||||
return Element(qname = (OFFICENS,'binary-data'), **args)
|
||||
|
||||
def Body(**args):
|
||||
return Element(qname = (OFFICENS, 'body'), **args)
|
||||
|
||||
def ChangeInfo(**args):
|
||||
return Element(qname = (OFFICENS,'change-info'), **args)
|
||||
|
||||
def Chart(**args):
|
||||
return Element(qname = (OFFICENS,'chart'), **args)
|
||||
|
||||
def DdeSource(**args):
|
||||
return Element(qname = (OFFICENS,'dde-source'), **args)
|
||||
|
||||
def Document(version="1.0", **args):
|
||||
return Element(qname = (OFFICENS,'document'), version=version, **args)
|
||||
|
||||
def DocumentContent(version="1.0", **args):
|
||||
return Element(qname = (OFFICENS, 'document-content'), version=version, **args)
|
||||
|
||||
def DocumentMeta(version="1.0", **args):
|
||||
return Element(qname = (OFFICENS, 'document-meta'), version=version, **args)
|
||||
|
||||
def DocumentSettings(version="1.0", **args):
|
||||
return Element(qname = (OFFICENS, 'document-settings'), version=version, **args)
|
||||
|
||||
def DocumentStyles(version="1.0", **args):
|
||||
return Element(qname = (OFFICENS, 'document-styles'), version=version, **args)
|
||||
|
||||
def Drawing(**args):
|
||||
return Element(qname = (OFFICENS,'drawing'), **args)
|
||||
|
||||
def EventListeners(**args):
|
||||
return Element(qname = (OFFICENS,'event-listeners'), **args)
|
||||
|
||||
def FontFaceDecls(**args):
|
||||
return Element(qname = (OFFICENS, 'font-face-decls'), **args)
|
||||
|
||||
def Forms(**args):
|
||||
return Element(qname = (OFFICENS,'forms'), **args)
|
||||
|
||||
def Image(**args):
|
||||
return Element(qname = (OFFICENS,'image'), **args)
|
||||
|
||||
def MasterStyles(**args):
|
||||
return Element(qname = (OFFICENS, 'master-styles'), **args)
|
||||
|
||||
def Meta(**args):
|
||||
return Element(qname = (OFFICENS, 'meta'), **args)
|
||||
|
||||
def Presentation(**args):
|
||||
return Element(qname = (OFFICENS,'presentation'), **args)
|
||||
|
||||
def Script(**args):
|
||||
return Element(qname = (OFFICENS, 'script'), **args)
|
||||
|
||||
def Scripts(**args):
|
||||
return Element(qname = (OFFICENS, 'scripts'), **args)
|
||||
|
||||
def Settings(**args):
|
||||
return Element(qname = (OFFICENS, 'settings'), **args)
|
||||
|
||||
def Spreadsheet(**args):
|
||||
return Element(qname = (OFFICENS, 'spreadsheet'), **args)
|
||||
|
||||
def Styles(**args):
|
||||
return Element(qname = (OFFICENS, 'styles'), **args)
|
||||
|
||||
def Text(**args):
|
||||
return Element(qname = (OFFICENS, 'text'), **args)
|
||||
|
||||
# Autogenerated end
|
71
src/odf/ooostyles.py
Normal file
71
src/odf/ooostyles.py
Normal file
@ -0,0 +1,71 @@
|
||||
from style import Style, ParagraphProperties, TextProperties
|
||||
|
||||
def addOOoStandardStyles(styles):
|
||||
style = Style(name="Standard", family="paragraph", attributes={'class':"text"})
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Text_20_body", displayname="Text body", family="paragraph", parentstylename="Standard", attributes={'class':"text"})
|
||||
p = ParagraphProperties(margintop="0cm", marginbottom="0.212cm")
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Text_20_body_20_indent", displayname="Text body indent", family="paragraph", parentstylename="Text_20_body", attributes={'class':"text"})
|
||||
p = ParagraphProperties(marginleft="0.499cm", marginright="0cm", textindent="0cm", autotextindent="false")
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Salutation", family="paragraph", parentstylename="Standard", attributes={'class':"text"})
|
||||
p = ParagraphProperties(numberlines="false", linenumber=0)
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Signature", family="paragraph", parentstylename="Standard", attributes={'class':"text"})
|
||||
p = ParagraphProperties(numberlines="false", linenumber=0)
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Heading", family="paragraph", parentstylename="Standard", nextstylename="Text_20_body", attributes={'class':"text"})
|
||||
p = ParagraphProperties(margintop="0.423cm", marginbottom="0.212cm", keepwithnext="always")
|
||||
style.addElement(p)
|
||||
p = TextProperties(fontname="Nimbus Sans L", fontsize="14pt", fontnameasian="DejaVu LGC Sans", fontsizeasian="14pt", fontnamecomplex="DejaVu LGC Sans", fontsizecomplex="14pt")
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Heading_20_1", displayname="Heading 1", family="paragraph", parentstylename="Heading", nextstylename="Text_20_body", attributes={'class':"text"}, defaultoutlinelevel=1)
|
||||
p = TextProperties(fontsize="115%", fontweight="bold", fontsizeasian="115%", fontweightasian="bold", fontsizecomplex="115%", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Heading_20_2", displayname="Heading 2", family="paragraph", parentstylename="Heading", nextstylename="Text_20_body", attributes={'class':"text"}, defaultoutlinelevel=2)
|
||||
p = TextProperties(fontsize="14pt", fontstyle="italic", fontweight="bold", fontsizeasian="14pt", fontstyleasian="italic", fontweightasian="bold", fontsizecomplex="14pt", fontstylecomplex="italic", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Heading_20_3", displayname="Heading 3", family="paragraph", parentstylename="Heading", nextstylename="Text_20_body", attributes={'class':"text"}, defaultoutlinelevel=3)
|
||||
p = TextProperties(fontsize="14pt", fontweight="bold", fontsizeasian="14pt", fontweightasian="bold", fontsizecomplex="14pt", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="List", family="paragraph", parentstylename="Text_20_body", attributes={'class':"list"})
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Caption", family="paragraph", parentstylename="Standard", attributes={'class':"extra"})
|
||||
p = ParagraphProperties(margintop="0.212cm", marginbottom="0.212cm", numberlines="false", linenumber="0")
|
||||
style.addElement(p)
|
||||
p = TextProperties(fontsize="12pt", fontstyle="italic", fontsizeasian="12pt", fontstyleasian="italic", fontsizecomplex="12pt", fontstylecomplex="italic")
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Index", family="paragraph", parentstylename="Standard", attributes={'class':"index"})
|
||||
p = ParagraphProperties(numberlines="false", linenumber=0)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Source_20_Text", displayname="Source Text", family="text")
|
||||
p = TextProperties(fontname="Courier", fontnameasian="Courier", fontnamecomplex="Courier")
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
||||
|
||||
style = Style(name="Variable", family="text")
|
||||
p = TextProperties(fontstyle="italic", fontstyleasian="italic", fontstylecomplex="italic")
|
||||
style.addElement(p)
|
||||
styles.addElement(style)
|
558
src/odf/opendocument.py
Normal file
558
src/odf/opendocument.py
Normal file
@ -0,0 +1,558 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2008 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
__doc__="""Use OpenDocument to generate your documents."""
|
||||
|
||||
import zipfile, time, sys, mimetypes, copy
|
||||
from cStringIO import StringIO
|
||||
from namespaces import *
|
||||
import manifest, meta
|
||||
from office import *
|
||||
import element
|
||||
from attrconverters import make_NCName
|
||||
from xml.sax.xmlreader import InputSource
|
||||
from odfmanifest import manifestlist
|
||||
|
||||
__version__= TOOLSVERSION
|
||||
|
||||
_XMLPROLOGUE = u"<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
|
||||
UNIXPERMS = 0100644 << 16L # -rw-r--r--
|
||||
|
||||
IS_FILENAME = 0
|
||||
IS_IMAGE = 1
|
||||
# We need at least Python 2.2
|
||||
assert sys.version_info[0]>=2 and sys.version_info[1] >= 2
|
||||
|
||||
sys.setrecursionlimit=50
|
||||
#The recursion limit is set conservative so mistakes like
|
||||
# s=content() s.addElement(s) won't eat up too much processor time.
|
||||
|
||||
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',
|
||||
}
|
||||
|
||||
class OpenDocument:
|
||||
""" A class to hold the content of an OpenDocument document
|
||||
Use the xml method to write the XML
|
||||
source to the screen or to a file
|
||||
d = OpenDocument(mimetype)
|
||||
fd.write(d.xml())
|
||||
"""
|
||||
thumbnail = None
|
||||
|
||||
def __init__(self, mimetype, add_generator=True):
|
||||
self.mimetype = mimetype
|
||||
self.childobjects = []
|
||||
self.folder = "" # Always empty for toplevel documents
|
||||
self.topnode = Document(mimetype=self.mimetype)
|
||||
self.topnode.ownerDocument = self
|
||||
|
||||
self.clear_caches()
|
||||
|
||||
self.Pictures = {}
|
||||
self.meta = Meta()
|
||||
self.topnode.addElement(self.meta)
|
||||
if add_generator:
|
||||
self.meta.addElement(meta.Generator(text=TOOLSVERSION))
|
||||
self.scripts = Scripts()
|
||||
self.topnode.addElement(self.scripts)
|
||||
self.fontfacedecls = FontFaceDecls()
|
||||
self.topnode.addElement(self.fontfacedecls)
|
||||
self.settings = Settings()
|
||||
self.topnode.addElement(self.settings)
|
||||
self.styles = Styles()
|
||||
self.topnode.addElement(self.styles)
|
||||
self.automaticstyles = AutomaticStyles()
|
||||
self.topnode.addElement(self.automaticstyles)
|
||||
self.masterstyles = MasterStyles()
|
||||
self.topnode.addElement(self.masterstyles)
|
||||
self.body = Body()
|
||||
self.topnode.addElement(self.body)
|
||||
|
||||
def rebuild_caches(self, node=None):
|
||||
if node is None: node = self.topnode
|
||||
self.build_caches(node)
|
||||
for e in node.childNodes:
|
||||
if e.nodeType == element.Node.ELEMENT_NODE:
|
||||
self.rebuild_caches(e)
|
||||
|
||||
def clear_caches(self):
|
||||
self.element_dict = {}
|
||||
self._styles_dict = {}
|
||||
self._styles_ooo_fix = {}
|
||||
|
||||
def build_caches(self, element):
|
||||
""" Called from element.py
|
||||
"""
|
||||
if not self.element_dict.has_key(element.qname):
|
||||
self.element_dict[element.qname] = []
|
||||
self.element_dict[element.qname].append(element)
|
||||
if element.qname == (STYLENS, u'style'):
|
||||
self._register_stylename(element) # Add to style dictionary
|
||||
styleref = element.getAttrNS(TEXTNS,u'style-name')
|
||||
if styleref is not None and self._styles_ooo_fix.has_key(styleref):
|
||||
element.setAttrNS(TEXTNS,u'style-name', self._styles_ooo_fix[styleref])
|
||||
|
||||
def _register_stylename(self, element):
|
||||
''' Register a style. But there are three style dictionaries:
|
||||
office:styles, office:automatic-styles and office:master-styles
|
||||
Chapter 14
|
||||
'''
|
||||
name = element.getAttrNS(STYLENS, u'name')
|
||||
if name is None:
|
||||
return
|
||||
if element.parentNode.qname in ((OFFICENS,u'styles'), (OFFICENS,u'automatic-styles')):
|
||||
if self._styles_dict.has_key(name):
|
||||
newname = 'M'+name # Rename style
|
||||
self._styles_ooo_fix[name] = newname
|
||||
# From here on all references to the old name will refer to the new one
|
||||
name = newname
|
||||
element.setAttrNS(STYLENS, u'name', name)
|
||||
self._styles_dict[name] = element
|
||||
|
||||
def toXml(self, filename=''):
|
||||
xml=StringIO()
|
||||
xml.write(_XMLPROLOGUE)
|
||||
self.body.toXml(0, xml)
|
||||
if not filename:
|
||||
return xml.getvalue()
|
||||
else:
|
||||
f=file(filename,'w')
|
||||
f.write(xml.getvalue())
|
||||
f.close()
|
||||
|
||||
def xml(self):
|
||||
""" Generates the full document as an XML file
|
||||
Always written as a bytestream in UTF-8 encoding
|
||||
"""
|
||||
self._replaceGenerator()
|
||||
xml=StringIO()
|
||||
xml.write(_XMLPROLOGUE)
|
||||
self.topnode.toXml(0, xml)
|
||||
return xml.getvalue()
|
||||
|
||||
|
||||
def contentxml(self):
|
||||
""" Generates the content.xml file
|
||||
Always written as a bytestream in UTF-8 encoding
|
||||
"""
|
||||
xml=StringIO()
|
||||
xml.write(_XMLPROLOGUE)
|
||||
x = DocumentContent()
|
||||
x.write_open_tag(0, xml)
|
||||
if self.scripts.hasChildNodes():
|
||||
self.scripts.toXml(1, xml)
|
||||
if self.fontfacedecls.hasChildNodes():
|
||||
self.fontfacedecls.toXml(1, xml)
|
||||
a = AutomaticStyles()
|
||||
stylelist = self._used_auto_styles([self.styles, self.body])
|
||||
if len(stylelist) > 0:
|
||||
a.write_open_tag(1, xml)
|
||||
for s in stylelist:
|
||||
s.toXml(2, xml)
|
||||
a.write_close_tag(1, xml)
|
||||
else:
|
||||
a.toXml(1, xml)
|
||||
self.body.toXml(1, xml)
|
||||
x.write_close_tag(0, xml)
|
||||
return xml.getvalue()
|
||||
|
||||
def manifestxml(self):
|
||||
""" Generates the manifest.xml file """
|
||||
xml=StringIO()
|
||||
xml.write(_XMLPROLOGUE)
|
||||
self.manifest.toXml(0,xml)
|
||||
return xml.getvalue()
|
||||
|
||||
def metaxml(self):
|
||||
""" Generates the meta.xml file """
|
||||
self._replaceGenerator()
|
||||
x = DocumentMeta()
|
||||
x.addElement(self.meta)
|
||||
xml=StringIO()
|
||||
xml.write(_XMLPROLOGUE)
|
||||
x.toXml(0,xml)
|
||||
return xml.getvalue()
|
||||
|
||||
def settingsxml(self):
|
||||
""" Generates the settings.xml file """
|
||||
x = DocumentSettings()
|
||||
x.addElement(self.settings)
|
||||
xml=StringIO()
|
||||
xml.write(_XMLPROLOGUE)
|
||||
x.toXml(0,xml)
|
||||
return xml.getvalue()
|
||||
|
||||
def _parseoneelement(self, top, stylenamelist):
|
||||
""" Finds references to style objects in master-styles
|
||||
and add the style name to the style list if not already there.
|
||||
Recursive
|
||||
"""
|
||||
for e in top.childNodes:
|
||||
if e.nodeType == element.Node.ELEMENT_NODE:
|
||||
for styleref in ( (DRAWNS,u'style-name'),
|
||||
(DRAWNS,u'text-style-name'),
|
||||
(PRESENTATIONNS,u'style-name'),
|
||||
(STYLENS,u'style-name'),
|
||||
(STYLENS,u'list-style-name'),
|
||||
(STYLENS,u'page-layout-name'),
|
||||
(TABLENS,u'style-name'),
|
||||
(TEXTNS,u'style-name') ):
|
||||
if e.getAttrNS(styleref[0],styleref[1]):
|
||||
stylename = e.getAttrNS(styleref[0],styleref[1])
|
||||
if stylename not in stylenamelist:
|
||||
stylenamelist.append(stylename)
|
||||
stylenamelist = self._parseoneelement(e, stylenamelist)
|
||||
return stylenamelist
|
||||
|
||||
def _used_auto_styles(self, segments):
|
||||
""" Loop through the masterstyles elements, and find the automatic
|
||||
styles that are used. These will be added to the automatic-styles
|
||||
element in styles.xml
|
||||
"""
|
||||
stylenamelist = []
|
||||
for top in segments:
|
||||
stylenamelist = self._parseoneelement(top, stylenamelist)
|
||||
stylelist = []
|
||||
for e in self.automaticstyles.childNodes:
|
||||
if e.getAttrNS(STYLENS,u'name') in stylenamelist:
|
||||
stylelist.append(e)
|
||||
return stylelist
|
||||
|
||||
def stylesxml(self):
|
||||
""" Generates the styles.xml file """
|
||||
xml=StringIO()
|
||||
xml.write(_XMLPROLOGUE)
|
||||
x = DocumentStyles()
|
||||
x.write_open_tag(0, xml)
|
||||
if self.fontfacedecls.hasChildNodes():
|
||||
self.fontfacedecls.toXml(1, xml)
|
||||
self.styles.toXml(1, xml)
|
||||
a = AutomaticStyles()
|
||||
a.write_open_tag(1, xml)
|
||||
for s in self._used_auto_styles([self.masterstyles]):
|
||||
s.toXml(2, xml)
|
||||
a.write_close_tag(1, xml)
|
||||
if self.masterstyles.hasChildNodes():
|
||||
self.masterstyles.toXml(1, xml)
|
||||
x.write_close_tag(0, xml)
|
||||
return xml.getvalue()
|
||||
|
||||
def addPicture(self, filename, mediatype=None, content=None):
|
||||
""" Add a picture
|
||||
It uses the same convention as OOo, in that it saves the picture in
|
||||
the zipfile in the subdirectory 'Pictures'
|
||||
If passed a file ptr, mediatype must be set
|
||||
"""
|
||||
if content is None:
|
||||
if mediatype is None:
|
||||
mediatype, encoding = mimetypes.guess_type(filename)
|
||||
if mediatype is None:
|
||||
mediatype = ''
|
||||
try: ext = filename[filename.rindex('.'):]
|
||||
except: ext=''
|
||||
else:
|
||||
ext = mimetypes.guess_extension(mediatype)
|
||||
manifestfn = "Pictures/%0.0f%s" % ((time.time()*10000000000), ext)
|
||||
self.Pictures[manifestfn] = (IS_FILENAME, fileobj, mediatype)
|
||||
else:
|
||||
manifestfn = filename
|
||||
self.Pictures[manifestfn] = (IS_IMAGE, content, mediatype)
|
||||
return manifestfn
|
||||
|
||||
def addThumbnail(self, filecontent=None):
|
||||
""" Add a fixed thumbnail
|
||||
The thumbnail in the library is big, so this is pretty useless.
|
||||
"""
|
||||
if filecontent is None:
|
||||
import thumbnail
|
||||
self.thumbnail = thumbnail.thumbnail()
|
||||
else:
|
||||
self.thumbnail = filecontent
|
||||
|
||||
def addObject(self, document):
|
||||
""" Add an object. The object must be an OpenDocument class
|
||||
The return value will be the folder in the zipfile the object is stored in
|
||||
"""
|
||||
self.childobjects.append(document)
|
||||
document.folder = "%s/Object %d" % (self.folder, len(self.childobjects))
|
||||
return ".%s" % document.folder
|
||||
|
||||
def _savePictures(self, object, folder):
|
||||
hasPictures = False
|
||||
for arcname, picturerec in object.Pictures.items():
|
||||
what_it_is, fileobj, mediatype = picturerec
|
||||
self.manifest.addElement(manifest.FileEntry(fullpath="%s%s" % ( folder ,arcname), mediatype=mediatype))
|
||||
hasPictures = True
|
||||
if what_it_is == IS_FILENAME:
|
||||
self._z.write(fileobj, arcname, zipfile.ZIP_STORED)
|
||||
else:
|
||||
zi = zipfile.ZipInfo(str(arcname), self._now)
|
||||
zi.compress_type = zipfile.ZIP_STORED
|
||||
zi.external_attr = UNIXPERMS
|
||||
self._z.writestr(zi, fileobj)
|
||||
if hasPictures:
|
||||
self.manifest.addElement(manifest.FileEntry(fullpath="%sPictures/" % folder,mediatype=""))
|
||||
# Look in subobjects
|
||||
subobjectnum = 1
|
||||
for subobject in object.childobjects:
|
||||
self._savePictures(subobject,'%sObject %d/' % (folder, subobjectnum))
|
||||
subobjectnum += 1
|
||||
|
||||
def _replaceGenerator(self):
|
||||
""" Section 3.1.1: The application MUST NOT export the original identifier
|
||||
belonging to the application that created the document.
|
||||
"""
|
||||
for m in self.meta.childNodes[:]:
|
||||
if m.qname == (METANS, u'generator'):
|
||||
self.meta.removeChild(m)
|
||||
self.meta.addElement(meta.Generator(text=TOOLSVERSION))
|
||||
|
||||
def save(self, outputfile, addsuffix=False):
|
||||
""" Save the document under the filename """
|
||||
if outputfile == '-':
|
||||
outputfp = zipfile.ZipFile(sys.stdout,"w")
|
||||
else:
|
||||
if addsuffix:
|
||||
outputfile = outputfile + odmimetypes.get(self.mimetype,'.xxx')
|
||||
outputfp = zipfile.ZipFile(outputfile,"w")
|
||||
self._zipwrite(outputfp)
|
||||
outputfp.close()
|
||||
|
||||
def write(self, outputfp):
|
||||
zipoutputfp = zipfile.ZipFile(outputfp,"w")
|
||||
self._zipwrite(zipoutputfp)
|
||||
|
||||
def _zipwrite(self, outputfp):
|
||||
""" Write the document to an open file pointer """
|
||||
self._z = outputfp
|
||||
self._now = time.localtime()[:6]
|
||||
self.manifest = manifest.Manifest()
|
||||
|
||||
# Write mimetype
|
||||
zi = zipfile.ZipInfo('mimetype', self._now)
|
||||
zi.compress_type = zipfile.ZIP_STORED
|
||||
zi.external_attr = UNIXPERMS
|
||||
self._z.writestr(zi, self.mimetype)
|
||||
|
||||
self._saveXmlObjects(self,"")
|
||||
|
||||
# Write pictures
|
||||
self._savePictures(self,"")
|
||||
|
||||
# Write the thumbnail
|
||||
if self.thumbnail is not None:
|
||||
self.manifest.addElement(manifest.FileEntry(fullpath="Thumbnails/", mediatype=''))
|
||||
self.manifest.addElement(manifest.FileEntry(fullpath="Thumbnails/thumbnail.png", mediatype=''))
|
||||
zi = zipfile.ZipInfo("Thumbnails/thumbnail.png", self._now)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.external_attr = UNIXPERMS
|
||||
self._z.writestr(zi, self.thumbnail)
|
||||
|
||||
# Write manifest
|
||||
zi = zipfile.ZipInfo("META-INF/manifest.xml", self._now)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.external_attr = UNIXPERMS
|
||||
self._z.writestr(zi, self.manifestxml() )
|
||||
del self._z
|
||||
del self._now
|
||||
del self.manifest
|
||||
|
||||
|
||||
def _saveXmlObjects(self, object, folder):
|
||||
if self == object:
|
||||
self.manifest.addElement(manifest.FileEntry(fullpath="/", mediatype=object.mimetype))
|
||||
else:
|
||||
self.manifest.addElement(manifest.FileEntry(fullpath=folder, mediatype=object.mimetype))
|
||||
# Write styles
|
||||
self.manifest.addElement(manifest.FileEntry(fullpath="%sstyles.xml" % folder, mediatype="text/xml"))
|
||||
zi = zipfile.ZipInfo("%sstyles.xml" % folder, self._now)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.external_attr = UNIXPERMS
|
||||
self._z.writestr(zi, object.stylesxml() )
|
||||
|
||||
# Write content
|
||||
self.manifest.addElement(manifest.FileEntry(fullpath="%scontent.xml" % folder, mediatype="text/xml"))
|
||||
zi = zipfile.ZipInfo("%scontent.xml" % folder, self._now)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.external_attr = UNIXPERMS
|
||||
self._z.writestr(zi, object.contentxml() )
|
||||
|
||||
# Write settings
|
||||
if self == object and self.settings.hasChildNodes():
|
||||
self.manifest.addElement(manifest.FileEntry(fullpath="settings.xml",mediatype="text/xml"))
|
||||
zi = zipfile.ZipInfo("%ssettings.xml" % folder, self._now)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.external_attr = UNIXPERMS
|
||||
self._z.writestr(zi, object.settingsxml() )
|
||||
|
||||
# Write meta
|
||||
if self == object:
|
||||
self.manifest.addElement(manifest.FileEntry(fullpath="meta.xml",mediatype="text/xml"))
|
||||
zi = zipfile.ZipInfo("meta.xml", self._now)
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zi.external_attr = UNIXPERMS
|
||||
self._z.writestr(zi, object.metaxml() )
|
||||
|
||||
# Write subobjects
|
||||
subobjectnum = 1
|
||||
for subobject in object.childobjects:
|
||||
self._saveXmlObjects(subobject, '%sObject %d/' % (folder, subobjectnum))
|
||||
subobjectnum += 1
|
||||
|
||||
# Document's DOM methods
|
||||
def createElement(self, element):
|
||||
""" Inconvenient interface to create an element, but follows XML-DOM.
|
||||
Does not allow attributes as argument, therefore can't check grammar.
|
||||
"""
|
||||
return element(check_grammar=False)
|
||||
|
||||
def createTextNode(self, data):
|
||||
""" Method to create a text node """
|
||||
return element.Text(data)
|
||||
|
||||
def createCDATASection(self, data):
|
||||
return element.CDATASection(cdata)
|
||||
|
||||
def getMediaType(self):
|
||||
""" Returns the media type """
|
||||
return self.mimetype
|
||||
|
||||
def getStyleByName(self, name):
|
||||
ncname = make_NCName(name)
|
||||
if self._styles_dict == {}:
|
||||
self.rebuild_caches()
|
||||
return self._styles_dict.get(ncname, None)
|
||||
|
||||
def getElementsByType(self, element):
|
||||
obj = element(check_grammar=False)
|
||||
if self.element_dict == {}:
|
||||
self.rebuild_caches()
|
||||
return self.element_dict.get(obj.qname, [])
|
||||
|
||||
# Convenience functions
|
||||
def OpenDocumentChart():
|
||||
doc = OpenDocument('application/vnd.oasis.opendocument.chart')
|
||||
doc.chart = Chart()
|
||||
doc.body.addElement(doc.chart)
|
||||
return doc
|
||||
|
||||
def OpenDocumentDrawing():
|
||||
doc = OpenDocument('application/vnd.oasis.opendocument.graphics')
|
||||
doc.drawing = Drawing()
|
||||
doc.body.addElement(doc.drawing)
|
||||
return doc
|
||||
|
||||
def OpenDocumentImage():
|
||||
doc = OpenDocument('application/vnd.oasis.opendocument.image')
|
||||
doc.image = Image()
|
||||
doc.body.addElement(doc.image)
|
||||
return doc
|
||||
|
||||
def OpenDocumentPresentation():
|
||||
doc = OpenDocument('application/vnd.oasis.opendocument.presentation')
|
||||
doc.presentation = Presentation()
|
||||
doc.body.addElement(doc.presentation)
|
||||
return doc
|
||||
|
||||
def OpenDocumentSpreadsheet():
|
||||
doc = OpenDocument('application/vnd.oasis.opendocument.spreadsheet')
|
||||
doc.spreadsheet = Spreadsheet()
|
||||
doc.body.addElement(doc.spreadsheet)
|
||||
return doc
|
||||
|
||||
def OpenDocumentText():
|
||||
doc = OpenDocument('application/vnd.oasis.opendocument.text')
|
||||
doc.text = Text()
|
||||
doc.body.addElement(doc.text)
|
||||
return doc
|
||||
|
||||
|
||||
def load(odffile):
|
||||
from load import LoadParser
|
||||
from xml.sax import make_parser, handler
|
||||
z = zipfile.ZipFile(odffile)
|
||||
mimetype = z.read('mimetype')
|
||||
doc = OpenDocument(mimetype, add_generator=False)
|
||||
|
||||
# Look in the manifest file to see if which of the four files there are
|
||||
manifestpart = z.read('META-INF/manifest.xml')
|
||||
manifest = manifestlist(manifestpart)
|
||||
for xmlfile in ('settings.xml', 'meta.xml', 'content.xml', 'styles.xml'):
|
||||
if not manifest.has_key(xmlfile):
|
||||
continue
|
||||
try:
|
||||
xmlpart = z.read(xmlfile)
|
||||
doc._parsing = xmlfile
|
||||
|
||||
parser = make_parser()
|
||||
parser.setFeature(handler.feature_namespaces, 1)
|
||||
parser.setContentHandler(LoadParser(doc))
|
||||
parser.setErrorHandler(handler.ErrorHandler())
|
||||
|
||||
inpsrc = InputSource()
|
||||
inpsrc.setByteStream(StringIO(xmlpart))
|
||||
parser.parse(inpsrc)
|
||||
del doc._parsing
|
||||
except KeyError, v: pass
|
||||
# Add the thumbnail here
|
||||
# Add the images here
|
||||
for mentry,mvalue in manifest.items():
|
||||
if mentry[:9] == "Pictures/" and len(mentry) > 9:
|
||||
doc.addPicture(mvalue['full-path'], mvalue['media-type'], z.read(mentry))
|
||||
elif mentry == "Thumbnails/thumbnail.png":
|
||||
doc.addThumbnail(z.read(mentry))
|
||||
else:
|
||||
pass # Add the SUN junk here to the struct somewhere
|
||||
# It is cached data, so it can be out-of-date
|
||||
z.close()
|
||||
b = doc.getElementsByType(Body)
|
||||
if mimetype[:39] == 'application/vnd.oasis.opendocument.text':
|
||||
doc.text = b[0].firstChild
|
||||
elif mimetype[:43] == 'application/vnd.oasis.opendocument.graphics':
|
||||
doc.graphics = b[0].firstChild
|
||||
elif mimetype[:47] == 'application/vnd.oasis.opendocument.presentation':
|
||||
doc.presentation = b[0].firstChild
|
||||
elif mimetype[:46] == 'application/vnd.oasis.opendocument.spreadsheet':
|
||||
doc.spreadsheet = b[0].firstChild
|
||||
elif mimetype[:40] == 'application/vnd.oasis.opendocument.chart':
|
||||
doc.chart = b[0].firstChild
|
||||
elif mimetype[:40] == 'application/vnd.oasis.opendocument.image':
|
||||
doc.image = b[0].firstChild
|
||||
elif mimetype[:42] == 'application/vnd.oasis.opendocument.formula':
|
||||
doc.formula = b[0].firstChild
|
||||
return doc
|
||||
# vim: set expandtab sw=4 :
|
85
src/odf/presentation.py
Normal file
85
src/odf/presentation.py
Normal file
@ -0,0 +1,85 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import PRESENTATIONNS
|
||||
from element import Element
|
||||
|
||||
# ODF 1.0 section 9.6 and 9.7
|
||||
# Autogenerated
|
||||
def AnimationGroup(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'animation-group'), **args)
|
||||
|
||||
def Animations(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'animations'), **args)
|
||||
|
||||
def DateTime(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'date-time'), **args)
|
||||
|
||||
def DateTimeDecl(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'date-time-decl'), **args)
|
||||
|
||||
def Dim(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'dim'), **args)
|
||||
|
||||
def EventListener(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'event-listener'), **args)
|
||||
|
||||
def Footer(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'footer'), **args)
|
||||
|
||||
def FooterDecl(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'footer-decl'), **args)
|
||||
|
||||
def Header(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'header'), **args)
|
||||
|
||||
def HeaderDecl(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'header-decl'), **args)
|
||||
|
||||
def HideShape(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'hide-shape'), **args)
|
||||
|
||||
def HideText(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'hide-text'), **args)
|
||||
|
||||
def Notes(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'notes'), **args)
|
||||
|
||||
def Placeholder(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'placeholder'), **args)
|
||||
|
||||
def Play(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'play'), **args)
|
||||
|
||||
def Settings(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'settings'), **args)
|
||||
|
||||
def Show(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'show'), **args)
|
||||
|
||||
def ShowShape(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'show-shape'), **args)
|
||||
|
||||
def ShowText(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'show-text'), **args)
|
||||
|
||||
def Sound(**args):
|
||||
return Element(qname = (PRESENTATIONNS,'sound'), **args)
|
||||
|
30
src/odf/script.py
Normal file
30
src/odf/script.py
Normal file
@ -0,0 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import SCRIPTNS
|
||||
from element import Element
|
||||
|
||||
# ODF 1.0 section 12.4.1
|
||||
# The <script:event-listener> element binds an event to a macro.
|
||||
|
||||
# Autogenerated
|
||||
def EventListener(**args):
|
||||
return Element(qname = (SCRIPTNS,'event-listener'), **args)
|
||||
|
148
src/odf/style.py
Normal file
148
src/odf/style.py
Normal file
@ -0,0 +1,148 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import STYLENS
|
||||
from element import Element
|
||||
|
||||
def StyleElement(**args):
|
||||
e = Element(**args)
|
||||
if args.get('check_grammar', True) == True:
|
||||
if not args.has_key('displayname'):
|
||||
e.setAttrNS(STYLENS,'display-name', args.get('name'))
|
||||
return e
|
||||
|
||||
# Autogenerated
|
||||
def BackgroundImage(**args):
|
||||
return Element(qname = (STYLENS,'background-image'), **args)
|
||||
|
||||
def ChartProperties(**args):
|
||||
return Element(qname = (STYLENS,'chart-properties'), **args)
|
||||
|
||||
def Column(**args):
|
||||
return Element(qname = (STYLENS,'column'), **args)
|
||||
|
||||
def ColumnSep(**args):
|
||||
return Element(qname = (STYLENS,'column-sep'), **args)
|
||||
|
||||
def Columns(**args):
|
||||
return Element(qname = (STYLENS,'columns'), **args)
|
||||
|
||||
def DefaultStyle(**args):
|
||||
return Element(qname = (STYLENS,'default-style'), **args)
|
||||
|
||||
def DrawingPageProperties(**args):
|
||||
return Element(qname = (STYLENS,'drawing-page-properties'), **args)
|
||||
|
||||
def DropCap(**args):
|
||||
return Element(qname = (STYLENS,'drop-cap'), **args)
|
||||
|
||||
def FontFace(**args):
|
||||
return Element(qname = (STYLENS,'font-face'), **args)
|
||||
|
||||
def Footer(**args):
|
||||
return Element(qname = (STYLENS,'footer'), **args)
|
||||
|
||||
def FooterLeft(**args):
|
||||
return Element(qname = (STYLENS,'footer-left'), **args)
|
||||
|
||||
def FooterStyle(**args):
|
||||
return Element(qname = (STYLENS,'footer-style'), **args)
|
||||
|
||||
def FootnoteSep(**args):
|
||||
return Element(qname = (STYLENS,'footnote-sep'), **args)
|
||||
|
||||
def GraphicProperties(**args):
|
||||
return Element(qname = (STYLENS,'graphic-properties'), **args)
|
||||
|
||||
def HandoutMaster(**args):
|
||||
return Element(qname = (STYLENS,'handout-master'), **args)
|
||||
|
||||
def Header(**args):
|
||||
return Element(qname = (STYLENS,'header'), **args)
|
||||
|
||||
def HeaderFooterProperties(**args):
|
||||
return Element(qname = (STYLENS,'header-footer-properties'), **args)
|
||||
|
||||
def HeaderLeft(**args):
|
||||
return Element(qname = (STYLENS,'header-left'), **args)
|
||||
|
||||
def HeaderStyle(**args):
|
||||
return Element(qname = (STYLENS,'header-style'), **args)
|
||||
|
||||
def ListLevelProperties(**args):
|
||||
return Element(qname = (STYLENS,'list-level-properties'), **args)
|
||||
|
||||
def Map(**args):
|
||||
return Element(qname = (STYLENS,'map'), **args)
|
||||
|
||||
def MasterPage(**args):
|
||||
return StyleElement(qname = (STYLENS,'master-page'), **args)
|
||||
|
||||
def PageLayout(**args):
|
||||
return Element(qname = (STYLENS,'page-layout'), **args)
|
||||
|
||||
def PageLayoutProperties(**args):
|
||||
return Element(qname = (STYLENS,'page-layout-properties'), **args)
|
||||
|
||||
def ParagraphProperties(**args):
|
||||
return Element(qname = (STYLENS,'paragraph-properties'), **args)
|
||||
|
||||
def PresentationPageLayout(**args):
|
||||
return StyleElement(qname = (STYLENS,'presentation-page-layout'), **args)
|
||||
|
||||
def RegionCenter(**args):
|
||||
return Element(qname = (STYLENS,'region-center'), **args)
|
||||
|
||||
def RegionLeft(**args):
|
||||
return Element(qname = (STYLENS,'region-left'), **args)
|
||||
|
||||
def RegionRight(**args):
|
||||
return Element(qname = (STYLENS,'region-right'), **args)
|
||||
|
||||
def RubyProperties(**args):
|
||||
return Element(qname = (STYLENS,'ruby-properties'), **args)
|
||||
|
||||
def SectionProperties(**args):
|
||||
return Element(qname = (STYLENS,'section-properties'), **args)
|
||||
|
||||
def Style(**args):
|
||||
return StyleElement(qname = (STYLENS,'style'), **args)
|
||||
|
||||
def TabStop(**args):
|
||||
return Element(qname = (STYLENS,'tab-stop'), **args)
|
||||
|
||||
def TabStops(**args):
|
||||
return Element(qname = (STYLENS,'tab-stops'), **args)
|
||||
|
||||
def TableCellProperties(**args):
|
||||
return Element(qname = (STYLENS,'table-cell-properties'), **args)
|
||||
|
||||
def TableColumnProperties(**args):
|
||||
return Element(qname = (STYLENS,'table-column-properties'), **args)
|
||||
|
||||
def TableProperties(**args):
|
||||
return Element(qname = (STYLENS,'table-properties'), **args)
|
||||
|
||||
def TableRowProperties(**args):
|
||||
return Element(qname = (STYLENS,'table-row-properties'), **args)
|
||||
|
||||
def TextProperties(**args):
|
||||
return Element(qname = (STYLENS,'text-properties'), **args)
|
||||
|
52
src/odf/svg.py
Normal file
52
src/odf/svg.py
Normal file
@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import SVGNS
|
||||
from element import Element
|
||||
from draw import DrawElement
|
||||
|
||||
# Autogenerated
|
||||
def DefinitionSrc(**args):
|
||||
return Element(qname = (SVGNS,'definition-src'), **args)
|
||||
|
||||
def Desc(**args):
|
||||
return Element(qname = (SVGNS,'desc'), **args)
|
||||
|
||||
def FontFaceFormat(**args):
|
||||
return Element(qname = (SVGNS,'font-face-format'), **args)
|
||||
|
||||
def FontFaceName(**args):
|
||||
return Element(qname = (SVGNS,'font-face-name'), **args)
|
||||
|
||||
def FontFaceSrc(**args):
|
||||
return Element(qname = (SVGNS,'font-face-src'), **args)
|
||||
|
||||
def FontFaceUri(**args):
|
||||
return Element(qname = (SVGNS,'font-face-uri'), **args)
|
||||
|
||||
def Lineargradient(**args):
|
||||
return DrawElement(qname = (SVGNS,'linearGradient'), **args)
|
||||
|
||||
def Radialgradient(**args):
|
||||
return DrawElement(qname = (SVGNS,'radialGradient'), **args)
|
||||
|
||||
def Stop(**args):
|
||||
return Element(qname = (SVGNS,'stop'), **args)
|
||||
|
307
src/odf/table.py
Normal file
307
src/odf/table.py
Normal file
@ -0,0 +1,307 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import TABLENS
|
||||
from element import Element
|
||||
|
||||
|
||||
# Autogenerated
|
||||
def Body(**args):
|
||||
return Element(qname = (TABLENS,'body'), **args)
|
||||
|
||||
def CalculationSettings(**args):
|
||||
return Element(qname = (TABLENS,'calculation-settings'), **args)
|
||||
|
||||
def CellAddress(**args):
|
||||
return Element(qname = (TABLENS,'cell-address'), **args)
|
||||
|
||||
def CellContentChange(**args):
|
||||
return Element(qname = (TABLENS,'cell-content-change'), **args)
|
||||
|
||||
def CellContentDeletion(**args):
|
||||
return Element(qname = (TABLENS,'cell-content-deletion'), **args)
|
||||
|
||||
def CellRangeSource(**args):
|
||||
return Element(qname = (TABLENS,'cell-range-source'), **args)
|
||||
|
||||
def ChangeDeletion(**args):
|
||||
return Element(qname = (TABLENS,'change-deletion'), **args)
|
||||
|
||||
def ChangeTrackTableCell(**args):
|
||||
return Element(qname = (TABLENS,'change-track-table-cell'), **args)
|
||||
|
||||
def Consolidation(**args):
|
||||
return Element(qname = (TABLENS,'consolidation'), **args)
|
||||
|
||||
def ContentValidation(**args):
|
||||
return Element(qname = (TABLENS,'content-validation'), **args)
|
||||
|
||||
def ContentValidations(**args):
|
||||
return Element(qname = (TABLENS,'content-validations'), **args)
|
||||
|
||||
def CoveredTableCell(**args):
|
||||
return Element(qname = (TABLENS,'covered-table-cell'), **args)
|
||||
|
||||
def CutOffs(**args):
|
||||
return Element(qname = (TABLENS,'cut-offs'), **args)
|
||||
|
||||
def DataPilotDisplayInfo(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-display-info'), **args)
|
||||
|
||||
def DataPilotField(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-field'), **args)
|
||||
|
||||
def DataPilotFieldReference(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-field-reference'), **args)
|
||||
|
||||
def DataPilotGroup(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-group'), **args)
|
||||
|
||||
def DataPilotGroupMember(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-group-member'), **args)
|
||||
|
||||
def DataPilotGroups(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-groups'), **args)
|
||||
|
||||
def DataPilotLayoutInfo(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-layout-info'), **args)
|
||||
|
||||
def DataPilotLevel(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-level'), **args)
|
||||
|
||||
def DataPilotMember(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-member'), **args)
|
||||
|
||||
def DataPilotMembers(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-members'), **args)
|
||||
|
||||
def DataPilotSortInfo(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-sort-info'), **args)
|
||||
|
||||
def DataPilotSubtotal(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-subtotal'), **args)
|
||||
|
||||
def DataPilotSubtotals(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-subtotals'), **args)
|
||||
|
||||
def DataPilotTable(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-table'), **args)
|
||||
|
||||
def DataPilotTables(**args):
|
||||
return Element(qname = (TABLENS,'data-pilot-tables'), **args)
|
||||
|
||||
def DatabaseRange(**args):
|
||||
return Element(qname = (TABLENS,'database-range'), **args)
|
||||
|
||||
def DatabaseRanges(**args):
|
||||
return Element(qname = (TABLENS,'database-ranges'), **args)
|
||||
|
||||
def DatabaseSourceQuery(**args):
|
||||
return Element(qname = (TABLENS,'database-source-query'), **args)
|
||||
|
||||
def DatabaseSourceSql(**args):
|
||||
return Element(qname = (TABLENS,'database-source-sql'), **args)
|
||||
|
||||
def DatabaseSourceTable(**args):
|
||||
return Element(qname = (TABLENS,'database-source-table'), **args)
|
||||
|
||||
def DdeLink(**args):
|
||||
return Element(qname = (TABLENS,'dde-link'), **args)
|
||||
|
||||
def DdeLinks(**args):
|
||||
return Element(qname = (TABLENS,'dde-links'), **args)
|
||||
|
||||
def Deletion(**args):
|
||||
return Element(qname = (TABLENS,'deletion'), **args)
|
||||
|
||||
def Deletions(**args):
|
||||
return Element(qname = (TABLENS,'deletions'), **args)
|
||||
|
||||
def Dependencies(**args):
|
||||
return Element(qname = (TABLENS,'dependencies'), **args)
|
||||
|
||||
def Dependency(**args):
|
||||
return Element(qname = (TABLENS,'dependency'), **args)
|
||||
|
||||
def Detective(**args):
|
||||
return Element(qname = (TABLENS,'detective'), **args)
|
||||
|
||||
def ErrorMacro(**args):
|
||||
return Element(qname = (TABLENS,'error-macro'), **args)
|
||||
|
||||
def ErrorMessage(**args):
|
||||
return Element(qname = (TABLENS,'error-message'), **args)
|
||||
|
||||
def EvenColumns(**args):
|
||||
return Element(qname = (TABLENS,'even-columns'), **args)
|
||||
|
||||
def EvenRows(**args):
|
||||
return Element(qname = (TABLENS,'even-rows'), **args)
|
||||
|
||||
def Filter(**args):
|
||||
return Element(qname = (TABLENS,'filter'), **args)
|
||||
|
||||
def FilterAnd(**args):
|
||||
return Element(qname = (TABLENS,'filter-and'), **args)
|
||||
|
||||
def FilterCondition(**args):
|
||||
return Element(qname = (TABLENS,'filter-condition'), **args)
|
||||
|
||||
def FilterOr(**args):
|
||||
return Element(qname = (TABLENS,'filter-or'), **args)
|
||||
|
||||
def FirstColumn(**args):
|
||||
return Element(qname = (TABLENS,'first-column'), **args)
|
||||
|
||||
def FirstRow(**args):
|
||||
return Element(qname = (TABLENS,'first-row'), **args)
|
||||
|
||||
def HelpMessage(**args):
|
||||
return Element(qname = (TABLENS,'help-message'), **args)
|
||||
|
||||
def HighlightedRange(**args):
|
||||
return Element(qname = (TABLENS,'highlighted-range'), **args)
|
||||
|
||||
def Insertion(**args):
|
||||
return Element(qname = (TABLENS,'insertion'), **args)
|
||||
|
||||
def InsertionCutOff(**args):
|
||||
return Element(qname = (TABLENS,'insertion-cut-off'), **args)
|
||||
|
||||
def Iteration(**args):
|
||||
return Element(qname = (TABLENS,'iteration'), **args)
|
||||
|
||||
def LabelRange(**args):
|
||||
return Element(qname = (TABLENS,'label-range'), **args)
|
||||
|
||||
def LabelRanges(**args):
|
||||
return Element(qname = (TABLENS,'label-ranges'), **args)
|
||||
|
||||
def LastColumn(**args):
|
||||
return Element(qname = (TABLENS,'last-column'), **args)
|
||||
|
||||
def LastRow(**args):
|
||||
return Element(qname = (TABLENS,'last-row'), **args)
|
||||
|
||||
def Movement(**args):
|
||||
return Element(qname = (TABLENS,'movement'), **args)
|
||||
|
||||
def MovementCutOff(**args):
|
||||
return Element(qname = (TABLENS,'movement-cut-off'), **args)
|
||||
|
||||
def NamedExpression(**args):
|
||||
return Element(qname = (TABLENS,'named-expression'), **args)
|
||||
|
||||
def NamedExpressions(**args):
|
||||
return Element(qname = (TABLENS,'named-expressions'), **args)
|
||||
|
||||
def NamedRange(**args):
|
||||
return Element(qname = (TABLENS,'named-range'), **args)
|
||||
|
||||
def NullDate(**args):
|
||||
return Element(qname = (TABLENS,'null-date'), **args)
|
||||
|
||||
def OddColumns(**args):
|
||||
return Element(qname = (TABLENS,'odd-columns'), **args)
|
||||
|
||||
def OddRows(**args):
|
||||
return Element(qname = (TABLENS,'odd-rows'), **args)
|
||||
|
||||
def Operation(**args):
|
||||
return Element(qname = (TABLENS,'operation'), **args)
|
||||
|
||||
def Previous(**args):
|
||||
return Element(qname = (TABLENS,'previous'), **args)
|
||||
|
||||
def Scenario(**args):
|
||||
return Element(qname = (TABLENS,'scenario'), **args)
|
||||
|
||||
def Shapes(**args):
|
||||
return Element(qname = (TABLENS,'shapes'), **args)
|
||||
|
||||
def Sort(**args):
|
||||
return Element(qname = (TABLENS,'sort'), **args)
|
||||
|
||||
def SortBy(**args):
|
||||
return Element(qname = (TABLENS,'sort-by'), **args)
|
||||
|
||||
def SortGroups(**args):
|
||||
return Element(qname = (TABLENS,'sort-groups'), **args)
|
||||
|
||||
def SourceCellRange(**args):
|
||||
return Element(qname = (TABLENS,'source-cell-range'), **args)
|
||||
|
||||
def SourceRangeAddress(**args):
|
||||
return Element(qname = (TABLENS,'source-range-address'), **args)
|
||||
|
||||
def SourceService(**args):
|
||||
return Element(qname = (TABLENS,'source-service'), **args)
|
||||
|
||||
def SubtotalField(**args):
|
||||
return Element(qname = (TABLENS,'subtotal-field'), **args)
|
||||
|
||||
def SubtotalRule(**args):
|
||||
return Element(qname = (TABLENS,'subtotal-rule'), **args)
|
||||
|
||||
def SubtotalRules(**args):
|
||||
return Element(qname = (TABLENS,'subtotal-rules'), **args)
|
||||
|
||||
def Table(**args):
|
||||
return Element(qname = (TABLENS,'table'), **args)
|
||||
|
||||
def TableCell(**args):
|
||||
return Element(qname = (TABLENS,'table-cell'), **args)
|
||||
|
||||
def TableColumn(**args):
|
||||
return Element(qname = (TABLENS,'table-column'), **args)
|
||||
|
||||
def TableColumnGroup(**args):
|
||||
return Element(qname = (TABLENS,'table-column-group'), **args)
|
||||
|
||||
def TableColumns(**args):
|
||||
return Element(qname = (TABLENS,'table-columns'), **args)
|
||||
|
||||
def TableHeaderColumns(**args):
|
||||
return Element(qname = (TABLENS,'table-header-columns'), **args)
|
||||
|
||||
def TableHeaderRows(**args):
|
||||
return Element(qname = (TABLENS,'table-header-rows'), **args)
|
||||
|
||||
def TableRow(**args):
|
||||
return Element(qname = (TABLENS,'table-row'), **args)
|
||||
|
||||
def TableRowGroup(**args):
|
||||
return Element(qname = (TABLENS,'table-row-group'), **args)
|
||||
|
||||
def TableRows(**args):
|
||||
return Element(qname = (TABLENS,'table-rows'), **args)
|
||||
|
||||
def TableSource(**args):
|
||||
return Element(qname = (TABLENS,'table-source'), **args)
|
||||
|
||||
def TableTemplate(**args):
|
||||
return Element(qname = (TABLENS,'table-template'), **args)
|
||||
|
||||
def TargetRangeAddress(**args):
|
||||
return Element(qname = (TABLENS,'target-range-address'), **args)
|
||||
|
||||
def TrackedChanges(**args):
|
||||
return Element(qname = (TABLENS,'tracked-changes'), **args)
|
||||
|
137
src/odf/teletype.py
Normal file
137
src/odf/teletype.py
Normal file
@ -0,0 +1,137 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Create and extract text from ODF, handling whitespace correctly.
|
||||
# Copyright (C) 2008 J. David Eisenberg
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, 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.
|
||||
|
||||
|
||||
"""
|
||||
Class for handling whitespace properly in OpenDocument.
|
||||
|
||||
While it is possible to use getTextContent() and setTextContent()
|
||||
to extract or create ODF content, these won't extract or create
|
||||
the appropriate <text:s>, <text:tab>, or <text:line-break>
|
||||
elements. This module takes care of that problem.
|
||||
"""
|
||||
|
||||
from odf.element import Node
|
||||
import odf.opendocument
|
||||
from odf.text import S,LineBreak,Tab
|
||||
|
||||
class WhitespaceText(object):
|
||||
|
||||
def __init__(self):
|
||||
self.textBuffer = []
|
||||
self.spaceCount = 0
|
||||
|
||||
def addTextToElement(self, odfElement, s):
|
||||
""" Process an input string, inserting
|
||||
<text:tab> elements for '\t',
|
||||
<text:line-break> elements for '\n', and
|
||||
<text:s> elements for runs of more than one blank.
|
||||
These will be added to the given element.
|
||||
"""
|
||||
i = 0
|
||||
ch = ' '
|
||||
|
||||
# When we encounter a tab or newline, we can immediately
|
||||
# dump any accumulated text and then emit the appropriate
|
||||
# ODF element.
|
||||
#
|
||||
# When we encounter a space, we add it to the text buffer,
|
||||
# and then collect more spaces. If there are more spaces
|
||||
# after the first one, we dump the text buffer and then
|
||||
# then emit the appropriate <text:s> element.
|
||||
|
||||
while i < len(s):
|
||||
ch = s[i]
|
||||
if ch == '\t':
|
||||
self._emitTextBuffer(odfElement)
|
||||
odfElement.addElement(Tab())
|
||||
i += 1
|
||||
elif ch == '\n':
|
||||
self._emitTextBuffer(odfElement);
|
||||
odfElement.addElement(LineBreak())
|
||||
i += 1
|
||||
elif ch == ' ':
|
||||
self.textBuffer.append(' ')
|
||||
i += 1
|
||||
self.spaceCount = 0
|
||||
while i < len(s) and (s[i] == ' '):
|
||||
self.spaceCount += 1
|
||||
i += 1
|
||||
if self.spaceCount > 0:
|
||||
self._emitTextBuffer(odfElement)
|
||||
self._emitSpaces(odfElement)
|
||||
else:
|
||||
self.textBuffer.append(ch)
|
||||
i += 1
|
||||
|
||||
self._emitTextBuffer(odfElement)
|
||||
|
||||
def _emitTextBuffer(self, odfElement):
|
||||
""" Creates a Text Node whose contents are the current textBuffer.
|
||||
Side effect: clears the text buffer.
|
||||
"""
|
||||
if len(self.textBuffer) > 0:
|
||||
odfElement.addText(''.join(self.textBuffer))
|
||||
self.textBuffer = []
|
||||
|
||||
|
||||
def _emitSpaces(self, odfElement):
|
||||
""" Creates a <text:s> element for the current spaceCount.
|
||||
Side effect: sets spaceCount back to zero
|
||||
"""
|
||||
if self.spaceCount > 0:
|
||||
spaceElement = S(c=self.spaceCount)
|
||||
odfElement.addElement(spaceElement)
|
||||
self.spaceCount = 0
|
||||
|
||||
def addTextToElement(odfElement, s):
|
||||
wst = WhitespaceText()
|
||||
wst.addTextToElement(odfElement, s)
|
||||
|
||||
def extractText(odfElement):
|
||||
""" Extract text content from an Element, with whitespace represented
|
||||
properly. Returns the text, with tabs, spaces, and newlines
|
||||
correctly evaluated. This method recursively descends through the
|
||||
children of the given element, accumulating text and "unwrapping"
|
||||
<text:s>, <text:tab>, and <text:line-break> elements along the way.
|
||||
"""
|
||||
result = [];
|
||||
|
||||
if len(odfElement.childNodes) != 0:
|
||||
for child in odfElement.childNodes:
|
||||
if child.nodeType == Node.TEXT_NODE:
|
||||
result.append(child.data)
|
||||
elif child.nodeType == Node.ELEMENT_NODE:
|
||||
subElement = child
|
||||
tagName = subElement.qname;
|
||||
if tagName == (u"urn:oasis:names:tc:opendocument:xmlns:text:1.0", u"line-break"):
|
||||
result.append("\n")
|
||||
elif tagName == (u"urn:oasis:names:tc:opendocument:xmlns:text:1.0", u"tab"):
|
||||
result.append("\t")
|
||||
elif tagName == (u"urn:oasis:names:tc:opendocument:xmlns:text:1.0", u"s"):
|
||||
c = subElement.getAttribute('c')
|
||||
if c:
|
||||
spaceCount = int(c)
|
||||
else:
|
||||
spaceCount = 1
|
||||
|
||||
result.append(" " * spaceCount)
|
||||
else:
|
||||
result.append(extractText(subElement))
|
||||
return ''.join(result)
|
559
src/odf/text.py
Normal file
559
src/odf/text.py
Normal file
@ -0,0 +1,559 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import TEXTNS
|
||||
from element import Element
|
||||
from style import StyleElement
|
||||
|
||||
# Autogenerated
|
||||
def A(**args):
|
||||
return Element(qname = (TEXTNS,'a'), **args)
|
||||
|
||||
def AlphabeticalIndex(**args):
|
||||
return Element(qname = (TEXTNS,'alphabetical-index'), **args)
|
||||
|
||||
def AlphabeticalIndexAutoMarkFile(**args):
|
||||
return Element(qname = (TEXTNS,'alphabetical-index-auto-mark-file'), **args)
|
||||
|
||||
def AlphabeticalIndexEntryTemplate(**args):
|
||||
return Element(qname = (TEXTNS,'alphabetical-index-entry-template'), **args)
|
||||
|
||||
def AlphabeticalIndexMark(**args):
|
||||
return Element(qname = (TEXTNS,'alphabetical-index-mark'), **args)
|
||||
|
||||
def AlphabeticalIndexMarkEnd(**args):
|
||||
return Element(qname = (TEXTNS,'alphabetical-index-mark-end'), **args)
|
||||
|
||||
def AlphabeticalIndexMarkStart(**args):
|
||||
return Element(qname = (TEXTNS,'alphabetical-index-mark-start'), **args)
|
||||
|
||||
def AlphabeticalIndexSource(**args):
|
||||
return Element(qname = (TEXTNS,'alphabetical-index-source'), **args)
|
||||
|
||||
def AuthorInitials(**args):
|
||||
return Element(qname = (TEXTNS,'author-initials'), **args)
|
||||
|
||||
def AuthorName(**args):
|
||||
return Element(qname = (TEXTNS,'author-name'), **args)
|
||||
|
||||
def Bibliography(**args):
|
||||
return Element(qname = (TEXTNS,'bibliography'), **args)
|
||||
|
||||
def BibliographyConfiguration(**args):
|
||||
return Element(qname = (TEXTNS,'bibliography-configuration'), **args)
|
||||
|
||||
def BibliographyEntryTemplate(**args):
|
||||
return Element(qname = (TEXTNS,'bibliography-entry-template'), **args)
|
||||
|
||||
def BibliographyMark(**args):
|
||||
return Element(qname = (TEXTNS,'bibliography-mark'), **args)
|
||||
|
||||
def BibliographySource(**args):
|
||||
return Element(qname = (TEXTNS,'bibliography-source'), **args)
|
||||
|
||||
def Bookmark(**args):
|
||||
return Element(qname = (TEXTNS,'bookmark'), **args)
|
||||
|
||||
def BookmarkEnd(**args):
|
||||
return Element(qname = (TEXTNS,'bookmark-end'), **args)
|
||||
|
||||
def BookmarkRef(**args):
|
||||
return Element(qname = (TEXTNS,'bookmark-ref'), **args)
|
||||
|
||||
def BookmarkStart(**args):
|
||||
return Element(qname = (TEXTNS,'bookmark-start'), **args)
|
||||
|
||||
def Change(**args):
|
||||
return Element(qname = (TEXTNS,'change'), **args)
|
||||
|
||||
def ChangeEnd(**args):
|
||||
return Element(qname = (TEXTNS,'change-end'), **args)
|
||||
|
||||
def ChangeStart(**args):
|
||||
return Element(qname = (TEXTNS,'change-start'), **args)
|
||||
|
||||
def ChangedRegion(**args):
|
||||
return Element(qname = (TEXTNS,'changed-region'), **args)
|
||||
|
||||
def Chapter(**args):
|
||||
return Element(qname = (TEXTNS,'chapter'), **args)
|
||||
|
||||
def CharacterCount(**args):
|
||||
return Element(qname = (TEXTNS,'character-count'), **args)
|
||||
|
||||
def ConditionalText(**args):
|
||||
return Element(qname = (TEXTNS,'conditional-text'), **args)
|
||||
|
||||
def CreationDate(**args):
|
||||
return Element(qname = (TEXTNS,'creation-date'), **args)
|
||||
|
||||
def CreationTime(**args):
|
||||
return Element(qname = (TEXTNS,'creation-time'), **args)
|
||||
|
||||
def Creator(**args):
|
||||
return Element(qname = (TEXTNS,'creator'), **args)
|
||||
|
||||
def DatabaseDisplay(**args):
|
||||
return Element(qname = (TEXTNS,'database-display'), **args)
|
||||
|
||||
def DatabaseName(**args):
|
||||
return Element(qname = (TEXTNS,'database-name'), **args)
|
||||
|
||||
def DatabaseNext(**args):
|
||||
return Element(qname = (TEXTNS,'database-next'), **args)
|
||||
|
||||
def DatabaseRowNumber(**args):
|
||||
return Element(qname = (TEXTNS,'database-row-number'), **args)
|
||||
|
||||
def DatabaseRowSelect(**args):
|
||||
return Element(qname = (TEXTNS,'database-row-select'), **args)
|
||||
|
||||
def Date(**args):
|
||||
return Element(qname = (TEXTNS,'date'), **args)
|
||||
|
||||
def DdeConnection(**args):
|
||||
return Element(qname = (TEXTNS,'dde-connection'), **args)
|
||||
|
||||
def DdeConnectionDecl(**args):
|
||||
return Element(qname = (TEXTNS,'dde-connection-decl'), **args)
|
||||
|
||||
def DdeConnectionDecls(**args):
|
||||
return Element(qname = (TEXTNS,'dde-connection-decls'), **args)
|
||||
|
||||
def Deletion(**args):
|
||||
return Element(qname = (TEXTNS,'deletion'), **args)
|
||||
|
||||
def Description(**args):
|
||||
return Element(qname = (TEXTNS,'description'), **args)
|
||||
|
||||
def EditingCycles(**args):
|
||||
return Element(qname = (TEXTNS,'editing-cycles'), **args)
|
||||
|
||||
def EditingDuration(**args):
|
||||
return Element(qname = (TEXTNS,'editing-duration'), **args)
|
||||
|
||||
def ExecuteMacro(**args):
|
||||
return Element(qname = (TEXTNS,'execute-macro'), **args)
|
||||
|
||||
def Expression(**args):
|
||||
return Element(qname = (TEXTNS,'expression'), **args)
|
||||
|
||||
def FileName(**args):
|
||||
return Element(qname = (TEXTNS,'file-name'), **args)
|
||||
|
||||
def FormatChange(**args):
|
||||
return Element(qname = (TEXTNS,'format-change'), **args)
|
||||
|
||||
def H(**args):
|
||||
return Element(qname = (TEXTNS, 'h'), **args)
|
||||
|
||||
def HiddenParagraph(**args):
|
||||
return Element(qname = (TEXTNS,'hidden-paragraph'), **args)
|
||||
|
||||
def HiddenText(**args):
|
||||
return Element(qname = (TEXTNS,'hidden-text'), **args)
|
||||
|
||||
def IllustrationIndex(**args):
|
||||
return Element(qname = (TEXTNS,'illustration-index'), **args)
|
||||
|
||||
def IllustrationIndexEntryTemplate(**args):
|
||||
return Element(qname = (TEXTNS,'illustration-index-entry-template'), **args)
|
||||
|
||||
def IllustrationIndexSource(**args):
|
||||
return Element(qname = (TEXTNS,'illustration-index-source'), **args)
|
||||
|
||||
def ImageCount(**args):
|
||||
return Element(qname = (TEXTNS,'image-count'), **args)
|
||||
|
||||
def IndexBody(**args):
|
||||
return Element(qname = (TEXTNS,'index-body'), **args)
|
||||
|
||||
def IndexEntryBibliography(**args):
|
||||
return Element(qname = (TEXTNS,'index-entry-bibliography'), **args)
|
||||
|
||||
def IndexEntryChapter(**args):
|
||||
return Element(qname = (TEXTNS,'index-entry-chapter'), **args)
|
||||
|
||||
def IndexEntryLinkEnd(**args):
|
||||
return Element(qname = (TEXTNS,'index-entry-link-end'), **args)
|
||||
|
||||
def IndexEntryLinkStart(**args):
|
||||
return Element(qname = (TEXTNS,'index-entry-link-start'), **args)
|
||||
|
||||
def IndexEntryPageNumber(**args):
|
||||
return Element(qname = (TEXTNS,'index-entry-page-number'), **args)
|
||||
|
||||
def IndexEntrySpan(**args):
|
||||
return Element(qname = (TEXTNS,'index-entry-span'), **args)
|
||||
|
||||
def IndexEntryTabStop(**args):
|
||||
return Element(qname = (TEXTNS,'index-entry-tab-stop'), **args)
|
||||
|
||||
def IndexEntryText(**args):
|
||||
return Element(qname = (TEXTNS,'index-entry-text'), **args)
|
||||
|
||||
def IndexSourceStyle(**args):
|
||||
return Element(qname = (TEXTNS,'index-source-style'), **args)
|
||||
|
||||
def IndexSourceStyles(**args):
|
||||
return Element(qname = (TEXTNS,'index-source-styles'), **args)
|
||||
|
||||
def IndexTitle(**args):
|
||||
return Element(qname = (TEXTNS,'index-title'), **args)
|
||||
|
||||
def IndexTitleTemplate(**args):
|
||||
return Element(qname = (TEXTNS,'index-title-template'), **args)
|
||||
|
||||
def InitialCreator(**args):
|
||||
return Element(qname = (TEXTNS,'initial-creator'), **args)
|
||||
|
||||
def Insertion(**args):
|
||||
return Element(qname = (TEXTNS,'insertion'), **args)
|
||||
|
||||
def Keywords(**args):
|
||||
return Element(qname = (TEXTNS,'keywords'), **args)
|
||||
|
||||
def LineBreak(**args):
|
||||
return Element(qname = (TEXTNS,'line-break'), **args)
|
||||
|
||||
def LinenumberingConfiguration(**args):
|
||||
return Element(qname = (TEXTNS,'linenumbering-configuration'), **args)
|
||||
|
||||
def LinenumberingSeparator(**args):
|
||||
return Element(qname = (TEXTNS,'linenumbering-separator'), **args)
|
||||
|
||||
def List(**args):
|
||||
return Element(qname = (TEXTNS,'list'), **args)
|
||||
|
||||
def ListHeader(**args):
|
||||
return Element(qname = (TEXTNS,'list-header'), **args)
|
||||
|
||||
def ListItem(**args):
|
||||
return Element(qname = (TEXTNS,'list-item'), **args)
|
||||
|
||||
def ListLevelStyleBullet(**args):
|
||||
return Element(qname = (TEXTNS,'list-level-style-bullet'), **args)
|
||||
|
||||
def ListLevelStyleImage(**args):
|
||||
return Element(qname = (TEXTNS,'list-level-style-image'), **args)
|
||||
|
||||
def ListLevelStyleNumber(**args):
|
||||
return Element(qname = (TEXTNS,'list-level-style-number'), **args)
|
||||
|
||||
def ListStyle(**args):
|
||||
return StyleElement(qname = (TEXTNS,'list-style'), **args)
|
||||
|
||||
def Measure(**args):
|
||||
return Element(qname = (TEXTNS,'measure'), **args)
|
||||
|
||||
def ModificationDate(**args):
|
||||
return Element(qname = (TEXTNS,'modification-date'), **args)
|
||||
|
||||
def ModificationTime(**args):
|
||||
return Element(qname = (TEXTNS,'modification-time'), **args)
|
||||
|
||||
def Note(**args):
|
||||
return Element(qname = (TEXTNS,'note'), **args)
|
||||
|
||||
def NoteBody(**args):
|
||||
return Element(qname = (TEXTNS,'note-body'), **args)
|
||||
|
||||
def NoteCitation(**args):
|
||||
return Element(qname = (TEXTNS,'note-citation'), **args)
|
||||
|
||||
def NoteContinuationNoticeBackward(**args):
|
||||
return Element(qname = (TEXTNS,'note-continuation-notice-backward'), **args)
|
||||
|
||||
def NoteContinuationNoticeForward(**args):
|
||||
return Element(qname = (TEXTNS,'note-continuation-notice-forward'), **args)
|
||||
|
||||
def NoteRef(**args):
|
||||
return Element(qname = (TEXTNS,'note-ref'), **args)
|
||||
|
||||
def NotesConfiguration(**args):
|
||||
return Element(qname = (TEXTNS,'notes-configuration'), **args)
|
||||
|
||||
def Number(**args):
|
||||
return Element(qname = (TEXTNS,'number'), **args)
|
||||
|
||||
def NumberedParagraph(**args):
|
||||
return Element(qname = (TEXTNS,'numbered-paragraph'), **args)
|
||||
|
||||
def ObjectCount(**args):
|
||||
return Element(qname = (TEXTNS,'object-count'), **args)
|
||||
|
||||
def ObjectIndex(**args):
|
||||
return Element(qname = (TEXTNS,'object-index'), **args)
|
||||
|
||||
def ObjectIndexEntryTemplate(**args):
|
||||
return Element(qname = (TEXTNS,'object-index-entry-template'), **args)
|
||||
|
||||
def ObjectIndexSource(**args):
|
||||
return Element(qname = (TEXTNS,'object-index-source'), **args)
|
||||
|
||||
def OutlineLevelStyle(**args):
|
||||
return Element(qname = (TEXTNS,'outline-level-style'), **args)
|
||||
|
||||
def OutlineStyle(**args):
|
||||
return Element(qname = (TEXTNS,'outline-style'), **args)
|
||||
|
||||
def P(**args):
|
||||
return Element(qname = (TEXTNS, 'p'), **args)
|
||||
|
||||
def Page(**args):
|
||||
return Element(qname = (TEXTNS,'page'), **args)
|
||||
|
||||
def PageContinuation(**args):
|
||||
return Element(qname = (TEXTNS,'page-continuation'), **args)
|
||||
|
||||
def PageCount(**args):
|
||||
return Element(qname = (TEXTNS,'page-count'), **args)
|
||||
|
||||
def PageNumber(**args):
|
||||
return Element(qname = (TEXTNS,'page-number'), **args)
|
||||
|
||||
def PageSequence(**args):
|
||||
return Element(qname = (TEXTNS,'page-sequence'), **args)
|
||||
|
||||
def PageVariableGet(**args):
|
||||
return Element(qname = (TEXTNS,'page-variable-get'), **args)
|
||||
|
||||
def PageVariableSet(**args):
|
||||
return Element(qname = (TEXTNS,'page-variable-set'), **args)
|
||||
|
||||
def ParagraphCount(**args):
|
||||
return Element(qname = (TEXTNS,'paragraph-count'), **args)
|
||||
|
||||
def Placeholder(**args):
|
||||
return Element(qname = (TEXTNS,'placeholder'), **args)
|
||||
|
||||
def PrintDate(**args):
|
||||
return Element(qname = (TEXTNS,'print-date'), **args)
|
||||
|
||||
def PrintTime(**args):
|
||||
return Element(qname = (TEXTNS,'print-time'), **args)
|
||||
|
||||
def PrintedBy(**args):
|
||||
return Element(qname = (TEXTNS,'printed-by'), **args)
|
||||
|
||||
def ReferenceMark(**args):
|
||||
return Element(qname = (TEXTNS,'reference-mark'), **args)
|
||||
|
||||
def ReferenceMarkEnd(**args):
|
||||
return Element(qname = (TEXTNS,'reference-mark-end'), **args)
|
||||
|
||||
def ReferenceMarkStart(**args):
|
||||
return Element(qname = (TEXTNS,'reference-mark-start'), **args)
|
||||
|
||||
def ReferenceRef(**args):
|
||||
return Element(qname = (TEXTNS,'reference-ref'), **args)
|
||||
|
||||
def Ruby(**args):
|
||||
return Element(qname = (TEXTNS,'ruby'), **args)
|
||||
|
||||
def RubyBase(**args):
|
||||
return Element(qname = (TEXTNS,'ruby-base'), **args)
|
||||
|
||||
def RubyText(**args):
|
||||
return Element(qname = (TEXTNS,'ruby-text'), **args)
|
||||
|
||||
def S(**args):
|
||||
return Element(qname = (TEXTNS,'s'), **args)
|
||||
|
||||
def Script(**args):
|
||||
return Element(qname = (TEXTNS,'script'), **args)
|
||||
|
||||
def Section(**args):
|
||||
return Element(qname = (TEXTNS,'section'), **args)
|
||||
|
||||
def SectionSource(**args):
|
||||
return Element(qname = (TEXTNS,'section-source'), **args)
|
||||
|
||||
def SenderCity(**args):
|
||||
return Element(qname = (TEXTNS,'sender-city'), **args)
|
||||
|
||||
def SenderCompany(**args):
|
||||
return Element(qname = (TEXTNS,'sender-company'), **args)
|
||||
|
||||
def SenderCountry(**args):
|
||||
return Element(qname = (TEXTNS,'sender-country'), **args)
|
||||
|
||||
def SenderEmail(**args):
|
||||
return Element(qname = (TEXTNS,'sender-email'), **args)
|
||||
|
||||
def SenderFax(**args):
|
||||
return Element(qname = (TEXTNS,'sender-fax'), **args)
|
||||
|
||||
def SenderFirstname(**args):
|
||||
return Element(qname = (TEXTNS,'sender-firstname'), **args)
|
||||
|
||||
def SenderInitials(**args):
|
||||
return Element(qname = (TEXTNS,'sender-initials'), **args)
|
||||
|
||||
def SenderLastname(**args):
|
||||
return Element(qname = (TEXTNS,'sender-lastname'), **args)
|
||||
|
||||
def SenderPhonePrivate(**args):
|
||||
return Element(qname = (TEXTNS,'sender-phone-private'), **args)
|
||||
|
||||
def SenderPhoneWork(**args):
|
||||
return Element(qname = (TEXTNS,'sender-phone-work'), **args)
|
||||
|
||||
def SenderPosition(**args):
|
||||
return Element(qname = (TEXTNS,'sender-position'), **args)
|
||||
|
||||
def SenderPostalCode(**args):
|
||||
return Element(qname = (TEXTNS,'sender-postal-code'), **args)
|
||||
|
||||
def SenderStateOrProvince(**args):
|
||||
return Element(qname = (TEXTNS,'sender-state-or-province'), **args)
|
||||
|
||||
def SenderStreet(**args):
|
||||
return Element(qname = (TEXTNS,'sender-street'), **args)
|
||||
|
||||
def SenderTitle(**args):
|
||||
return Element(qname = (TEXTNS,'sender-title'), **args)
|
||||
|
||||
def Sequence(**args):
|
||||
return Element(qname = (TEXTNS,'sequence'), **args)
|
||||
|
||||
def SequenceDecl(**args):
|
||||
return Element(qname = (TEXTNS,'sequence-decl'), **args)
|
||||
|
||||
def SequenceDecls(**args):
|
||||
return Element(qname = (TEXTNS,'sequence-decls'), **args)
|
||||
|
||||
def SequenceRef(**args):
|
||||
return Element(qname = (TEXTNS,'sequence-ref'), **args)
|
||||
|
||||
def SheetName(**args):
|
||||
return Element(qname = (TEXTNS,'sheet-name'), **args)
|
||||
|
||||
def SortKey(**args):
|
||||
return Element(qname = (TEXTNS,'sort-key'), **args)
|
||||
|
||||
def Span(**args):
|
||||
return Element(qname = (TEXTNS,'span'), **args)
|
||||
|
||||
def Subject(**args):
|
||||
return Element(qname = (TEXTNS,'subject'), **args)
|
||||
|
||||
def Tab(**args):
|
||||
return Element(qname = (TEXTNS,'tab'), **args)
|
||||
|
||||
def TableCount(**args):
|
||||
return Element(qname = (TEXTNS,'table-count'), **args)
|
||||
|
||||
def TableFormula(**args):
|
||||
return Element(qname = (TEXTNS,'table-formula'), **args)
|
||||
|
||||
def TableIndex(**args):
|
||||
return Element(qname = (TEXTNS,'table-index'), **args)
|
||||
|
||||
def TableIndexEntryTemplate(**args):
|
||||
return Element(qname = (TEXTNS,'table-index-entry-template'), **args)
|
||||
|
||||
def TableIndexSource(**args):
|
||||
return Element(qname = (TEXTNS,'table-index-source'), **args)
|
||||
|
||||
def TableOfContent(**args):
|
||||
return Element(qname = (TEXTNS,'table-of-content'), **args)
|
||||
|
||||
def TableOfContentEntryTemplate(**args):
|
||||
return Element(qname = (TEXTNS,'table-of-content-entry-template'), **args)
|
||||
|
||||
def TableOfContentSource(**args):
|
||||
return Element(qname = (TEXTNS,'table-of-content-source'), **args)
|
||||
|
||||
def TemplateName(**args):
|
||||
return Element(qname = (TEXTNS,'template-name'), **args)
|
||||
|
||||
def TextInput(**args):
|
||||
return Element(qname = (TEXTNS,'text-input'), **args)
|
||||
|
||||
def Time(**args):
|
||||
return Element(qname = (TEXTNS,'time'), **args)
|
||||
|
||||
def Title(**args):
|
||||
return Element(qname = (TEXTNS,'title'), **args)
|
||||
|
||||
def TocMark(**args):
|
||||
return Element(qname = (TEXTNS,'toc-mark'), **args)
|
||||
|
||||
def TocMarkEnd(**args):
|
||||
return Element(qname = (TEXTNS,'toc-mark-end'), **args)
|
||||
|
||||
def TocMarkStart(**args):
|
||||
return Element(qname = (TEXTNS,'toc-mark-start'), **args)
|
||||
|
||||
def TrackedChanges(**args):
|
||||
return Element(qname = (TEXTNS,'tracked-changes'), **args)
|
||||
|
||||
def UserDefined(**args):
|
||||
return Element(qname = (TEXTNS,'user-defined'), **args)
|
||||
|
||||
def UserFieldDecl(**args):
|
||||
return Element(qname = (TEXTNS,'user-field-decl'), **args)
|
||||
|
||||
def UserFieldDecls(**args):
|
||||
return Element(qname = (TEXTNS,'user-field-decls'), **args)
|
||||
|
||||
def UserFieldGet(**args):
|
||||
return Element(qname = (TEXTNS,'user-field-get'), **args)
|
||||
|
||||
def UserFieldInput(**args):
|
||||
return Element(qname = (TEXTNS,'user-field-input'), **args)
|
||||
|
||||
def UserIndex(**args):
|
||||
return Element(qname = (TEXTNS,'user-index'), **args)
|
||||
|
||||
def UserIndexEntryTemplate(**args):
|
||||
return Element(qname = (TEXTNS,'user-index-entry-template'), **args)
|
||||
|
||||
def UserIndexMark(**args):
|
||||
return Element(qname = (TEXTNS,'user-index-mark'), **args)
|
||||
|
||||
def UserIndexMarkEnd(**args):
|
||||
return Element(qname = (TEXTNS,'user-index-mark-end'), **args)
|
||||
|
||||
def UserIndexMarkStart(**args):
|
||||
return Element(qname = (TEXTNS,'user-index-mark-start'), **args)
|
||||
|
||||
def UserIndexSource(**args):
|
||||
return Element(qname = (TEXTNS,'user-index-source'), **args)
|
||||
|
||||
def VariableDecl(**args):
|
||||
return Element(qname = (TEXTNS,'variable-decl'), **args)
|
||||
|
||||
def VariableDecls(**args):
|
||||
return Element(qname = (TEXTNS,'variable-decls'), **args)
|
||||
|
||||
def VariableGet(**args):
|
||||
return Element(qname = (TEXTNS,'variable-get'), **args)
|
||||
|
||||
def VariableInput(**args):
|
||||
return Element(qname = (TEXTNS,'variable-input'), **args)
|
||||
|
||||
def VariableSet(**args):
|
||||
return Element(qname = (TEXTNS,'variable-set'), **args)
|
||||
|
||||
def WordCount(**args):
|
||||
return Element(qname = (TEXTNS,'word-count'), **args)
|
||||
|
427
src/odf/thumbnail.py
Normal file
427
src/odf/thumbnail.py
Normal file
@ -0,0 +1,427 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# This contains a 128x128 px thumbnail in PNG format
|
||||
# Taken from http://www.zwahlendesign.ch/en/node/20
|
||||
# openoffice_icons/openoffice_icons_linux/openoffice11.png
|
||||
# License: Freeware
|
||||
import base64
|
||||
|
||||
iconstr = """\
|
||||
iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAAG0OVFdAAAABGdBTUEAANbY1E9YMgAAABl0RVh0
|
||||
U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAFoHSURBVHjaYvz//z8DJQAggFhu3LiBU1JI
|
||||
SOiPmJgYM7IYUD0jMh8ggFhAhKamJuOHDx/+8fPz4zQsMTGRYf78+RjiAAHEBCJOnTr1HZvmN2/e
|
||||
MDAyQiycOXMmw5MnTxhmzZoViqwGIIAYrl+/DqKM/6OBNWvWgOmvX7/+37Rp0/8jR478//fv3/+f
|
||||
P3/+h+phPHHixH+AAIK75D8WMGnSpP8vXrz4//v37/9///6Fi4MMALruf3Bw8H+AAAJp5rQrOoeh
|
||||
edmyZWAbgd77f/bsWTAbBoB6JOpbmkF0OkAAgcLgO8gUYCCCnSIlJQWmw8LCGA4cOAAOAyMjI3hY
|
||||
gMDvP7+f3791+weQuQAggGBi7FPmrvnf3NwMtgnkt/Xr1//fuXMn2EaQ5TB89+nX/wUlJSDbPUFe
|
||||
AQgguKleiY2/QIpBTv727TuKJhB+//nf/xtP/4ANrK6tBRnAATIAIICQEwUjUCHIoyjOBYGbz/8y
|
||||
8HMwMXCzfmcoLC1kMDH3YNDU1mGQ4PvLCBBALEjq/t958Zfh0dt/DL/+MDD8BdkBNIeXnYFBhIeR
|
||||
4efffwybNqxgEOEXZLjw25Xh2QMWhmi9BwwAAYRsAMO5268ZZMREGGSEGBmYgcEL1MMAcgwo3D9/
|
||||
+sIwf84cBhHLGoYAVVYGxi/3wDYABBCKU6dPn37s1vM//3/+/v//20+gn5/9+b/7yq//iw++/6+o
|
||||
qAhy0zUg1gH5HYYBAgg99Srsvvzz//6Tt//beSf+V/doBGkqheaFL0CKF1kzCAMEECOWfAMSY3Yq
|
||||
PvF7X68FKCcCPcLAA8QqQHwB3VaAAGKktDwACCCc5QETE5ODjIzMfi4uLoRtjIwiQBe8RVYHEEDg
|
||||
WODh4dkBTMLuQE1YDdPR0WG4cuUKw6tXr968ffsWxdsAAQTWAbQJq+aenh5wogJpBpUNzMzMGGoA
|
||||
AggckshZFRmA8sXz58/BeQKY2WA5kRmkp7Oz8z8vL+8WgAACG3Lv3j0Mze/fvwcpBuaLb/9//foF
|
||||
FweG2U9dXV2RixcvguTNAAKIAVQWaPt2oGgGlT4gzSBDNm/e/P/jx48o8n/+/PlraWkJil5OgAAC
|
||||
OUDEKvsgWOLdu3f/k5KSwOxPnz79nzt3LrgIQwY/fvz4X1FbDbIgAOQVgAACxcIbFnZesFcEBQXB
|
||||
AbdhwwYGNjY2BmdnZzANSypffvxn4OFgY/j5+TvI9i0gMYAAgkUJI7Dc+/flyxeGly9fMaipqWEE
|
||||
9m1gTv329RvDjAmVDE52dgx6enpgvQABBIu7//fvPwCmB14Mze+//geXBwKcTAwn9q9kEOIXYNC2
|
||||
8IfLAwQQcqIIOHPv9/o3X/4z/PkLzABAR7KyQMoCPi5Ghm9fvjJM7i5lUDbwYXjI4sIwK41LHBgG
|
||||
rwACCLk82Pvq038GaQEmBi52iAEwK/4BDbx7cTeDEB8/w42/TgwhRt8ZzNeeeAHyAUAAoSTL15/+
|
||||
/f/++z+DrBATw/P3/xgeAkunt5//MSzYcpOhJYyNQUNDowGorA9o82eYHoAAQjFgw6kv/yV4/zLc
|
||||
v3WRoaRxBoOEtj/D2cXhPECNAcAExAbUiFE5AgQQenkAis/PrkWH/u/us3MGsvdBxYOAeD3QAIy8
|
||||
DxBAjNiKJXIAqIZ//PjxYT4+PmtgHmEAJjiGhw8fMhLSBxBALIQUcHBw1AINbAIZCkqUuABywQZM
|
||||
kwzAnMBw//79TcCy2A+f+QABBA4BoOuZHj169FdWVpYs3wPzKoOAgACKI0BsYCnDwMrKyg204xsu
|
||||
vQABxAQtkv6FhISUEmuho6Mjw9OnT+F8UNsIWHQxAMsChtOnT4PaSwzAVglYDBgNX9H129raci8C
|
||||
AhAbIICQkTCoACEWgAoVDw8PcKl17Nix/ydPnvx//vz5/9jMAKqRh9Vi9fX1YLHe3l6QuD1AAMEs
|
||||
ZwUVi6s37CTK8t27d4MtBrW7QPj169f/79y58x+YCDFKP1jJCIruurq6VyC+t4/Pf2DUgAozSYAA
|
||||
Atvu4Wm5D+QA47hVoLIWwwBQsVpaWgq2FIRVVVX/gxp427dv/79kyZL/Fy5cAIcIPrBh/QZwtZOS
|
||||
mvoXmLDngDIOKEQAAgg5CmLsis7+v3XrFlgDyAJIWoIAkM+A8Q5ufYEqidmzZ4Md8PnzZxzVGQSD
|
||||
wN79+8F0ekb6X2C92AyqRmFRAhBA6PnUVtuv99CVjUXwlAysicEKQZUuKJcAm/7AlM0GrmyBwYi9
|
||||
ogWa+hYY6m+AxeDPt9cY9PV0GSoqKxjef/jGMGvGZGmgec9gSgECCFtBofvu3ftLoJQNjFuwI0RF
|
||||
RRlwNRkQbQ4Ghmfv/jF8BlZaoKDjAzYnb1w4wHDx+lWG98A66s27zwwVZUUM8vJyakAH3IbpAwgg
|
||||
rCXVxo2bnvr5+Ur9+w+pFX78+s/w8w+kvQnyMCsQs7GAeIwM91//A6r5z8DLAQwRFmDVwwnUA1R6
|
||||
4uhBhl0H9jG8efacgZldgCE4Pp+BiUuc4fTNLwyVwUJMsGIZIIBwFZUam89+u84GrND+QZMeKQ04
|
||||
acYbDGs3bWR4B/T5kbtcDLouWQycvKLgqp0FGJBGghdu2mgLaoDUAgQQrqL4BjOw/augogGuXNnZ
|
||||
GBn4OUG+Y2RgY4W2l7//Bwb3P2BpB2oGMjKwMDMy3ARW+5nRbgwB7hYMTk5ODIVdWxmiQp0Yvj5b
|
||||
9qy1uHIn0NyroH4dyHxYDgAIIHyVhdvzd392vvj4nwGYdhi+AKOBGdpY//vvDwPr348MX94+BVed
|
||||
fTPXMry4tm02qMbLzs7eBmynrwOWgsuA/G1Ai77jCy2AAMLnAM75S1a/SIwJ3QTqpoAEzFO3N7Nx
|
||||
CTEwMrMycN8qvLB9y8FAoPADmFna2tp/rl69mglyCKh9QExNCxBAjCTWOxKg+h6Iv2KRAzXDxYD4
|
||||
ORD/ROoG4wUAAURx/4BSABBAeMcbSAHA4jUF2M2YDWo3sLOzM0ybNi0SmBBXENIHEEAkt4hALR9g
|
||||
FTsX2PJJBFrIwMKCPSMB2xcMwI4BwSgGCCC8LSJgBSMtLi5+AGiRCsgyUPFLTJRt3bqVwdXVFRQS
|
||||
oK7MX3xqAQII7gCgTyKBrZplIIuAwUlyFADbAwwWFhZgB3p7e8OEZYD4IT59AAEEGzKyBuVb9CEC
|
||||
YsHy5csZysvLUUIH1Bq6du3aLdBACD69AAEEC4GXwHYAuHYjFqxevZph3bp1DCtWrACH2Pfv38EO
|
||||
AHWQgFU0OLqEhYXZQM00fAAggGBV3DPYeA8hAEq0SkpKDKGhoWCfgywFWQ7shTLcvXuXAdjzBLeI
|
||||
QVEpIiICCl1hdDMWLFiwCtirBdsNEEDwEQdgcBFsih08eBCFD2qOgTqloEYMaIwJmPjATTPkLvG2
|
||||
bds2IY9sAHt/6rDhNFAAAAQQ3FWtra1biW2Qgjrvly5dAteTwP422HJQo/TBgwcYTTpgg+Y/zHIX
|
||||
FxdWYGj9P3fu3H9g6LwHNYQBAgil8kEel8NneXp6OthyUF8e1H8HNddAoYGtPQlSD+3LM2ZmZoLF
|
||||
Nm7c+B86XMcLEEBgmw10JazMUrYSbFiC23VQy0EhABreACa6/8BCBxz0oEEFbJ4ANmiDgXoEQOyG
|
||||
1tb/VlZWIDNAvWxGgABiSSqseXiHMUju359fDEADGCQkJHAmwJUrV4LbiKDEBeyxgjodDLdv3wY3
|
||||
19TV1Rm4ubkZsGXlnJycNdpa2vfAQwXAtAbsP2wEMu+AWkUAAQQSkwU1yUH4ypUrGK4HKQImJHiT
|
||||
HIRBiezy5cvgJjko4b18+fI/vugDhdK/P//+VTfU/09ISACNliaCogWULgACCJQVHp+aYtQEToiz
|
||||
9qK4fP/+/aBsBC5WQdkNVLiAshtoCBqU3Tg5ORmMjY3BjVZ8hdiZM2eBbQhGxhdPnv4DOrofZDSs
|
||||
oQIQQOC8+OMXQw+IvvaSB16axcTEMJiYmID5oKY3KG/fvHmTAZjwwMUuyCGgQTRcloOMAeFPX34A
|
||||
+4I2DKWVlUA9P38DE+oRoDS8YwkQQLCS8POhPiNfi/Rdm0H9ehUVFXjnE2QRsMvFAExkDF+/fgWX
|
||||
lqAmu4KCArifAIp/XPXTm8//GW5dPs9gbW3JwAxUtGL5ik7ooOVvmBqAAEKuDXfwcLIwvH37Fm45
|
||||
MHuBfQ2MY3DilJSUZIDUikxgi5EHsVC668DAffcF2Ef4/BVseU5hAYMwjyBo3ABUN7xEVgsQQMi9
|
||||
jT97JjgZvHkDGc8E9e1BdfqPHz8Z9PUNGLS1QcEtBox3LnDZj2uw4hWwEfvyw1+G38B+BOsviEcE
|
||||
efkYXgNzGLC/0Qn0/R9k9QABhN7duTRn/pyPIF/9/PkLWJ9zAC3WBscz1i4YUsPy0zfIAPuHb//A
|
||||
vSRulh8MZ8+dY4iMjWX49/cfg6OjHYORiYU0ul6AAMKWdAP+/v23HpT4YAmQEHj05h/Dj9//wRYL
|
||||
8zCBHXTs4DaG81cuM7x98YLh229mhqjEPAZpaRkGNSkWPuRhMoAAwtbhOwmKe2ZmYDwDLf8G7A98
|
||||
+g7qG/wHxi2w5gPy//6HWPYOmMhuPvsL7raJAC2WFmQGdlCAXTfGbwzPgenm0YMHQHNYGGxsHRg+
|
||||
M4kz3H71jyGlbGoOsmUAAYStSfbm3M3XDAIiUkAL/zF8+8nI8PM3pMMJshSMQcPGTJA+IiewCcEJ
|
||||
7Dm9AAYzGzNktuHZrdMMt+7eYeAA9qKffGBmEPinx3DkNNDRTH8Yfoh4tAHzVjvMMoAAwhYCv6/f
|
||||
f/Xv6XtgKgam5j/AugTUMQZZyMSImKwAWfQdmJnefQM1Jv6D50zuAH14/fFnBhU1VYY3r18y8PHx
|
||||
M3zms2F4/EUEaDmk06ogKw4q3OAeBwggrI3SnprEqgnLz3aAesCgXi8fEIPLGuiEDIyJngVBFZ+l
|
||||
jgLDbWCZIcgrwLDj4l8GbSdDBi52JgZ3/f8M74FZ/O2rZ7C2IrhHBRBAWB1w89rlAwrC0PAGdXlY
|
||||
GRmE+BjBQQ0S+v7zP8MvoO+/AtPDDyAN6jPyczEyHLryHjyC9ub1awZhUQkGHVZRBnOJ2wzt5Zbb
|
||||
Jj55AuqYngXlNOSSECCAcBXgou8/fnn16RcneGxAQpAJHBKgIASNmoMGgD8AE+QXYBR9A6aPP7//
|
||||
MGw69prh8e1zDOZCFxiAjRSGkJCQbaD5JKilr9HzPwwABBAuBzBdu3n/LwuvLDCOgTng639wnP+D
|
||||
TFcC8Q+Gv19fMnx5/5yhu386w9kDK0CWzAE269k3bdo0wc7ODlTkggai7mIbH0YGAAGEq2Py7/jl
|
||||
J98klKW5+Dj+MvAxfWJ4+/opw707VxnaJq1g4BRUYOCT1GWQF3z9G2i5JdSXjOvXr/8HtXwZMZaD
|
||||
AEAA4esIRLu7e+bu3Ln9JJB9xSh2+SwOPikG2AQHsPIKh3bDwRULsGiWB9aeB48dOxYH5B4FZRRi
|
||||
un0AAYTPAWxQ+Z9Qvg2w0XIYaDGo6gb58g2aen0gVgXiXaCSmdjuOUAAkdIVAqlVBjWlcMhLgio0
|
||||
qMP+E+sAgACi2nwBLQGoRw7se7gCO7uJwHZnBLBNyobcpqAEAAQQy0B6DNjkUAR6KAnYvIgFpWFQ
|
||||
EwM0tgEackBu5SH3eUHNlNOnT98GBgpovPMXpW4ACCAWWsQWsPUYB/RIPNBjjjBPgVqShAZ7iQGg
|
||||
1omysrK8lpaWJpB7kVLzAAKI6CwA9IAlECcBPRMDxBwgj4EwrgEiagDQnHdRURHD4sWLGbq7uxlK
|
||||
Skrgcvfv3weNEaA0rcgBAAEEDwBQzC1cuNDO39//AB8fHwO5QzUUZgmG3t5ehoqKCnCyB3UPQHMT
|
||||
2ABoQGTt2rU9sbGxZcTUN7gAQACxII26/AcGwndQgIACgB4A5MEHwDbrt2/fGC5cuMCQl5cHbkb8
|
||||
g89aI8oAkBhoCAuEQWxQdrK1tQUlCVA38xm5bgAIIPRMeX/Xrl0HQQ6iNgD1Ljdu3Ahf2hQVFQVO
|
||||
xvr6+iCPMOTm5oI9eunSJUgHDehR0Fjb8+fPwaMP165dA9MgPkgclFrExMRAXeRjwIhjJdddAAGE
|
||||
UgYADQL1f1yBsbJdTk6OKtkAlH+zs7PBMY0rOYNiFIRBngIFFMiDoNQBKgNAM+CgIRfQcAxIP6hX
|
||||
DCp7YAUqaDjHxsbGAJgdLuIrmC0tLa+tXLlSA2Tew4cP/8bFxXE9efLkH0AAYRSCQMWKBw8ePG9h
|
||||
YcGPb5qeGIBtZRhsNh00/gByfG1tLcPSpUvBMd7f389gaGgIlgOpA2VF0HAAqFMMWo6Eq3967949
|
||||
UM2AtUD08vLiAeK7QHvEQOtjgCmcAeh50Ey/FjDQHwIEEDbzuCQlJVNB403UBKCRPNDYZEZGxn9g
|
||||
coePc7W0tPwHDc6C1iEBYwS8aAlkN2jgFbT+CNuQIzoAqQOmtG5YioZGKouTk9NP0FgodNnR/zlz
|
||||
5vzfsWPHf2Dq6QOldCAWAQggbM1NXv9Q/9OggTpcq6tIBaAx1Pz8/P8bNmyAexxkPmjFJmzBJciB
|
||||
oOFR0BQ4aMUWSA/IYyB5YsZtQdPpoKk0qOfZHBwcnoNGob/+/P5/2owZ/1tbW/8fPXoUZn8CA2Rp
|
||||
HStAADFCPS0UXTbt3uM/FuDi/8+PTwzavNcYeqqiKa4ROjo6wENtoDF9cHe7p4ehsLAQnMRBox+g
|
||||
/A5aeAIa+wMlfVAyB+VzUHIF2Q0agCSmrQHKVsCa5AGwR6QBbKeI37x585S8vLz49bt3GKrLKxiE
|
||||
geYBszaoIAWtGQCtKboIDKz3AAEEMhlUglrCPA9OOxy8DCfvsYCn7EFTb8QWhiALlixZAsqP4NId
|
||||
BCorK1GW9IAKO1DeB40zg0p0EBvkeJA9oPwuLi4OXoUDaj0SMyaF3EJUVFRUAJZhFgcOHlwtBiw4
|
||||
rty6yVBXVc1gaW7+e+bMmX/v3r3bC+0qgpZ1fgTpAwggRqT2gI1D0en9/xgglv78/JIhy/kPQ5i/
|
||||
C96JM1DVBmrmIk2OMVhbWzP4+vqCqylQTIPqeGDeZ5CWlmZ49uwZeGAdFLigwACV7KAaB7QaGDTo
|
||||
CjKLnNoHZA9oDJWNg51BSECQ4cLVqwz1wALWztr61+zZs/8CU0QtdLIe5Pn3oNVKIH0AAcSI1iYw
|
||||
DClZfOLVP22Wf39/Mby7e4hh98xo+FJlGAAtS9q5cydDQkICQ1JSEsPcuXMxqjVQqQ6q0kDJHJS0
|
||||
QUkd5GlQAIDm0UClOmh0GTTKDKriQDFOnsch9j14cB8YgIJAs4QYTl04z9Bc38BgbWnxa+HCRb9u
|
||||
3LhRCvU8qCv9GbnlCBBAjFgKQZXo9MwDj7lTpb69vccwr1gNPEkAyoegUAbFKmhcHjR5gJ4HQR4F
|
||||
5WVQsgZNEILYoCYrKOmD5EGBAqveQLEOzKPgFIArqROaFgbJv//yl+E2MKmrK0sByw0BhqOnTjK0
|
||||
tbQymJub/dm6ecvXUydPlgGVnoZ6/gt6sxkggHAFuZStrfb0f/oz/ER/n2GY1x4PLpSAfQWG+Ph4
|
||||
lGQHimVQIQZqtIBiGDSHAAKgGAU1YEAxDcpCIE+CYhjUgIHI8eCt23EtDQItGP/4DTRI9h/o+X8M
|
||||
j+9fY7AxVgWaxcmw/8gRhq72dgYfbx+GbVu3MWzbtiULmudB81NfsfUZAAIIX5oDNdviDCLm969s
|
||||
tGJQVVVFSaIgj4Nmd0GFGSjGQYEBKshAMcrLCym9YV1gSlqUIK0/gb3+Lz//M4DWp3798R+ezR7e
|
||||
vshgZ64N9vzOffsYJgA7UmGh4cDGzg4GNQ19hlUrFmfcuH51KS7PgwBAABFyGTdotqp76vIZWQl+
|
||||
DLDF4aA5E5CnQRjkEJDHQSU3SJ4a3WOQp0EDvp+BMf3l5z8wm4kRkez//vvL8PzueQZBXlaGA0eP
|
||||
APM+L8OqlasZEmPjGLZs3sygq2/IYGRmy8DPx8NgYaIjBKrucNkFEEDERA1oPX7Z06fPakEzVKCY
|
||||
BuVpUOEGHY2k2mDHT6BHQTMhn779g+yLgI3GM0JWwoGG6n//Bub5GxeAofCDYdf+feAIuHDmLIOn
|
||||
pwfDWSCtpaPHYGRqzSAjr8bwl4GN4cal4/uC/ZxdYaU+OgAIIGKiC7SbYQ0wf9eCCkBQnoUNhmAL
|
||||
TZiDiVmKBFL3DZi8P4Cm84Aeh818gD3MCfEwaECcA9hS4WJnZPj2/Q/DjZvnGVgY/zFs2buH4dfv
|
||||
XwwXz55jcHJwZLh46QaDpJIeg4qOLYOEHNDzzFwMX4Fm/+RRd4LORTzC5gaAACI2c/L7+fnX9U+Z
|
||||
W8TOLcjw4w+ou/of4mFGREiCVheCkuq//4jQ+AddrffnH2Q66ecfyLJDYIUAXob4H+pvUALi4WAE
|
||||
eg6Y74CeZwZng/8MXGyM4MV77z7/YTh/9igDO8tfhv2HD4Gr1XvA7rGRgSHDk2cvGIRkdBgUtKwY
|
||||
FJWUGV594WC49OgfUA/QTqb/DNy/b3+fmGcgCEwFP9E9BhBApJROVnM3Xz0qLq0CXiXIiJQn/xNZ
|
||||
bRGq0hiQZp1AAQlis4Irib8MX5+cAmaDfwyHjh4GN3hePX/BoKWpxXDl9nMGRkEDBhZxCwZeEQUG
|
||||
VnYuFHMFuBgZXr37yHB6frD1mmVzjqHbCxBApJRYd989vnRDSFRagxVY2KE7GBTTyEkfFOuw/QxM
|
||||
0Lk1ZmhJxsQEmnAEBiJUzz/QfA+QAZoLBPFBMQ5SCp4P+veHYd/ayQyeThYMf5mYwY2mA3v3MTjY
|
||||
2TOsP/yYQVDWhEFc0pyBT0SRgZmVA6wXZIacMCODtjwzMACAfY5ffAy2SvOOamqqg1IBysIkgAAi
|
||||
JQWAAstj54n7m+VlpRkYgWkWFDl//6PGPCz1w1begqZsQetLQROczEAT/v+DrEVlBq3EBQYEKIBA
|
||||
+kFiIDlQVmAH5oPfQPY3YPE/d/kOhsnNmQx1dXVg80FtClC12j5nP4OIgjmDsLwZg7aaNIOGFNCQ
|
||||
318Yvnz9zPDtyycG1l8vv+/duvzaxg3rQas+QbUAaHpwKzAAUMoCgAAiJQWAZl1u/Pr8+g8zgySL
|
||||
IBczMK8ygh0LCvHfwJAANVJAc9pfvjFA5rGheZyXG6IOtCKNm50RkufBSZwRHDi//oECCVHPP3r3
|
||||
n+HOiz8MB84+Z1hbG85QX18H7iGCWqCgwY/mrml/OX99eHp40XzwXOcGYOucAbJi9DFopQJ0dgg0
|
||||
PQVqlf3CN2gKEECkVtrPw/0ds05cuDdLUkiUgYMFMl0MSqqgCdsvPyHzp8CaiuEbkA2a0P/5F5Sk
|
||||
/4HV/IUmedA8J0iM4T+wifz7BzDGvjB8+/aJ4dzNTwzs/94zPDm/+sW61YtBnvsI7G+EgjwOnnzT
|
||||
198DigRo6w7UvH1M6eQIQACRGgBfv337eu78rZcMz77xAz3EBE7qoOQNbqBAS3w2pn/A0vwPA/P/
|
||||
XwzMwGT5++snhi/AfsGfH58ZDhw6yrB+x3Fgl5uPgZVTgIGVS5iB+/3Gu5cu3JwH9RhoNQson7J2
|
||||
dnbeBdXzISEhi4HtjtfQadhz0Jj+RslwOAwABBA5zbYH146t26wYmuoL9D445j59+szw68fn/6eO
|
||||
7Hy6ceMG4R9cepwsQM+BVlqz80owsHELAz0rCB5nYGb1YNDx8WDY32cFmmXdDp2yfwdJF4iZ2ebm
|
||||
5sfAzpNQbW1tFTAQQJ6/AO3QgJL2P2rNaQIEECOZekBp0hwaU8+hee49NM8JGBrId/E6rY9Cnbo9
|
||||
9mtlX04xkAlarXWbAfsKcGjjkq0F2NfwgY75g8y/Ah37/4U0j0GVAAAIIFpN/4A6UmG+gS6pm9fv
|
||||
6YT2xZ/CJvMJuIcX2nKTgMb2I2gKQVljQa0AAAgg+s9/EZctWaBu+w1uBWHZQkKtAAAIoAHfPzDQ
|
||||
ACCAqLZ/gZYA2PsUAbYDkoGNoOi/f/+elJWVTaNGDQACAAHEMtg8C+xtGgMLQdCiiRggzQcaPUKe
|
||||
hn/06JEukCqE9lIpBgABNGABAJqvu3v3biDQcwlAT/rCutggjG+YDDTSxABZ8U6VAAAIILoEwMeP
|
||||
H/nExMSSgZ6LA8asAciToAFUEE3qcBmoSbx48eIcYACWUSMbAAQQ1QOAiYlJFxijoJUksUAsDPIk
|
||||
aGaIWitJQJ0hU1PTPCAT1Dv6Tql5AAHEQkkSvnPnjjfQk6AkHAwaFoPlV1JGeokFt27dAk+ogNbw
|
||||
8/Lygoaj+KkRAAABxEJkEmYXFRVNAXouHpgHTSlJwqQA0CYl0KoRkB2ghROwgxdAg7DA7rEDkLmC
|
||||
UjsAAgjbIil1oCfBSRjoQUlYrJKyu4oSAJo8aWxsZGhpaQHzQVsI0GemQJMs58+ffwjMCqqUrhcE
|
||||
CCAWpCTNAUxi30GW0XLlFz6wY8cOhm3btjFMnjwZfMzSvHnzcFWVoBkqeSATNKH7lhI7AQII2aeg
|
||||
c2zuiYuLKw1EAGzZsoVh1apV4CU1oO0xoAlW7GOHkAVToDkIYKTJUhoAAAGE7NPfu3fvPmphYaEE
|
||||
Svb0SOqgPX+g6TRQeQKaaAWtCwJNnoLmH5ABbP0QSA+IBgFQluzs7GwGBkIgrsXoxACAAEJeJwjy
|
||||
tT/QASvRHUBNcOLECXCBBtqLtGfPHlBehssdP34cvBcVOa8jzzCDAgB2lgGoOgTNUqurq/MD/fCJ
|
||||
XPcABBByCgD1tV+AJjexLW6iFID6HKBtp9XV1eApcdBiSBCGrRwDeRQ22QKKcdDsE8gtoKl0EA3b
|
||||
5gqbbAWxoatXBKHdZrIAQAAxIXUvQa2qt6CQhiUzagHQMlfQFDtkp9l/8PrA9PR0lGVzMM+D7AZN
|
||||
qYNmm0H79EAYNgcJagaDWoKgQACpBwUAtFVIMLaAhWrUokWLDgL9aY4sDhBA6BN6H65evXoLFPrU
|
||||
AqB1AKB1AiCPg2IcW6EGS+ogj4PUgiY+QB4H0aDkD/KwsLAwGIM8DZtuBwUItFWId+93dHS0eEBA
|
||||
wJKmpiY7QUHBE8AI2QvN9kwAAYRe3H8BFoR73N3d1aCdDoqAoqIieAceNgAr1JDzOCibwM4mAk19
|
||||
gWIZ5GnQuiHQ8hlQ4Yw8CQvKpoRahaBNUubm5mdiY2MZQakIlJ02bNjgAKxiQWXeL4AAQk8B3+fO
|
||||
nbsXtsiBEgDyFCipowOQI0ByoJjetGkTfAuqm5sbOGa/gIfIv4E9C5qMBRXIoKwCksM2Aw0KsNLS
|
||||
UmtczfWqqqrslJQUGVD75syZM+B5BWCqew1tQzABBBC2ITJr0M5wYtbmkQpAawFBB/2ATjg0NDSE
|
||||
rxlcunTpf2ANAN4MDtoUfvr0afDiSdCCSdAebXxuAZkJVP8AVDOiHebH6Ojo+AHoafiud9CJksAs
|
||||
AFooCVrmAtrfww4QQOhZAFwQghYoApMoIzUbRKDkfvToUXBDB9S8BVV/oGwG2g8Mil3kTRWwKXhY
|
||||
aY+vRsLWKgTFPDD7cTo5OfGDVp/DaiGQWba2tn+AKQ+U/ME9NoAAwubDj2fPnr2sqqqqR60AAOX3
|
||||
9vZ2sOdA+5FB63VBHZu9e/eCCzjYNhnYchpYNUxsVQzKBlpaWjJIrUIWYEx/Bq1MBwUkyP5jx46B
|
||||
p9aAnmeBDuGDlsT/BQggJiztAuH1R1/pggoiaoH6+npwPgYGLNjzoCoRdAoYKO+DCjdQSgB5HpRK
|
||||
QDUBqAyANXyIGbQFLcbq6ekBtQqZQbEvIiIiYGVlxQQKmMvA7NDX1wcuT0CbMYABAjpXCzR/CFpY
|
||||
/RcggFiQ8j5/aknt6Rt//FTu3z8CdgRoZRilDSLQSnBQSQ7y2Pr168GrQUHJH5a6QJ4EeRbmaVBs
|
||||
geRAKQPkMWJSISiWgS1CXwbI0To/gO0GXmDT+j+wgGW8AWxunwQWfpcvXwY3xIDgALTh9BPU9gEI
|
||||
IJDp7EH+phFvlGcuuAk6ahQ0t8clzECNmgA2fg/q2Hh5eYH5oPodFKiw2AbVBqDVZqDSH9bYAaUK
|
||||
UN6GLa0jNhtAW4VvJ06cuFNbWxs01cYMOnOEA5j3QRsugI2obUB73kHHE8GNHYAAAmUBaZDnUfIB
|
||||
Bx94Cz65LULQ5ghQzIMKPNCZlTDPg8RBHgJVg6DWHSgwQNUSqK0AW2oHinVQYweUAkhZfAVqIQJb
|
||||
ernAVMsbHh7OCyxAmUELpa8A+x3A5P8PtBwf6HnQ/CJoiu0jdMKFASCAQKb/lf4w4S5KALDzMGw/
|
||||
fBW+EozYer+hoQG8Ehy0aBpU74I6PKBDtkAAtBECtDQW1swFDW+B2gmgDg2oMQTyAKjBA8qroBQA
|
||||
a+2RMlYITPJ5EydOOAEMBNAJUwwrli1nEOTn//fu3bs/wOy1kgFywM8TBshyWfBkLEAAgQLg+fJ5
|
||||
i3JR2sesHAz7zr5kILYgBK0g3b59O7hkB7YkwV1bkMeBTU+4GlAfH2QeqMsLqglAGLScFhTDoGUv
|
||||
MjIy4PIBFPsUDLWxOTu78gMDjvEysNq7dOECg6aGxl9gO+EfMOBBjQNQRIMaQfCYBQggFmgv8Pyz
|
||||
DS6zpAL2pIEDgJmd4c03SKsMVHrjcgwoX4GWvIPorq4usBjIE5mZmaATVcHJGORh0EgPKDZh/X1Q
|
||||
OwBkNii/g2Ic5HlQjQDikzugCuq/fPzwkUFdQ1UAHPvAvC8iJPQPWPiBlsnPYoCsOwC1yz8hrxkE
|
||||
CCBYEfv6zr13C1UY36d9+w8s+ZmYGVi5BOEnJWELAFCMgo75ADYzwckX1MgBVj1YOzqgAAGtJwZ1
|
||||
bkBJHtTFBeVvUMyDltCDaEo8D1sqr6yizMDMxMpw7vIlcOzb29r8mT17zl9g9gR5/h567IMAQADB
|
||||
ShhQgXBtR69zFkyClYOf4cWrd+DSGh2A8jiwcwH2PGgrG8hDyJ6HrRwHeRoU6yBPg2IelFpAYqAA
|
||||
BVWxoHY+yPOkLppG9Tyk/Ll29TqDsAjkAKmVK1YyiAMLvqtXroEKvwnQvA9aZ4CxZhgggJCLWFDJ
|
||||
eEjm/x5w/cfMxg0sCG+ACyhkADpHy8HBgcHPzw8c8qBJD2SPg1INqFoDeRZ24hBoTB9U2oOGv0Dm
|
||||
gTwMSvIgz4NKfWI9Dzsi5z/SyrT///8xXL/1kMHU3BQY+8wMJ4CNravAOl9ZSfnP8RPHvgMjELSc
|
||||
5inUfxixCRBALGj9gPvL+ssS7YrOrQKtudt//jVDMbCBAkriIABqURUXF4M9BurnIydB2AgOyPOg
|
||||
wg1UrYH4oNhB3vEJ8jyoXAF5HlR342vo4GsEgpfZAhPzu4/ArvOHVwyCupA5g1WrVgIbRSpANz74
|
||||
//DhoxkMkPVEoKSPdU0RQACh2w5qH58SfFh56p1cq9kPBl5wCw12YhrI8+hNU1CsgzwJ2zMASvKg
|
||||
LAEbVIHtG4DV56DqChT7sH1BsPKFlGUKoMWQn779B680u3HrDoO5oQHYnIPA9v6N6zcYXBwdGRYt
|
||||
XPgVmA3vI8U+1kYNQABhC/5nG9furLIrat8DWtgEC4CAgACsngfJg2IctG8AFPuwsT1QXQ7yOKhw
|
||||
Q97pCRvXA22YAJ2LRIrHQWEFOlEEVCyBzlB59/E7gxDXX1grkGHdmjUMOsB+xof3HxiuXr26HFrn
|
||||
g2L/O66JVIAAwnqUDRBfvrnYsg/UInzw+BU4NkE9N3TPg5I4bPcXyPOwOh20FQa0cww0IgTZECUN
|
||||
LPCkwBh0JhPoiBtS6nrwThGgq95+hhwm9OYr6Iyfvwyvnt6GT5ftPngAWN7cAtqpwHDrzi2GiKhY
|
||||
FwbIAspPuGIfBAACCFc78+3L1z9XiLC//rfj6C2MghCUl0GFHSjmQUkeVOKDyglQlQYa8QUdmwTy
|
||||
KD+/ADimQakAlPRh/X70EyLwl3yQWActp38P9DhoPwFI56+fPxhkRDmA9nKDlW1Yt57B2MgE2MZ4
|
||||
wSAkLMVgaGyuDh0m+4FvGh0ggHAFACjEbm6bmph18OI7BuTd5LB9QqB8Dsr3oMAQEBAEexoUw4KC
|
||||
QuCkT+kmCvDxLX8g55KB8vubL5DVprDU9+zBTQZFYGCDwLbdu8C1jaqyCrBtcoNBQU6KQUddEWYM
|
||||
3g4NQADhcyGov3xY7P+5j7ByAGL5P/BpX9+//wB6kBnsYVC7H1SwgVIBufv+0D3/Hhjm7z//Y3gH
|
||||
Su7Qw7pALgDvRfj7k4HpzzuGNevXMazZuJFhy6bNDJampuC+B6htISElx8AvJscwceLkIEJ2AQQQ
|
||||
E/7Ex3Bvz+bV9aA9Qoj6F3LSGMijoJIc1JSFleiUbpuB7QoDndX0DohBB4jBAgTkcdDaZEHO/wwf
|
||||
XtwB2ivOcA/Yuzx//hywN/kQmPUUge2N2wzSMrIMmmoKDGqKUgzWdk7VDJDzgHACgAAiNNoA6g2d
|
||||
BvbZ/wGTHRMs78ImJUB8ap0jAj4DEJTXf/4H7xBjZEDsPwB5nIcTkqq+ASv/r5/fMVy78YiBA1i2
|
||||
3Lt7l0FPW5fhDpCWkBRnkJFVYmDlFmf4+IMDWKfzgsb2QX2Dl7jsBQggYqLs/smTJ27Beoaw4/xA
|
||||
+RxUqFHqefAOMWAZ+/LTf4ZXwFj/CvU8eA8B0OMivEwM3KCTvEBVKPM/hif3L4PPtr4PbIx9/gRs
|
||||
agNbl5Cjyd8x8AnLMnAKyDL8ZeEHNvmYGPh4eBk8fYK08dkPEEDEBMCn/Pz86aBSHzYZARutwZXk
|
||||
GdFoXB4HD0EDC7kXH4DJHZjX/0G334D2FIE8DtpDBB7t4WIEn5cGKndAVfI9YJJnBAbC08dPGJSA
|
||||
SR80qvSHkZNBXFoR2BsVB3qcA1hjABsBn9kZotPK5iGfIIcOAAKImOgD+fwmrCBkgm57+Qvd3QGq
|
||||
n3/9hZQN4H4T1GNMDBB5kEdBu0ZA2yQgZ7RDxL8CExSogANtkGCEbuIHJSbQ9jiYGlDMgzZn/QTW
|
||||
/Rxs/xju3boMNucBMPa/f//G8ArYyVIwNWN4+OQlg6qaJugweYb3f/gYPr1hAqaW/wxvvzAzHLsn
|
||||
CBoyB7XlsZ7hCxBAxAQAKPW9ffv+CwMb31+G33+ZgB7+D94OA9shBk4I/xHbZUD7BpihGynAaqDi
|
||||
0L0S4MBhYERsjgKZwcsJ2jEG2VnCycYAPikRZAc7KyPDb2DA3n/2DVzt3n94H7xd7svnTwyyMjIM
|
||||
n4DVMTsnL8NvLjmGrwzAzhUjO8P5+8DAevGPQYyfkeHHf3A/RhRXAAAEELEZ+M2TVx++cQn/5mJi
|
||||
YQNvZwPV0d9/gUptSEkN2hYHa9b+Q/IYOCCQdoGBNleAT2UESjAz/gemCkbwJguQmSAZkOf/ADWA
|
||||
jg/8/x+y2eoHMIk9un0B3Oh5/voVw3dganz98jV4y9yFG48ZZJR1GfiE5BhOPeIBFn7/wZuyQJEC
|
||||
akCxsnMzVE7YMQWYDTyxbZ4ECCBiA+Dz0SOHD//h1XTn5mFBKaFh9SUjUqZnxkHDCjdwfQ4MOFCb
|
||||
G+Tx/9CtNKAN0UyMsJ0nEFNBSfnPr+8MrAy/GK5cv8vw9dtX8F0+wP4+OEX8ZRFkePhNjuHtMyEG
|
||||
Lj52BuSeNShSmJhZGR59l3GDDpljrC4FCCBiK+5v3S2VS379/A452hLN88g0uTUBAyx1MEK23cBM
|
||||
/fkb2Od4fpHByMiYQUpWhuHLx88Mn4D9DkkJKYaDl94xvPkry8DGK8PAzsUL7lyhjx0oSTAzaCmA
|
||||
F1IIYLMbIICITQGgOvDZD2Do//uHKAj/w/sGiC2zIDbIIyAOEzCJs4L2D4JikhGRD0AeBJcTwFj+
|
||||
9x+0fxBC/2eA7CeEtDoh+wh/AmP/9+dnDEdPfAGP+LwGdr6kxCWA3fPPDP/YgP0NUXkGDl4RBmYW
|
||||
drCHQQWyALD2V5dhYlARhxROHz9yMJRV1oFOjcG4wAgggIgNAJCL3v0COgYUAP8ZIHe2gU5VZQWm
|
||||
bw5WUOEF3SzJAKEhSZ0RvgEStDHyP9QkRkbYRktGaEqCjQkwQrMSRBzY+mIwt5QDjzBPmTKFYc++
|
||||
fcBW3wMGG0trhgVbrjAIyZkw8AjJMDCy8ALtYGJQFmNk0JAB1h5sv4F9lW8Mz55+Ae8h/A10t6GJ
|
||||
RRKwHFiKvssMIIBIacW85f7/7r2UwB9BLtDmRQZEgYdcXcCqSPDuT1BMQ/cQM0PTOQsrKFVAPAra
|
||||
LAkrI0ClP6g8ZWOGlAkgvadvfQMPxIDmC0BrB0FrCDrbOhhWrFjJwM4rycAhoMDAySvAYKr8l0GY
|
||||
8w2wlfiF4cndjwys/78xPL5x7OmCOdMuALvqL6HjgfuxNU0AAoiUAPhyeM/6rRra+jHAJiB0Hz8D
|
||||
tIUGSQnswBTBww6p70H7i1mQCiRQbQHaHg9K6qCzekF7C0E0qBAE6f3C8B+8hZaXiwl8aPCdFz8Z
|
||||
7jz4AG5xgqa4QR0t0PgC6Hqlg1d/MEgr8TIYyf1iEBG4B+z1v/uxevuq6+vWrgbt/ngHHQR5Bh0Q
|
||||
gW2kfMuAtOkKBgACiJRuG3gZ3ZHzj1cqyUuBW2mgqgrkSVAqAHViQB4CbZz8Br0h5e8/SMBwcUCy
|
||||
BUg9JysjvO0AKi/AbYr/kOYw6BDblx//MTz98B9YwH0BtvNvMTzfUwjOAqBRaNC9evWds4F5/O+X
|
||||
OzcvX3v58uVd6JDXS6hnn0E9C5v/+0FoDSFAAJGSAsDL6MR5fgA9D7l35jWw7Q5L6qCmKg/QgxIC
|
||||
TPCNlKBTtsG7SH9B1IPO/PgBPRIYVEWBYh+8dfYvpCT9++83w5X7Xxku3vkMLPheMDy/vpPBztaW
|
||||
wcDAADys3tPT8/Lq6ROg1SCgbXTHGSC7SGFzfQS3yWIDAAFESgCAC8L7z78x8IkAW1kCLPDqCpS0
|
||||
wUNVn0FJ+h+4kQQ+9/gXxHOgghMUUKB2DbhQBLXy/oMkfjH8+Qls4X36zPD+/QeGs7c+Mwj/Pv/r
|
||||
4vq512/evHFfVFTU0ts4Txw09L5ixYrXJ06cOMgA2T0K2gYP2gz9gdJNEwABRGpX7u339w8f//uj
|
||||
Ivv8HSPDp++QZP/tNyQ2QdkA3A+AlvL/oS3Bf/+BFSEwdln+/2D49xtYlX7/zPDzG7Aa+/WJYee+
|
||||
wwxb95xm4AU2V+7dvAHaGwyawQUdjfddR0fHH3Sjwfnz5790dnZuZoDsMgXtGb4JneKieMcIQACR
|
||||
GgDfZsyas/KfiEUJOw8rOPkyQmMV3BZghJzYwMr0D9xyY/jzneHXj08MX4F1NqiEfvboHsPaLfsZ
|
||||
7j5+ywDeWsspyMDHy/b/9c1ds4Gl1mGg+WegJfYPAQEB5cbGRsZp06b9XwEq9iGevgid4PxI6C4Z
|
||||
YgFAAJE6dgXaNOC9aNeD9YIiUuDSn53lHwMHy18Gpr+/QPuHgc1U6F5iYCwfPX6cYe3WowxMrDzg
|
||||
uUZWLiFgo0WCgZVbBDz19mZ/4pb7D94vgObnl0jjd+zd3d1P//79K1xVVdX379+/N9CkfxVawv+i
|
||||
1sZJgAAiNQWAmu+v+FiAeZX1HTAZfwG3yF4Ae2QfXj/4smTBrKe33/Gpg3eFg2KYR4xBTCcQHNMs
|
||||
QA8zs3ExMLNyMsh8nf96+ezp5VCP30ebsGRUUFAIAhZ8wgsWLHgD9Pwz6MzuTWgJ/4uBigAggMgZ
|
||||
znnH9Ovjr80r1jyfMqnv3OfPn99CHQaKwe9WNiZ5v1VTtUCHgIM8zMTMBll3AxrYYHr+f2uPPWi9
|
||||
LCi5X4OO2aPnYzbQjpXU1NR/Dx48aIZmidvQ+pyqngcBgAAiZ/gWtA7HEUrD5t3eQj0DSiGWDkWn
|
||||
d8NOpYOB55vc1t6+82YBNCm/wjFcDXKPILD0f/r69esMaODcgKaAj8iBRa0sABBA5G6f54Y65gcW
|
||||
j4iJi7KXq8ceB19kKP15Nr7kjg5AoQZa3qLHANmBDkpZ16EzPDTZPQ4QQORkgf8M+Hdtvnn5+udy
|
||||
B6Yz2St70uoIJHdsgcsEbdR8g3r8HaHJDUoAQADRas8baPBBCuqRVyR4ABQhoJlOPqgeWAsPYySH
|
||||
WikAIIBotTsKFHt3yND3F+rhn1D2b2yepyYACKAhcb/AUAdycnKijx49ej0Y3QYQQCyj0UM6AK3H
|
||||
vnbtmjILC4sRKyurAZDWB2I9ZmZmGdicEQyDJtJfvXr1DKgHdO7MF2pdjEEtABBAoyUAUqSeO3dO
|
||||
gIeHxwgYmYbAyDMAYm1QBKNHKjImtBAAlABAa+MuXLiw2MfHB3SI0FtcRzsOBAAIIJaRELG3bt0C
|
||||
5VBDJiYmUMTqAyNVF0gLIkck7Exv0GwvNc4GhfedWVnBK7iA7ohNTExcNH/+/OMMuE+QojsACKAh
|
||||
WQKAIvXSpUuyXFxcoAgF51ZQEQzEirANV6A1C8gRTOnRvpQA0AJR0EIy0GHv9vb2oEtAX1Cy2Zua
|
||||
ACCABlUCePHiBbesrKwhMKJAOdYYGHF60IhlJbcIHiwAtJwSVBVs2rSpMD8/fwF0RG/AT/ACCCAW
|
||||
euRWYMrXBOZAI2h9qg+NVDH03ApaV4pv0c1gBaDVkqB7aEFHzYNORgAtJAJdLADaJQUazIdt8QZV
|
||||
BQ4ODqA1a6C77b8TGBWhCwAIILJKAFCkXr16VYyNjQ25waQHjGB1WKSiF8MDWQRTC4Dm60ERDTrk
|
||||
ZNasWeBiHQRAuz7KysoYsrKy8N5FAlpODyoFzp8/v9TPzw90ENqbgS4FAAKIBUcEMwEdZgX0TBe0
|
||||
e8MNikBYhMIaTEOpCCYXgJbdgnbAga4HAR3tA9rjCA0j8C455CtFCAHYwlJtbe1oYINwwWBoEAIE
|
||||
ELYLpkDlL9CdfPLHjh07JSEhwYZvx9xwBKAtD6CDbUA5HHTQzbRp08DioP0dkyZNYkhOTh42DUKA
|
||||
AMJW2YKPcv/06RPfoUOHzoACA3mR/HAFoJ0HoLr88OHD4MifPXs2+EIgUOSD1qWAdiGAGnLERD7s
|
||||
jCvk01FgJ6SAxEElgbS0tFlvb28YKLMRc/YNrQBAAGFUAdDbFkFj2R/WrFmzzc7OzgpU5JO6g3mw
|
||||
AVAEgLamwzYtgiIHtp0FtMIatOcXtBES+bQX0EKkAwcOoOwLxBXZyPcEwjCIj5xxYGMMoHAEhSew
|
||||
BADdvQVa7AAK7x8DES4AAYS1EQhdUg46zVl33bp1U42MjBRBy9PIvQFqIABoExeo/gZFOqjeBh2b
|
||||
AzqlDrSkFgZg13rBLnSD7YkE7X4D7XoH3XyJL8Jhm0BBy/ZBCQzGhsnDIh3WIIadxQhiw+5ZAzYq
|
||||
lwUEBBQMVIMQIICwNgJBdRIwEYDmPF/vBQIgO4Uep2ZSCkCbVUFHkoAiG3RoBbCnAt6Z6+PjwxAT
|
||||
EwNeYAra0kRO6x+2+R1WpIPCA4ZBRTss4kEAFOGgiIZFOPJBnKDIh+02Apmpo6MTBWwQzqd2g3Dt
|
||||
2rWcoqKi7MCq5hOwe41z6BkggHB2A6EnCkoDsdHRo0cXKCgocIP2gVJ68ygtAOhIBlCdDToXBrRV
|
||||
s6CgAHwIJ7nXQ8KKbVgRDsvZoMgG9fFBbQFQuwjEhm0DRz7uCdTnh20PhR0JBetBwbrDsKNjqN0g
|
||||
BCb2TBMTkwZgqSICtBvUXf8PLOm+ysvL7wOGU0p8fPwbpJ7eP4AAwjcQBFqAA1rF8BLYGzgOTE0u
|
||||
oAClxk5IagFQfzw8PJwhKCgIfOwsMNWTnKtx1eEwNqx4hx1uBDvgCLYdHnacJag9AcPIEY9vDASU
|
||||
KEDVDzCCzCZOnBgCGiEERgzJI4TQRiSzoaHhNFNT04S0tDRW0FlFoARpbm7OePnyZV5glegPbNR7
|
||||
Aruuuc+fP58DLf1/AQQQzgSA1Bh8O2/evA3u7u4uIM9TY28gpQCU86ZPnw66bIXo3glyRMOKcljO
|
||||
BuVoUOMPVH2ADlkDHfEFakMA++vgfj6ozw/SB0oIsLOUQIEL6haCIhA0wgeikTeDEzvwRekIIbTb
|
||||
zqaurj4TiKOAPRcW0PEloMQHWk8Nqg5B7gFWMaBRSmZgKQ6KPNCarp+ghAMQQIRcCFukpbts2bJ+
|
||||
S0tLLVBjEHa501AYuUPvjoGOKwIN6IAwMEdgRAao8RcREQGOQFgVgNyaB+Vo2CEYoEiHnQkBuxSX
|
||||
nBFP2AghMLIWBAYGgq5DfUtMKVBYWOgKtHtzZGQkE7AtwSIpKckIa+OAGr6ghAyK/BkzZoCOdfoH
|
||||
jLsZwEQB2iUEWqYFag1/AwggQlkZtkTpNbD+2KOvr68FKv4Ge28AuZUOammDLgIGHfQDO10I1LVD
|
||||
BqCtF6BhXNg5+MjTwrD6GnY7Kqw1D8LI9TslQ92wEUI9Pb0EYNtlKTC3HoN2DXEW90B1icASaFZU
|
||||
VBT4wCLkk59BpRdoAAvU4wF1e4Hs/8CcvwMY+aCl5YLQOAUfJQEQQMRuFH6/aNGi/cAGRAzQoUKw
|
||||
Ix8Ha44H5XSge8FHRoIOMwDlVFBggA43gwFQ9w90tT3oiEnk1jm2xho6Rk4c1JjjAOmHHZYILIFa
|
||||
gQkgGBjRv9AbhNDinhWY42uA3dUaUMIFlsrgHWQwAGpUgo7wApUooAEs2CAUMOH/grbrQBjUgAGZ
|
||||
/Q8ggIhJAH+hgxTf9+7ddUdGRsYMdizOYCoFQJEPyu2gIzJBI3pKSkoMLi4u4HvPQUd2woCWlha4
|
||||
iwg63AU54tFzPKzIhyUqbA1HWDVBjURAqEEIOhoUSLED3T8Z2F5JAs2cnjt/Dlx9gA6rAw1agfwD
|
||||
mo0ERT5oTxVo/gJ0zzuwRAB5AHTkD2j1PmiZ8WdonP4FCCAWPEPEoP4eb3SUY9J3ibjGx+/52bdc
|
||||
uckQ/AXSBQLVewPdGEQexgWd3Adq9IC2E4HugwYV+6BzHGEAJgY6zgi5yIZFNnp7AUbDqhPIMQmI
|
||||
kTzkrh1swIfSRICrQQiLfNCwMTBidUE7Bt3c3cEnBcDAnIXzGXZs28HwH+hufz8/8FZK0IWcoHMj
|
||||
GSB3z7yGRv5HaPUCKmH+AQQQC1qDD3QcOV96VlTPE664yM//xBgfg5M+sJ/L/h6YJIQYdh+7wRDq
|
||||
xQ926GCYDQSdXgg6px6UIzw9PcFFPbDHApcHRdTmzZvBp5gin0qMbSQPNl4P4sOuhocV0bC6H1T1
|
||||
wc7GofbQOMhMUCkgJCQksnr16srQ0NBKYOSDimvQriye6OjoBGAjUR7ov19AdfABmWWrVzKcPH6S
|
||||
4Sewd8QDrEZAp7aCzssFRj6oNzEJ2p0HRfwXaKICVQPgYg0ggFighvNlFOVvvc0YZv77Pyd4LwbK
|
||||
anRGoGdZOMA7nvaeeczg4/gd3BWDtXwHCoBOZATduGJrawsu0svLyxnOnTsHlwctygDleuSiHHly
|
||||
BuQHGIaN6sFyP6zBB/Ij7MZ45HO/kBt/1FzrAGsQAtsmKcB23kpgewB0KSMjsHuXAaz704ENcR7U
|
||||
yF/NsH/vfnDjVglYDYAOcAMd0yssLPwNKDaXAbK95hU093+CFf2wqgUggECuBu3ikOHnZfA0Sz00
|
||||
4ScDD/Y69t9fhl9f3zB8fX2LoTpWjcHKRAvc+KB1WwCUw0ErbUBHboP666ChXdAxvLBxfFBktbW1
|
||||
YbTsZ86cyZCamgofwkUfyYNhUHUGy/WwuhgUwbBGGQzDunrIgzu0WrkEGyEERtIpR0fH6IKCgqT4
|
||||
uPhYdQ01EU5OLvilEUtWrmQ4CAybN69egaq+v3///Pm7b98+UAJ4B9S/mgGycRx0bCjo0FjQLjvY
|
||||
2el/YAkAIIBge5FAFzEoA7FVQMma/nf/lLD67M/Pzwzf3z9k0JP4xFCR6gzueoBSK7USACiiQBfK
|
||||
gCIblENBkQ27OQPWvQEdQwqKbNDp+/hGCIODg+E3dIAiHnYvC2jmDzThA+LDjiyHHYIFq4NhGDni
|
||||
kXM7PQDIraA2zbp168+7u7tJamioCXBxcXPAjnpYtGI5OPLfv3nLoK+n9xcEDh8+/P/OnTvPnjx5
|
||||
soEBcnrAIyh+AY3878iRDwIAAcQCLexBRwmBtiD+2tATkhhd2Dv9MaMjF0YdxcIO3uh66tZzhvcf
|
||||
P4NP6oKd9E0uAKV0UGSCIgY0IwdrdIFGrkCRTSoA3UYGGhqG3U4CimyQ2aC2AYgGBSzsOFdQZMKG
|
||||
cUERDvIPKMFRY3CH0owAsvPmzVsMAUGBhlISEr+Bkc8Ki/yFy5YwHNh/kOHDu7cMBnr6f4DhBY58
|
||||
YO/gLjDyQXUeaFMx7MzcV9D4/Y5c9MMAQAAxorFBZ8yBLunSi80unfaQPVIErSJg+P39A8O3t/cZ
|
||||
fI2ZGeKDbMClACgRkBJAoFwJGnYF5UJQZIOOogZFHHK/GHTlA2gWz8PDA9yyB/XniRnbB0UsKIJB
|
||||
RT0o0kELWkAYFPmg4h5U1IPMh43mgSIcNHoGinzki4oGIuKR7xXaC8zdoKFoSdDIKycHA/QQHYZ5
|
||||
wAbeoQP7GT4Au7z6unp/gHr+AqtIUORffvr0KSzynzIgbr3+jF7vIwOAAMLmO1B5CxpW0guNDmx9
|
||||
KV6Lcubevz/AxtLHpwxsP+4xzKzxArcDQDmXmC4hqH8KGmsHRcSaNWsY5syZAxYH5T7QGeOgG6ZA
|
||||
/XdiBnuQu23I3TdY5INyPigBgDAo14NKA5A62A0VsIgHYViuJ3UcnxaR/+3bd4YdO7YzGBgaAds4
|
||||
kgzcnJDMBTqAYu7ChQwHgdXfZ2CC1tXR+QN0Jyjn/wOG6Vlg428zNOKfMiC2FYNa/T/xHSgBEEDY
|
||||
Yu0H1JDfq5euL7K1vZXNaLrYD55imIG5g52X4dNnbobj5+8wuNnxEuwSglqooBwPKupB9yyAgLq6
|
||||
OngaF7nLhmtYFxY4sEiGdduQaeSLqWAte9iULayBB8rZoFwOyu2g9gUo8kFuh1VjtO7W4pq3giRm
|
||||
0FHM34Fd1k0MVpaWDBKgkpWDE9xCA3Xk5wJ7O4cPHQAdl/bf0FD/79cv3/+ePHXiH7CRfOzli5c7
|
||||
oXH2BGmw5wu0r493azZAALHgmQoGpaLfhw9f7VN56vJcLnBb+p//bOAz2ZhZucAHX+w5+YjBxkQd
|
||||
5xWroGIX1E0DXWUCatiBWu2gC7RA3TNiFl8gT8fC6nQYBkUsSAw5ASAP4sDEQGbBJnBgK39gkQ/i
|
||||
w7p4lDbuSF0yCTtg8Nfv/wxff/xl+PDpK8Pxg9sYbGxswYcBgop9kPyP/38ZFsybD2z4HmT4A/Sz
|
||||
vr7e35/ff4HOz/h/7+69Y69fvd6JVN/DGnuwyCe4BxEggPCV23+gdciVO/feLbjTa/HAu2Rr2+d/
|
||||
kozM4MYgH8OVR88ZHj97Db/2BXmxyNatW8F1OAjExcWBZ97wzR8gT+Ag52RYLobNw8O6bLAEAksw
|
||||
yO0H5BE62KgdyH2g3I5c38OmtglFPrXWwzJCT46DHbf5+88/8JF4X4F+O3pgK4M1MOeLiokwwHp6
|
||||
34D+nD8fmPMPHgKfKWhhYQlqzzCev3D+77lz53a+efPmKDDMnqDl/K/ERj4IAAQQMbOBoBQFGhv6
|
||||
sbXH+1VYybwZLxj0WZnZeRjYuIUYth+5xaAoJwmOGNhiEdDRdqALkUGrdEDXbBAzXQuLdNiiC1gf
|
||||
Hbb4AjYsCzu2F3ZgM6ENKOgDOrArOZHre1oteIY5A2T+j98Q/A96NvDPv/+A/vvD8PHLV4ZH148y
|
||||
uLm6Aksnfngm+gRM9AsXLgBHPsggcxMTcHg9e/6c6ezZsweA7alj0JwPi3xYzv9Nyu5jgAAi9tRc
|
||||
0AgS6MSLX6t6khKj8xqmPWRx42PhEGA4eOEWQ0IApM6FzQ+A7kjEt1ADFvGw4h15cAaW40HisEkY
|
||||
WA6GDcXCpmOREwGs/sbMzYjZO8yJH9pEPiP0pEDQ6X/gIxL/wU4U/A8+Dfj3b9BheX8YfoCOPr53
|
||||
msHezoaBm4cbHvnvgI3WRYsWMhw5dJiBCajRzNKMgYWZheHalcsM33/8YRQRFfsKTABvGBAnBcJy
|
||||
/m9St54DBBAjiWpB3UTQ2S96EQkx3Q/Y45S+vr3LEO8kwBDkYQ7uEYASAa6GFPJwLKyIB0U67BJN
|
||||
kBhs/B2Wa2Fr7GBj8LBIhyysZMKYxcM35YpMUz3SGSCRDiraYQcBgxMBMMJB9Tz85GRw++YPwzeg
|
||||
v5/dPgFs8JmDqyYODkj1+PrjB4bFixYzHDl8mIGTg43B3sYe3Ja6desOw2+gefwCggw83FzfWptq
|
||||
QRsULkO7e2SdlAgCAAFE6kD+b6hln65cuHRGT/qpxncea6lXL54xOJrKwxdCYgtkWB8dlLNBkQ0b
|
||||
lQPRoIQAu0QQ1B0D1dNCQqA7dEWQWut8SMuuQPdssqHM3eObv0fG1MzlsMOTwcdhgs4J/QmJfNDx
|
||||
9yD8/Tfk7G+YeuTI//DkAoOdnS3QT6C1FZCc//ztG4ZFCxcxHAW2lziACd3F0QnYTvjDcOPmbWAY
|
||||
/WQQl5BkkJGRZZCRlmI1MTFh3rdv7y5oO+0XuUvKAQKI3BABDf2BBol0NdQls1g0SvwbknQZzI00
|
||||
wddooDf2YPU8YnQOMQYPm09HXlGLXEcPto2lIGeAzjr9CT0zHcT+BT75Fpg7oPU7NqeCMwAw8n98
|
||||
/cLw7M4J0A13DLygYXQWZgZxYWGG+0+egIewjx45wsAJTNzOzi4Mf//8Zrhw8SIw4/xlkJaWZJCT
|
||||
lWOQkQVmNB5+0DUmf50dLE1AVTMw8r+Q6x+AAKIkVEHtB9DyImNWFobQjPLJSbnx7sBqQAKcU5Ej
|
||||
DP2CeORVtbCiHrmIH5SRDj/iGMKGHIH8H3zOMy5Xwq5QAB2qyQwsPH///MZw/tR+BiUlZXBiOHnm
|
||||
NMNnYPX3BZgoPn74wPD502fwnLwtsCsICi/QzCbo2HQxcSnw5JeCvAKDvLw0g7CQAMOf3+CdTmfs
|
||||
7OxAYzSvyD09FCCAKA1hkP9A65GsgUV34PHjJ6JAq1NAfW1YNwx5QwX6PDusBQ9q5MH64oPhbABY
|
||||
d+3PP8hBwKCGHOj6hp/QRhz0VHeMiIcc9s3IwAY6RRVYqrMxQY6C//3rN7DE+8pw8exhYOQJgi8I
|
||||
uH7zOsMXYCkIvnkNiEG3IbABw0JPVw9s+K1bN8CXFcnISDPIy8kDc74cg5gE6IYmEQbQOZzfgI4C
|
||||
jazu2Lwqpam+cjUwAXwix68AAURpaP+DTjZcBjbmDt27dw982xLyTciwljlshwzyxAtsxo3Y/jit
|
||||
Ix3cev8LOt6ageEtsFB99ekf+BToN5//MXz4/g/coEPv3oEii42ZEXz3hygvE4MwDyP4PHEWYOSD
|
||||
unygYvzPr68Ml88fAUaeADjSL127DOwh/GJ49+EdeE3DV2A7iBNY8oEi/y+wSnzy5DG4lBERl2YQ
|
||||
EpNn4BKWZ2DmkWL4xSLM8PEPN8OPf6wMP/8D21qsPAy2Tt49oOoYupGHZAAQQNQI8b/QRHBtxYoV
|
||||
20GtetgdpMh9ceTtUrB5dXoMvxIzGgfK6V++Q+4rewmMdNDB7W8+/wXfXQYq6hlhuR0pwvk4IXcb
|
||||
ifBAIh90ODxIEYgGXfYkxM0ATAh/GP79/sJw6vgh8GAZqLdz4/ZNYCn4h+Hp86cMTx48YvgFDCte
|
||||
8FpAefC8BehiiJfvvjFwC0oyCIorALE8A+hsZm5+YciFdMCeAeSKIdDN19wMn/7xCkyau6YWNKVC
|
||||
zi5jgACiVsiDmrGgBWpmwGpgAbC+YgdtI8M1TYwS3/8xXfEfS0MKXQybGhSz/iNu80DhQ5WBDrMH
|
||||
Fe+gbhuoLod11ZBzN0w9GyvkFi9WFkYUp4IOx2cHi0PYoIQEOigfVMT/Bub8Xz++MFw8f5aBm4sL
|
||||
XNdfv3mTgRGoEDQ3Arr27BuwMcwPLAVBRTzILlDv4MXbb8CiXhKcIBTk5RkkJaUZePgEGX4zcTF8
|
||||
/8PK8OUXpDriZmcEJs5/DN+/fmT48uHt31gvTV3Q4g9gVfCNlIgDCCBqreoEzR2A1pw9OXXq5Glh
|
||||
YSEbXl4eBhZW0C5YRshFGv8gl+OAijbQlSiw2wL+/oXcRAKuLf8zgtWAAuM/9H4qBuigCuwseiZo
|
||||
1wt2NRMT9Daif9A7msB3VcEqcQZIfQyrWVjAF/NArmT59RvSgkdOM7Dj30GRycHGBG28QYo4UAYH
|
||||
JQA26A0p4ET0B2QeyC+QhAG+RAAo/wvYL/z44QvDpfPHwLkbVMzffvCAgR2Ye9++e8vwCHT7GTC3
|
||||
CwG7t7LAbh24ewy6DhpY9ygBG3kikgoM3MKyDF9YJBmefONnYP/PCUyELODBpE/A7ubrj0D8CZT4
|
||||
/jPcf8HO8P0LO3P5xP2LOvMd/YClwE9SGoQAAVg7gx6CYSiO/4sEkxEjNjvgS/gwvpOvIOLuzNXd
|
||||
wVEiMTcO2AxLNMO0fR2uEocemiZNmn/z3vu/NP39M/bKByQdMbrT2WJYqdrMrFgiCuTeQLBUlu/u
|
||||
mxQ6TiEk4oRSR+WmnsTXUUIn9B8/vsRn+kIkTC8yEovIbNLzE7tDYqrImol5hr2RFkponfdTpld6
|
||||
UdT+6v//D/JK4nFojaGQT1DSeKv4Qc6AikUiTF6jC/beXNU3fhBguV7BKBrwjz48b43zKUTTbijw
|
||||
Ib9xYSljbLYhypaLmtOG7bZg1R1kClWE3MDulBUpSdOg2AeyZIpaQ/Yf7jwCjw7gy0FvPOpPfikI
|
||||
XwKImuu6f0CHJJ8+fXz/wR8mXsXfTDwMzMBQ/AfNdX//IW6bQekv/0esQWVEaoVjqMNeY0DrA9S6
|
||||
AFFF/IcnOlAigJUW/xkQF7/Brv+B3W32FzpCxsyMsBtUt7Mywdo0kMTBBG0cgC6KAJU8v4Fds2/A
|
||||
Bt2rB8DI5+ECXwVy/fYt8DD250+fQBc8M7wHJgJxUVFonf8JPMDz8M0vBmExaQZOIXmGL8wyDC9f
|
||||
iTP8fsMPbO1zgOt6ZmgpxobWYgNFvpQgE8PTd5wMzL+B7QiTyBkMC3sMgaXAD/Q7knABgACidusL
|
||||
tB9bxcTcxj+pdEqdsKgEsKUvAGzhM2EclI5SCqDX4wyUXUdG+8UbiITxF5q6/v35BayPPzNwfzkP
|
||||
vujuNbBrd+XGVWDk84AHve7fuwe+8lBESBi8FgI0FvL563eG07eB+YZTioFdQI6BV1iOgUdAnIGD
|
||||
W5CBhY0TGOks2EeVkNzBDE0UX779YPj77Q2DEtOJvtbyuDZQZiRmdBAggKi9swO8m/jMySNnU/+8
|
||||
//zzBz8vByc3+GozYiP/PzHTskh9cNj9NOCSA6k9ALu2EXZzIUwvuJ6H5nKG/6hdQORr4KCFA+SW
|
||||
M6g5DFA1sO4TI/RGwN+gCa2v7xj4v19lUFJWAq9aBk3u+P8PYti0eRP4mufHjx8ySAH78ZqaWuD7
|
||||
L998/MFw5NoPBl4haQZeEXkGHiFZBi4+cWDDHphhQHdtMDJjRD6sBAUJg25aFONnAnY9GRjkREGT
|
||||
WtwM/37+ZvjxxSQfqHQWNC6+E4owgACiRf8LdNWDenZhdam+fWSgELAU4OLmBde/yJEIrsuRingm
|
||||
eEQwQu/Y/A9udIEaVsyMSA0+RsiVdCxMsMiFVAqM0DodcicXpEEJa9QxIl1kBBcDLXj4zwC92Q0S
|
||||
o///wa61Q5q4+Q9xNxO0OgG1ARABB7rf7yfDlJ46hucPb4BXItvZ2QEjn5fh+YvnDAcOHWI4euwo
|
||||
w7PHTxjkgInCxNgEvD7x8cuPDOcf/AdffccL7ONzC8owcPGLM7BzCTAwA3M+sKUCbNZArtAD9UD4
|
||||
gd1KcX5GBlEg5mUHNUb/gy9j+gdeDgdZ/AIab/j1E9ie+PGNgf3Hw21x4V5JoLklQrODAAFEi71d
|
||||
4FJgan/r6lk2gX6/fnxn5uHmAqZYFgZ2ZkhLmgXauobVoUxMiEiBRdR/2DJIRuyLMuANSgZGlJQM
|
||||
0/sfaaQKXM//Q5QU/5mQruWGDdn+Q1IPbRWC3McCvdIT3EYA8llZGaFtDFDk/2J4/uwlw7wZ/eB6
|
||||
HtSaBxX3sDGOH8Cu3/tXrxnMTM3AmzZA3b+bD14z3H7NgYh8YGufi1eMgY2THzwgJsjDxCAh8B+Y
|
||||
s/8BI/sv+D61nz9+gRuKvz78ZHjx+yewxIFgJoY/DOwM3/68f/Xg04M7116fP3v6PrAXBrqUBrQ7
|
||||
hgfaM8N7+BRAANEiAYC2I4GWIT///ebqVTEpPj0R3j9Az7GCh0n//8cs6sGlwX9E5CNyHFoxzAQd
|
||||
V4eWAuAWMTP0qkKkRASyB3SRLKjUgVxmCb30khF+gxHYnj/QIogZGMvg3shfyAW2sCvPwJdc/4a0
|
||||
vkFXG4ISL0ju3ee/DE/e/GR49e4Tw5YV88Dmgep10A4l0CAYqNsH2phqb2/P4O/vD96rD9qxu33/
|
||||
GYY/PGoMXAKSwFwvxSAiIswgLcHBICX2i0GQ6y3QDX/AufjHO6DZb/8wfGT88ffTm8ef79+58vrC
|
||||
udMvjh879hwaod+hGe0bdHb2CzSyQYtC3kIH5t4yoF20gw0ABBCthuBAqU9JRlbOccbCLRNExMQZ
|
||||
eICNQSZQbP1H3C0NijjYXZOgVjUogEFKQGxYVwdl3Pk/JIJAd9SBIu8ftA/+9z9kfAHUJYPdZghK
|
||||
JGB5aGMAfMcltBvIAG0rgIZrQXdeguz/D78Z9T+YD6vz/0LNff3pP8ODN//ALe+Pn38y3Hn6heHW
|
||||
/dcMW3pcGfh52MF7EUBL5EEJABT5IDbotLGHwD4/GxsHQ3nbPAYuYNUgJirCICslBox0gX/MwM7b
|
||||
8yf33ty4dvn5yRMnnv38+fM7lsj9zIDY2/eZAXGhEEztD+g0PQz/IWVqGCAAbWewgjAMg+EyC3pS
|
||||
BnrydXw194bzsOMUEaZDRTdmm9YkbezAq556Lfz52yYh/f413ksbaw/7ulL9qcln89V6ucBcOHX4
|
||||
nA+FFOJnykrERRFRHluTLKRgGu89zc5Wn2CZor11pr4iRWoF3oWikyCuYYS0JGGfjKxMxNcBAgzd
|
||||
R6Kzxfv+ZRwH3QVdXx0tOt+oDo922595PsKZDp2/4TY4tbZpQJXKvvT5FnX0tkVx25XlFQAe8WQk
|
||||
ZzYqQU3b6Nz7SHQReIiiykw//Bo28RZAtEoAf6HF0ps1q1esj0stSvv69yuwMQhausUEabAxQe4Q
|
||||
B12UDrqLmA+YOFiYGbBGJCRRMIJzPijyQJH47wcoIv+Bb7IHzdD9/c8AH0kEJag/0NwPHkz6C6GR
|
||||
hh3ACewvtG5hBDakgOUFuEH1B6j5/79fwAbWL4bHr38x3H7yneH1+x/gbh4z4y8GEa4f/7m/P/j5
|
||||
8uGFj7dP7Gc2MTERAZ0IDlrHACryQQ0yUOSvWrXqxYoVKx5CI/0FdPkWiA+76BW2hu87tKj+MxA3
|
||||
iQAEEC1nYWDHzBmePHlqmaysDBtsfgA0/PsbWrT+/ou4ffcndFEFePj4P0IOrB46nAzr4kE7Coiu
|
||||
IAN6V/A/9Cpx8NgiOJKB2RW0swUoB4xgYGPq31/QTN1Pho9ffjB8+fETfOPnr69vwcX2nVs3GW5c
|
||||
2PPx/r1H95Dq1jfQnAqKtP/Aer/Cx8eHE5QATE1NYUezvC8pKTkC1QO72Re2OfMlA2J//u/BcHUM
|
||||
QADR8oQH2PzAqz37Dx0xsfF24nnPycDGzg0dj4dE7p9//+GLJv/C+/T/4d035L4+A3w+ADpDB6KB
|
||||
EczE+JeB6T+o7Aa12H6B8e8/wJbyT9A28J/gSGYElqCf3r9luHv/IcOVG/cYrt1+zPDl22/wfkcQ
|
||||
Bu114Gd+8efx9f1XP378Cbql9DE04p5Bi+wP0OIZ5BJuYMRnAxt4nKCt2KAEA8z5PwsKCtYDq4Ef
|
||||
0ITyHJrrnzEgVu1+hYbL38FwWQQIAAQQredhwfMDHJyc5v2Lj8zjFRBn4BUQAq9wRYlc2OwadPiV
|
||||
BdSCByUCYN+MmfEfPOf+h0bsH3A36DfDDyANajUzAiP/88d3DPfuP2C4fus+MHKfMLz/9B18cSkT
|
||||
KwcwgjmBEcwBub2VjZuBhY0HTLMBO9kiP3a/37VxLWg3Leh2x3vQiH/JgNhQ+QdpvIqFiYmJz8/P
|
||||
b0JKSko0sMvHdOzYsX9AfP4UsP8FVf8GKeJhW7Q+Q+vzP4Ml4mEAIIBofcYLeH7gx/fvj3+9v3vn
|
||||
Hw+vCjsTDwMX9KZ5pv9/wZH3Dxi5oCVOf0B93O8/wf1r0PIxEP7/H7SO7hP4HL9rN+8zXL35iOHt
|
||||
x2+QLWosHOAIBl3JC8agyGWXYmCVVmWQVOCCyEHVMDEDczow4fGyvv3PcHvipZ3rD69ggNxlirF3
|
||||
HsdINDM3N7coMNfPiYmJ8fj48SPTyZMn/+7cuXMjMFIvI0U+LOJfQyMeloj+MQxCABBAtE4A/6DF
|
||||
3tvVi6YsLavrq//74TvDuz+/oQtCgXXw98+/nzy6/f761cuvTp449uzmzZvvYMUkdJ2BhIZdotNf
|
||||
NklgnIsxsEgqMkjIQSMcnLs5IMU4Myuw/geWLEwgmhmImeAFnCTDsV/nNjVsvn3nzQEg9wEDYjMF
|
||||
/MQMAqUkyDBOaWnpCmAR73rgwAGmT58+/QFG/hxgwrwJa/BCzYSVHt8YEDd/DtqpDYAAYqRTIgOd
|
||||
PK4FxAbQhiEb2iAGbCADdo4NrBsECnhRINYMzp3Y85LRnA09crFaCGyti39aCLq1eCG0aH8IzZmw
|
||||
7dKkXMkKPqBJSkoqRFhYuB/Y0BN8+vTpdGBVcBOYGH5CzXsNjfg3aIkKI+IH2y1tAAFEr7VY7NCZ
|
||||
QtAqYg5o4MPOyP8JzfF/YH1dpICDHWEDOrBfPyavevojlmCsx32DLif/d6Pr4vYtB5dDc/ljIot2
|
||||
fIAJ6nbQhcZmQJwKxCsZIMviGdByPnJdjzNxDbYEABBAQ+Hwf0ZoogHvSIpMiut+KlCgDCnaTwCL
|
||||
9jpyi3ZiSy/QbijQETrC0ATMA3XTD6SBnY9ILXy8JctgSwAAATSULgIC5UTQZhR5aJXCBA3852QW
|
||||
7cSEDTM0AYBKIW4oZmVAHJ4Ji/gfxJYwgy0BAATQULo69ic0sl9DI+Y/NND/0qiR9R+amGAN0p/Q
|
||||
CGeAjdwhVVv/GQb3GhacACCAWIbY1bGwCKEL0NTU/A+1jxGaABiRIvs/NEcP6du0AAIMANtMxR3x
|
||||
N38FAAAAAElFTkSuQmCC\
|
||||
"""
|
||||
|
||||
def thumbnail():
|
||||
icon = base64.decodestring(iconstr)
|
||||
return icon
|
||||
|
||||
if __name__ == "__main__":
|
||||
icon = thumbnail()
|
||||
f = file("thumbnail.png","wb")
|
||||
f.write(icon)
|
||||
f.close()
|
322
src/odf/userfield.py
Normal file
322
src/odf/userfield.py
Normal file
@ -0,0 +1,322 @@
|
||||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 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): Michael Howitz, gocept gmbh & co. kg
|
||||
#
|
||||
# $Id: userfield.py 447 2008-07-10 20:01:30Z roug $
|
||||
|
||||
"""Class to show and manipulate user fields in odf documents."""
|
||||
|
||||
import sys
|
||||
import time
|
||||
import zipfile
|
||||
|
||||
import xml.sax
|
||||
import xml.sax.handler
|
||||
import xml.sax.saxutils
|
||||
|
||||
from odf.namespaces import OFFICENS, TEXTNS
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
|
||||
|
||||
OUTENCODING = "utf-8"
|
||||
|
||||
|
||||
# OpenDocument v.1.0 section 6.7.1
|
||||
VALUE_TYPES = {
|
||||
'float': (OFFICENS, u'value'),
|
||||
'percentage': (OFFICENS, u'value'),
|
||||
'currency': (OFFICENS, u'value'),
|
||||
'date': (OFFICENS, u'date-value'),
|
||||
'time': (OFFICENS, u'time-value'),
|
||||
'boolean': (OFFICENS, u'boolean-value'),
|
||||
'string': (OFFICENS, u'string-value'),
|
||||
}
|
||||
|
||||
|
||||
class UserFields(object):
|
||||
"""List, view and manipulate user fields."""
|
||||
|
||||
# these attributes can be a filename or a file like object
|
||||
src_file = None
|
||||
dest_file = None
|
||||
|
||||
def __init__(self, src=None, dest=None):
|
||||
"""Constructor
|
||||
|
||||
src ... source document name, file like object or None for stdin
|
||||
dest ... destination document name, file like object or None for stdout
|
||||
|
||||
"""
|
||||
self.src_file = src
|
||||
self.dest_file = dest
|
||||
|
||||
def list_fields(self):
|
||||
"""List (extract) all known user-fields.
|
||||
|
||||
Returns list of user-field names.
|
||||
|
||||
"""
|
||||
return [x[0] for x in self.list_fields_and_values()]
|
||||
|
||||
def list_fields_and_values(self, field_names=None):
|
||||
"""List (extract) user-fields with type and value.
|
||||
|
||||
field_names ... list of field names to show or None for all.
|
||||
|
||||
Returns list of tuples (<field name>, <field type>, <value>).
|
||||
|
||||
"""
|
||||
found_fields = []
|
||||
def _callback(field_name, value_type, value, attrs):
|
||||
if field_names is None or field_name in field_names:
|
||||
found_fields.append((field_name.encode(OUTENCODING),
|
||||
value_type.encode(OUTENCODING),
|
||||
value.encode(OUTENCODING)))
|
||||
return attrs
|
||||
|
||||
self._content_handler(_callback)
|
||||
return found_fields
|
||||
|
||||
def list_values(self, field_names):
|
||||
"""Extract the contents of given field names from the file.
|
||||
|
||||
field_names ... list of field names
|
||||
|
||||
Returns list of field values.
|
||||
|
||||
"""
|
||||
return [x[2] for x in self.list_fields_and_values(field_names)]
|
||||
|
||||
def get(self, field_name):
|
||||
"""Extract the contents of this field from the file.
|
||||
|
||||
Returns field value or None if field does not exist.
|
||||
|
||||
"""
|
||||
values = self.list_values([field_name])
|
||||
if not values:
|
||||
return None
|
||||
return values[0]
|
||||
|
||||
def get_type_and_value(self, field_name):
|
||||
"""Extract the type and contents of this field from the file.
|
||||
|
||||
Returns tuple (<type>, <field-value>) or None if field does not exist.
|
||||
|
||||
"""
|
||||
fields = self.list_fields_and_values([field_name])
|
||||
if not fields:
|
||||
return None
|
||||
field_name, value_type, value = fields[0]
|
||||
return value_type, value
|
||||
|
||||
def update(self, data):
|
||||
"""Set the value of user fields. The field types will be the same.
|
||||
|
||||
data ... dict, with field name as key, field value as value
|
||||
|
||||
Returns None
|
||||
|
||||
"""
|
||||
def _callback(field_name, value_type, value, attrs):
|
||||
if field_name in data:
|
||||
valattr = VALUE_TYPES.get(value_type)
|
||||
attrs = dict(attrs.items())
|
||||
# Take advantage that startElementNS can take a normal
|
||||
# dict as attrs
|
||||
attrs[valattr] = data[field_name]
|
||||
return attrs
|
||||
self._content_handler(_callback, write_file=True)
|
||||
|
||||
def _content_handler(self, callback_func, write_file=False):
|
||||
"""Handle the content using the callback function and write result if
|
||||
necessary.
|
||||
|
||||
callback_func ... function called for each field found in odf document
|
||||
signature: field_name ... name of current field
|
||||
value_type ... type of current field
|
||||
value ... value of current field
|
||||
attrs ... tuple of attrs of current field
|
||||
returns: tuple or dict of attrs
|
||||
write_file ... boolean telling wether write result to file
|
||||
|
||||
"""
|
||||
class DevNull(object):
|
||||
"""IO-object which behaves like /dev/null."""
|
||||
def write(self, str):
|
||||
pass
|
||||
|
||||
# get input
|
||||
if isinstance(self.src_file, basestring):
|
||||
# src_file is a filename, check if it is a zip-file
|
||||
if not zipfile.is_zipfile(self.src_file):
|
||||
raise TypeError("%s is no odt file." % self.src_file)
|
||||
elif self.src_file is None:
|
||||
# use stdin if no file given
|
||||
self.src_file = sys.stdin
|
||||
|
||||
zin = zipfile.ZipFile(self.src_file, 'r')
|
||||
content_xml = zin.read('content.xml')
|
||||
|
||||
# prepare output
|
||||
if write_file:
|
||||
output_io = StringIO()
|
||||
if self.dest_file is None:
|
||||
# use stdout if no filename given
|
||||
self.dest_file = sys.stdout
|
||||
zout = zipfile.ZipFile(self.dest_file, 'w')
|
||||
else:
|
||||
output_io = DevNull()
|
||||
|
||||
|
||||
# parse input
|
||||
odfs = ODFContentParser(callback_func, output_io)
|
||||
parser = xml.sax.make_parser()
|
||||
parser.setFeature(xml.sax.handler.feature_namespaces, 1)
|
||||
parser.setContentHandler(odfs)
|
||||
parser.parse(StringIO(content_xml))
|
||||
|
||||
# write output
|
||||
if write_file:
|
||||
# Loop through the input zipfile and copy the content to
|
||||
# the output until we get to the content.xml. Then
|
||||
# substitute.
|
||||
for zinfo in zin.infolist():
|
||||
if zinfo.filename == "content.xml":
|
||||
# Write meta
|
||||
zi = zipfile.ZipInfo("content.xml", time.localtime()[:6])
|
||||
zi.compress_type = zipfile.ZIP_DEFLATED
|
||||
zout.writestr(zi, odfs.content())
|
||||
else:
|
||||
payload = zin.read(zinfo.filename)
|
||||
zout.writestr(zinfo, payload)
|
||||
zout.close()
|
||||
zin.close()
|
||||
|
||||
|
||||
class ODFContentParser(xml.sax.saxutils.XMLGenerator):
|
||||
|
||||
def __init__(self, callback_func, out=None, encoding=OUTENCODING):
|
||||
"""Constructor.
|
||||
|
||||
callback_func ... function called for each field found in odf document
|
||||
signature: field_name ... name of current field
|
||||
value_type ... type of current field
|
||||
value ... value of current field
|
||||
attrs ... tuple of attrs of current field
|
||||
returns: tuple or dict of attrs
|
||||
out ... file like object for output
|
||||
encoding ... encoding for output
|
||||
|
||||
"""
|
||||
self._callback_func = callback_func
|
||||
xml.sax.saxutils.XMLGenerator.__init__(self, out, encoding)
|
||||
|
||||
def startElementNS(self, name, qname, attrs):
|
||||
if name == (TEXTNS, u'user-field-decl'):
|
||||
field_name = attrs.get((TEXTNS, u'name'))
|
||||
value_type = attrs.get((OFFICENS, u'value-type'))
|
||||
if value_type == 'string':
|
||||
value = attrs.get((OFFICENS, u'string-value'))
|
||||
else:
|
||||
value = attrs.get((OFFICENS, u'value'))
|
||||
|
||||
attrs = self._callback_func(field_name, value_type, value, attrs)
|
||||
|
||||
self._startElementNS(name, qname, attrs)
|
||||
|
||||
def _startElementNS(self, name, qname, attrs):
|
||||
# copy of xml.sax.saxutils.XMLGenerator.startElementNS
|
||||
# necessary because we have to provide our own writeattr
|
||||
# function which is called by this method
|
||||
if name[0] is None:
|
||||
name = name[1]
|
||||
elif self._current_context[name[0]] is None:
|
||||
# default namespace
|
||||
name = name[1]
|
||||
else:
|
||||
name = self._current_context[name[0]] + ":" + name[1]
|
||||
self._out.write('<' + name)
|
||||
|
||||
for k,v in self._undeclared_ns_maps:
|
||||
if k is None:
|
||||
self._out.write(' xmlns="%s"' % (v or ''))
|
||||
else:
|
||||
self._out.write(' xmlns:%s="%s"' % (k,v))
|
||||
self._undeclared_ns_maps = []
|
||||
|
||||
for (name, value) in attrs.items():
|
||||
if name[0] is None:
|
||||
name = name[1]
|
||||
elif self._current_context[name[0]] is None:
|
||||
# default namespace
|
||||
#If an attribute has a nsuri but not a prefix, we must
|
||||
#create a prefix and add a nsdecl
|
||||
prefix = self.GENERATED_PREFIX % self._generated_prefix_ctr
|
||||
self._generated_prefix_ctr = self._generated_prefix_ctr + 1
|
||||
name = prefix + ':' + name[1]
|
||||
self._out.write(' xmlns:%s=%s' % (prefix, quoteattr(name[0])))
|
||||
self._current_context[name[0]] = prefix
|
||||
else:
|
||||
name = self._current_context[name[0]] + ":" + name[1]
|
||||
self._out.write(' %s=' % name)
|
||||
writeattr(self._out, value)
|
||||
self._out.write('>')
|
||||
|
||||
def content(self):
|
||||
return self._out.getvalue()
|
||||
|
||||
|
||||
ATTR_ENTITIES = {
|
||||
'\n': '
' # convert newlines into entities inside attributes
|
||||
}
|
||||
|
||||
|
||||
def writetext(stream, text, entities={}):
|
||||
text = xml.sax.saxutils.escape(text, entities)
|
||||
try:
|
||||
stream.write(text)
|
||||
except UnicodeError:
|
||||
for c in text:
|
||||
try:
|
||||
stream.write(c)
|
||||
except UnicodeError:
|
||||
stream.write(u"&#%d;" % ord(c))
|
||||
|
||||
def writeattr(stream, text):
|
||||
# copied from xml.sax.saxutils.writeattr added support for an
|
||||
# additional entity mapping
|
||||
countdouble = text.count('"')
|
||||
entities = ATTR_ENTITIES.copy()
|
||||
if countdouble:
|
||||
countsingle = text.count("'")
|
||||
if countdouble <= countsingle:
|
||||
entities['"'] = """
|
||||
quote = '"'
|
||||
else:
|
||||
entities["'"] = "'"
|
||||
quote = "'"
|
||||
else:
|
||||
quote = '"'
|
||||
stream.write(quote)
|
||||
writetext(stream, text, entities)
|
||||
stream.write(quote)
|
29
src/odf/xforms.py
Normal file
29
src/odf/xforms.py
Normal file
@ -0,0 +1,29 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006-2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from namespaces import XFORMSNS
|
||||
from element import Element
|
||||
|
||||
# ODF 1.0 section 11.2
|
||||
# XForms is designed to be embedded in another XML format.
|
||||
# Autogenerated
|
||||
def Model(**args):
|
||||
return Element(qname = (XFORMSNS,'model'), **args)
|
||||
|
Loading…
x
Reference in New Issue
Block a user