# HG changeset patch # User root # Date 1146048489 0 # Node ID cc367abb080e4041712a9a3678007307ce0b095a forget the past. forget the past. diff -r 000000000000 -r cc367abb080e .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,4 @@ +(^|/)\.svn($|/) +(^|/)\.hg($|/) +(^|/)\.hgtags($|/) +^log$ diff -r 000000000000 -r cc367abb080e ChangeLog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ChangeLog Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,35 @@ +Changelog for doctools +----------------------- + +2005-12-05 -- 0.1.6 + * added fragment writer + * bugfixes + +2005-07-18 -- 0.1.5 + * remove deprecated mkview example (close #8813) + * changed dependency from libfop-java to fop + * print external tools output in non quiet mode + + +2005-03-30 -- 0.1.4 + * added english documentation, dropped the mkview part + * packaging fixes: added missing executable script py2dbk and xml2dbk + + + +2005-03-29 -- 0.1.3 + * rename xml2db and py2db scripts into xml2dbk and py2dbk + * first public release + + + +2004-06-03 -- 0.1.2 + * Fix bug with xmlproc_parse with UTF-8 files. + + + +2004-06-01 -- 0.1.1 + * First release. + + + diff -r 000000000000 -r cc367abb080e DEPENDS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DEPENDS Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,3 @@ +python-xml +fop +xsltproc diff -r 000000000000 -r cc367abb080e MANIFEST.in --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MANIFEST.in Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,11 @@ +include README +include ChangeLog +include DEPENDS +include SUGGESTS +include bin/mkdoc +include bin/mkview +include bin/py2dbk +include bin/xml2dbk + +recursive-include doc * +recursive-include examples * diff -r 000000000000 -r cc367abb080e README --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,5 @@ +logilab doctools +================ + + +Outils Logilab pour la production de documents. \ No newline at end of file diff -r 000000000000 -r cc367abb080e SUGGESTS --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SUGGESTS Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,1 @@ +logilab-xml diff -r 000000000000 -r cc367abb080e __init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/__init__.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,30 @@ +# Copyright (c) 2000-2003 LOGILAB S.A. (Paris, FRANCE). +# http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# 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., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" +doctools is a python package to transform xml files into fo, pdf or html files +""" + +__revision__ = "$Id: __init__.py,v 1.2 2004-05-27 13:26:45 sand Exp $" + +try: + false = False +except NameError: + false = None + +true = (not false) + +__builtins__['false'] = false +__builtins__['true'] = true diff -r 000000000000 -r cc367abb080e __pkginfo__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/__pkginfo__.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,43 @@ +# 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., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" Copyright (c) 2003-2005 LOGILAB S.A. (Paris, FRANCE). +http://www.logilab.fr/ -- mailto:contact@logilab.fr +""" + +__revision__ = "$Id: __pkginfo__.py,v 1.18 2005-12-05 12:35:30 arthur Exp $" + +modname = "doctools" +numversion = (0, 1, 6) +version = '.'.join([str(num) for num in numversion]) + +license = 'GPL' +copyright = '''Copyright (c) 2003-2005 LOGILAB S.A. (Paris, FRANCE). +http://www.logilab.fr/ -- mailto:contact@logilab.fr''' + +author = "Logilab" +author_email = "devel@logilab.fr" +scripts = ['bin/mkdoc', 'bin/py2dbk', 'bin/xml2dbk'] + +short_desc = "tools used at Logilab to make documents" +long_desc = "Set of tools to help writing documents." +web = "http://www.logilab.org/projects/doctools" +ftp = "ftp://ftp.logilab.org/pub/doctools" +mailinglist = "mailto://management-projects@logilab.org" + +subpackage_of = 'logilab' + +debian_name = 'logilab-doctools' +debian_maintainer = 'Alexandre Fayolle ' +debian_maintainer_email = 'alexandre.fayolle@logilab.fr' +pyversions = ["2.3", "2.4"] + diff -r 000000000000 -r cc367abb080e bin/mkdoc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/mkdoc Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,7 @@ +#!/usr/bin/env python +# -*- coding: ISO-8859-1 -*- + +from logilab.doctools import transform +import sys +sys.exit(transform.run(sys.argv[1:])) + diff -r 000000000000 -r cc367abb080e bin/py2dbk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/py2dbk Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,6 @@ +#!/usr/bin/env python + +from logilab.doctools import py2db +import sys +py2db.run(sys.argv[1:]) + diff -r 000000000000 -r cc367abb080e bin/trf-session --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/trf-session Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- coding: ISO-8859-1 -*- + +import sys +from os import system + +USAGE = """ +Produire les conventions de formation (fichiers xml-docbook) : + format-session conv fichier-session.xml + +Produire la liste de présence (fichier pdf) : + format-session pres fichier-session.xml + +Produire les feuilles d'évaluation (fichier pdf) : + format-session eval fichier-session.xml + +Produire les certificats de formation (fichiers xml-docbook) : + format-session cert fichier-session.xml +""" + +xslt_dir = "/usr/share/sgml/logilab-xml/stylesheet/others" + +xslts = { 'conv': "%s/session2conv-form-dcbk.xsl" %xslt_dir, + 'pres': "%s/session2liste-pres-fo.xsl" %xslt_dir, + 'eval': "%s/session2eval-fo.xsl" %xslt_dir, + 'cert': "%s/session2certif-form-dcbk.xsl" %xslt_dir, + } + +if __name__ == '__main__' : + if len(sys.argv) != 3 : + print USAGE + sys.exit(1) + + if sys.argv[1] == 'conv' : + line = "xsltproc %s %s" %(xslts['conv'],sys.argv[2]) + system(line) + + elif sys.argv[1] == 'pres' : + line = "xsltproc --output liste-presence.fo %s %s" %(xslts['pres'],sys.argv[2]) + system(line) + line = "/home/logilab/bin/fop liste-presence.fo liste-presence.pdf" + system(line) + system("rm liste-presence.fo") + + elif sys.argv[1] == 'eval' : + line = "xsltproc --output evaluations.fo %s %s" %(xslts['eval'],sys.argv[2]) + system(line) + line = "/home/logilab/bin/fop evaluations.fo evaluations.pdf" + system(line) + system("rm evaluations.fo") + + elif sys.argv[1] == 'cert' : + line = "xsltproc %s %s" %(xslts['cert'],sys.argv[2]) + system(line) + + else : + print USAGE + sys.exit(1) diff -r 000000000000 -r cc367abb080e bin/xml2dbk --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/bin/xml2dbk Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,7 @@ +#!/usr/bin/env python + +from logilab.doctools import xmlformat +import sys + +xmlformat.run(sys.argv[1:]) + diff -r 000000000000 -r cc367abb080e debian/changelog --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/changelog Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,66 @@ +logilab-doctools (0.1.6-4) unstable; urgency=low + + * Added missing dependency on logilab-common + * Updated debhelper build dep to 5.0.0 and compat mode accordingly + + -- Alexandre Fayolle Mon, 27 Feb 2006 14:32:37 +0100 + +logilab-doctools (0.1.6-3) unstable; urgency=low + + * fixed dangerous postrm script + + -- Alexandre Fayolle Thu, 16 Feb 2006 17:20:26 +0100 + +logilab-doctools (0.1.6-2) unstable; urgency=low + + * reorganization to install into site-python, removing the need for + pythonX.X- packages + + -- Sylvain Thénault Mon, 23 Jan 2006 16:35:02 +0100 + +logilab-doctools (0.1.6-1) unstable; urgency=low + + * new upstream release + + -- Arthur Lutz Mon, 5 Dec 2005 13:33:28 +0100 + +logilab-doctools (0.1.5-1) unstable; urgency=low + + * new upstream release + * depends on fop instead of libfop-java + * python-logilab-doctools has been renamed to logilab-doctools + + -- Sylvain Thénault Mon, 18 Jul 2005 15:24:17 +0200 + +logilab-doctools (0.1.4-1) unstable; urgency=low + + * new upstream release + * added home page to packages description + * added watch file + + -- Sylvain Thénault Wed, 30 Mar 2005 11:17:26 +0200 + +logilab-doctools (0.1.3-1) unstable; urgency=low + + * new upstream release + + -- Sylvain Thénault Tue, 29 Mar 2005 13:56:25 +0200 + +logilab-doctools (0.1.2-1) unstable; urgency=low + + * Fix bug with xmlproc_parse for UTF-8 files. + + -- Sandrine Ribeau Thu, 3 Jun 2004 15:58:08 +0200 + +logilab-doctools (0.1.1-1) unstable; urgency=low + + * Changes package name. Becomes logilab-doctools instead of doctools. + + -- Sandrine Ribeau Tue, 1 Jun 2004 13:36:57 +0200 + +logilab-doctools (0.1.0-1) unstable; urgency=low + + * First release. + + -- Sandrine Ribeau Thu, 27 May 2004 15:09:21 +0200 + diff -r 000000000000 -r cc367abb080e debian/compat --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/compat Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,1 @@ +5 diff -r 000000000000 -r cc367abb080e debian/control --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/control Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,19 @@ +Source: logilab-doctools +Section: python +Priority: optional +Maintainer: Alexandre Fayolle +Build-Depends: debhelper (>= 5.0.0), python-dev +Standards-Version: 3.6.2 + +Package: logilab-doctools +Architecture: all +Suggests: logilab-xml +Depends: python, python-xml, fop, xsltproc, python-logilab-common (>= 0.13.1-4) +Provides: python2.3-logilab-doctools, python2.4-logilab-doctools +Conflicts: python2.3-logilab-doctools, python2.4-logilab-doctools +Replaces: python2.3-logilab-doctools, python2.4-logilab-doctools +Description: tools used at Logilab to make documents + Set of tools to help writing documents. + . + Homepage: http://www.logilab.org/projects/doctools + diff -r 000000000000 -r cc367abb080e debian/copyright --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/copyright Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,28 @@ +This package was debianized by Alexandre Fayolle Sat, 13 Apr 2002 19:05:23 +0200. + +It was downloaded from ftp://ftp.logilab.org/pub/doctools + +Upstream Author: + + Logilab + +Copyright: + +Copyright (c) 2003-2005 LOGILAB S.A. (Paris, FRANCE). +http://www.logilab.fr/ -- mailto:contact@logilab.fr + +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 St, Fifth Floor, Boston, MA 02110-1301, USA. + +On Debian systems, the complete text of the GNU General Public License +may be found in '/usr/share/common-licenses/GPL'. diff -r 000000000000 -r cc367abb080e debian/logilab-doctools-test.dirs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/logilab-doctools-test.dirs Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,2 @@ +usr/share/doc/logilab-doctools/ +usr/share/doc/logilab-doctools/test diff -r 000000000000 -r cc367abb080e debian/logilab-doctools.dirs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/logilab-doctools.dirs Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,6 @@ +usr/lib/site-python +usr/lib/site-python/logilab +usr/lib/site-python/logilab/doctools +usr/share/doc/logilab-doctools +usr/share/doc/logilab-doctools +usr/share/doc/logilab-doctools/test diff -r 000000000000 -r cc367abb080e debian/logilab-doctools.docs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/logilab-doctools.docs Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,5 @@ +doc/user_manual.html +doc/manuel_utilisateur.html +doc/manuel_utilisateur.txt +doc/user_manual.txt +doc/spec-mkdoc.pdf diff -r 000000000000 -r cc367abb080e debian/logilab-doctools.examples --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/logilab-doctools.examples Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,1 @@ +examples/* diff -r 000000000000 -r cc367abb080e debian/logilab-doctools.postinst --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/logilab-doctools.postinst Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,26 @@ +#! /bin/sh -e +# + + +touch /usr/lib/site-python/logilab/__init__.py + + +# precompile python files +VERSION=2.3 +PACKAGEDIR=/usr/lib/site-python/logilab/doctools +case "$1" in + configure|abort-upgrade|abort-remove|abort-deconfigure) + python$VERSION -O /usr/lib/python$VERSION/compileall.py -q $PACKAGEDIR + python$VERSION /usr/lib/python$VERSION/compileall.py -q $PACKAGEDIR + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + + +#DEBHELPER# + +exit 0 diff -r 000000000000 -r cc367abb080e debian/logilab-doctools.prerm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/logilab-doctools.prerm Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,14 @@ +#! /bin/sh -e +# + +# remove .pyc and .pyo files +dpkg --listfiles logilab-doctools | + awk '$0~/\.py$/ {print $0"c\n" $0"o"}' | + xargs rm -f >&2 + + + + +#DEBHELPER# + +exit 0 diff -r 000000000000 -r cc367abb080e debian/rules --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/rules Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,79 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. +# +# adapted by Logilab for automatic generation by debianize +# (part of the devtools project, http://www.logilab.org/projects/devtools) +# +# Copyright (c) 2003-2005 LOGILAB S.A. (Paris, FRANCE). +# http://www.logilab.fr/ -- mailto:contact@logilab.fr + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +build: build-stamp +build-stamp: + dh_testdir + python setup.py -q build + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + rm -rf build + find . -name "*.pyc" | xargs rm -f + rm -f changelog.gz + dh_clean + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + python setup.py -q install_lib --no-compile --install-dir=debian/logilab-doctools/usr/lib/site-python + python setup.py -q install_headers --install-dir=debian/logilab-doctools/usr/include/ + python setup.py -q install_scripts --install-dir=debian/logilab-doctools/usr/bin/ + # remove sub-package __init__ file (created in postinst) + rm debian/logilab-doctools/usr/lib/site-python/logilab/__init__.py + # remove test directory (installed in a separated package) + rm -rf debian/logilab-doctools/usr/lib/site-python/logilab/doctools/test + if head -1 debian/logilab-doctools/usr/bin/mkdoc | grep "^#! */usr/bin" | grep "python" >/dev/null ; then \ + sed -i "s@^#! */usr/bin/env \+python\$$@#!/usr/bin/python@" debian/logilab-doctools/usr/bin/mkdoc; \ + fi + chmod a+x debian/logilab-doctools/usr/bin/mkdoc + if head -1 debian/logilab-doctools/usr/bin/py2dbk | grep "^#! */usr/bin" | grep "python" >/dev/null ; then \ + sed -i "s@^#! */usr/bin/env \+python\$$@#!/usr/bin/python@" debian/logilab-doctools/usr/bin/py2dbk; \ + fi + chmod a+x debian/logilab-doctools/usr/bin/py2dbk + if head -1 debian/logilab-doctools/usr/bin/xml2dbk | grep "^#! */usr/bin" | grep "python" >/dev/null ; then \ + sed -i "s@^#! */usr/bin/env \+python\$$@#!/usr/bin/python@" debian/logilab-doctools/usr/bin/xml2dbk; \ + fi + chmod a+x debian/logilab-doctools/usr/bin/xml2dbk + # install tests + (cd test && find . -type f -not \( -path '*/CVS/*' -or -name '*.pyc' \) -exec install -D --mode=644 {} ../debian/logilab-doctools/usr/share/doc/logilab-doctools/test/{} \;) + + +# Build architecture-independent files here. +binary-indep: build install + dh_testdir + dh_testroot + dh_install -i + gzip -9 -c ChangeLog > changelog.gz + dh_installchangelogs -i + dh_installexamples -i + dh_installdocs -i README changelog.gz + dh_installman -i + dh_link -i + dh_compress -i -X.py -X.ini -X.xml -Xtest + dh_fixperms -i + dh_installdeb -i + dh_gencontrol -i + dh_md5sums -i + dh_builddeb -i + + + +binary: binary-indep +.PHONY: build clean binary binary-indep + diff -r 000000000000 -r cc367abb080e debian/watch --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debian/watch Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,3 @@ +version=2 +ftp://ftp.logilab.org/pub/doctools/doctools-(.*)\.tar\.gz debian uupdate + diff -r 000000000000 -r cc367abb080e doc/makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/makefile Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,15 @@ +MKHTML=mkdoc --target=html --stylesheet=single-file +MKHTML_OPT=--param toc.section.depth=1 + +SRC=. + +TXTFILES:= $(wildcard *.txt) +TARGET := $(TXTFILES:.txt=.html) + +all: ${TARGET} + +%.html: %.txt + ${MKHTML} ${MKHTMLOPTS} $< + +clean: + rm -f *.html diff -r 000000000000 -r cc367abb080e doc/manuel_utilisateur.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/manuel_utilisateur.txt Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,133 @@ +Manuel utilisateur +================== + +:Author: Sylvain Thénault +:Organization: Logilab +:Version: $Revision: 1.1 $ +:Date: $Date: 2005-03-29 14:24:04 $ +:Abstract: + Manuel pour l'utilisateur des outils de documentations de + Logilab. + + +py2dbk +------ + +Description +``````````` +Formate un script Python afin de pouvoir l'inclure dans un document Docbook. + +Synopsis +```````` +:: + + USAGE: py2dbk [OPTIONS] ... + + OPTIONS: + -h / --help + display this help message and exit + + -r / --root "rootstring" + insert "rootstring" as root + + -f / --format + set output format. Default to docbook. + Available formats are docbook, extended-docbook. + + -s / --stdout + write results to standard output + +Exemple +``````` +:: + + py2dbk --format extended-docbook monfichier.py + +Cet exemple produira en sortie un fichier monfichier.xml. + + +xml2dbk +------- + +Description +``````````` +Formatte un fichier XML afin de pouvoir l'inclure dans un document Docbook. Il +est également possible d'obtenir une sortie HTML (colorisée) + +Synopsis +```````` +:: + + USAGE: xml2dbk [OPTIONS] ... + + OPTIONS: + -h / --help + display this help message and exit + + -o / --output + write results in file . + -s / --stdout + write results to standard output. + -e / --encoding iso-8859-1 + specify encoding to use in outputs. + + -n / --no-head + do not insert output headers. + + -f / --format + set output format. Default to docbook. + Available formats are docbook, extended-docbook, html. + +Exemple +``````` +:: + + xml2dbk --format extended-docbook monfichier.xml + +Cet exemple produira en sortie un fichier monfichier_dcbk.xml. + + +mkdoc +----- + +Description +``````````` +Convertit des fichiers au format ReST_ (Restructured Text) ou Docbook_ dans +divers formats tels que html ou pdf. + +Synopsis +```````` +:: + + USAGE: mkdoc [OPTIONS] ... + + OPTIONS: + -h / --help + display this help message and exit + + -f / --format + set output format. Default to html. + Available formats are docbook, html, multi_html, pdf, pdf_ao, pdf_iup, pdf_manual, pdf_psyc, site_html. + + -n / --noverif + doesn't verify XML correctness. + -k / --keep-tmp + doesn't remove temporary directory where transforms are done. + + -p / --parameter : + sets the stylesheet parameter to . You may set this option + multiple times. Parameters are given to the xslt processor. + +Exemple +``````` +:: + + mkdoc --format pdf monfichier.rst unautrefichier.xml + +Cet exemple produira en sortie 2 fichiers : monfichier.pdf et +unautrefichier.pdf. + + + +.. _ReST: http://docutils.sourceforge.net/rst.html +.. _Docbook: http://www.docbook.org \ No newline at end of file diff -r 000000000000 -r cc367abb080e doc/spec-mkdoc.pdf --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/spec-mkdoc.pdf Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,299 @@ +%PDF-1.3 +%ª«¬­ +4 0 obj +<< /Type /Info +/Producer (FOP 0.20.5) >> +endobj +5 0 obj +<< /Length 620 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GasJPhf$st&BE]"=87bUd$r?G@XCmmK;"u2K/E_(Q%ptd-Ypg*-)LW*cC36X8egrlZ$"sMS\Jgp<>&TmE.SKH8[]55s3c^dV[*TO59q]_aTXse^_J(c5oqA2o#^%[a!mE2V4D/&KK2`J:Qg*K3'?0r$n=QP%&E@)I^dZ$@SuR\+2@_cdrj3VHU,Jr9fFjS.8$f@1;CS02S+r@o\5r%;q))KDr)a=@"WPAbb"c?H<6c+>>1cC`<#.H<3#j&*??Xuh#2GjM0L3g54P7[b@U!iM.>,TpJ1J>S&d]s#9TNhjkem31ng2,r/fCL*YGDktO-kI)*Y7T;#=l0JYb[Y9)QQV51Bb=Y+(.^WRa5ZFGXHsp;HU+iVadKb=k*USmX+%CSh:<7YQ7p(9f`^moJ$Z=pDQC2$AU^T:=Ur7V(ld>k`Ug/iX-aZ1Qln^G&@)VsPc6n>5B6BIc2~> +endstream +endobj +6 0 obj +<> +stream +Gb"/L$(Ou6[5Znte$HnBbQ>us+:9#Ug]1h\FtkU_@at0@N'>#&-%:`G0n^sb4bt!bU5AF9N64ML-ZOu9?As]=Lk7l'&Ju8q(^:23IAUY'X7+hJpRZ_Lh5.`=T"WFQIQ_mmhl^2,3WD/'<7NG;,kW"3(k3bBm2pe.s0?T38ba,d!8k!dU^3/08Q%Jp7I!lM7hFUsoP=Cc%9<1o0[mbrE"ULdFAO8/8WqSPKX-ZuYmOt&^mYe=:!6_"'g1#onL=oGY`PKpKs9Q0OsEV)Q#M":,bVXfWja#s<^pud$J;\$jZN&9!0.$fS)HSS$c%c9FUimnQ;E#d?/m*XXW`donSP@.sAZ&#]&-3$.O^H9YuK/8_o>a:c?-NG%CQsVgmE8X9^Bpa:>CdiFChC1P^mKXdUM,P1kMPr>ji4--!q'[4MdGfSbUnIML`52e=:\\=$tX"O)uR8Q,:*eSYYHJh8NMaUW^2mEbek0!)#JrL%KbqlFKb$i?o$+dZn7P12&i,WZbP.Cqh7(ou>5FOd!n`/91s?bh\<@/`MEeAUBQ=M[;?Kd95qRcr,%b^4r?#K+B>lCSL8Z)0\Ni$U+K5I^+7WO=4[lT];LqYkkR*i*d7$Q]V0RTfh:lJ@a:+\>S@,esb0lB>q?\&0dK<6na.1&kZ_]8I^+(G#M@Yk+X*p(&=On%W7qhlur?XRREK5/MpEMJk9bU:ptk'p9hb91"=4f3p/m&_:Sg^qL(5-k"!]<@h%CXO'e\Er+=b=j#_2IThke#>())!nfU^$)u(%!Y,5HBi.&oT[9$M)*a?(Kd95QM6%g2ich+LkE^'18Q(Tm'e#dr58MheKko&_?:C&'8Q$?JU,*@jOQRNSOsJ/7,5gM4(3R0"/C-kM,cM08PKG!fa<$1e<1/CI8WqeoUr)#!.!@8KoI!;;-OCUFP_>IjGS*1F6'YtJ%WGjfm0G/]@1G\\.5>JW]s/6Z(#?6TE=16,:X!ViG#\8`F]+)c]BB7)E6DC%(lfad6:Vfu4b7W[:J9f*Yf(a^nu&NdpE#GqCU6M%Z!2,NP1^LkYcN?cd[=87lK&\5Gdc(46T015&F\$4@S0VSs3=LF\F;G+kU_NX<.5!C24.]m=r)0oCkbqu&)e>m!ZhPh_OL`E*Xf@)2r#5)M5)Am;*h%8%E,Qge]C>S\[/d]b..#R4kjR^R8Euub'eU3f,']c,9k',64?g9R"1SnC#TTnFbNi@H,@'m+Q)oD6cPI<2BoUKQ5bmm@Fc%gSZirn7E7HQh@K9Xu.P0j\iM)gLN2/?XF^h(rL%eYudEuoQGVdl&ptf$G"M!Zbhp50ik1;G0h&D)SDfT8p+^G2l\r1Y1>_%"6gOpfI$XB>f_R0aP/gO#GS^`@DN@_H?lH>3BMaRMBi?CZh$UsfhWijUg0B1u0,9#iq;c4?KojKMhKim$2:D'a8Uh@[+]+Eo;Wa//Yj@jY=P8:5hJI=/$^3HX;[>RkpH(C3)(YO3EUM(HefBT/?JT^'qQNI\:ag^9pX@c6'NUNU.=2KZefZAXO*_!CK_1f$tQqPV_*3Bj%(GT8qA#)0u)C&MI6=5_9C6@RO)<6Id[knNKuRUVK=bF!T8Q6]%6M?tmrL$ul"0'X]e#UJ@q;S*O3>1I4S3f,R8i?C1CE$;4:a9!0,(+QLkq\KPT?%jP/88<>U1N&/)Roo1,Z*fK9>]^^DE$;2J86lAT`'T_H?bIfFU8sB/$VB_TVCgdI/cpg/eh35,d8``SKqo2%Aa*a(R>#AcXa<^X79?1#%i7"&BEqA@a>2*_C06<(@t@J$JYqm#$h!hPIJ4?.o2"appIaOg&,h0b5#e]D!Tf`7OkoMjO$dJ#"h&mtgpT!-H#%%p,[A8]h&\0OC0`4@`]91B8?Qo?`4OB>NjQ#]/Rq:Rp]q6LAYC>P$2XJHt=j6J\m34+^.F_7^Tr4cGY8%Nj(cZIgY87C*GC^-_*n?[r`PdUs-!YOqP&Sg?e3i/'d%D$T\8^nSWbG.qFC?:'MZ+Mc*C1;jg66h$>XY]_[4*A+FCp\Td@Sj_i5-02hR0t@^iKeuSY%04ZmYN3\.H:gg5.Tu0"NB$\7e\';/h(_i/-U]UdqRY\EM-^iM&K7#Jrogr@YL9/jU+&S>\"H+Q5Z(7@0km%MuR/.^n06-!X!NkgItuiIW0?DC+W''2fkX(D8@32"bgt5f,+ai]5'dY)BgdaU)3_FfDp@0u@d(m8iH8No"'\EFhViBhc"s0n!E0&].67@0mC!#J6AThl#^Ydld@eC7`1hg"KiF[a:.IJXLjfs5bLVTk2\CtSCQfADgZ=hf\"j)dLlrmSU@-5,7,.m0h.B-Eb89pRc-;&/kWW2W`#4>WM+7(?SN2$7QCc8bX/!/0VdOoDcS9ZVWL,d&.TY3?*mdjRDU-a[=U6QXpZ&sLk=:)n,Y*'pUAZ%e8EcZ=!oZ>5#cHT4cYco5)0.A=f2Jh$UE>*6'p%IR@It$FtNIW_0?VK'7.#)+a6D?1D6!qP)p"F3]o@RREJ.FQZt^sXBO\V9;4R40Sa*Xp\Ql]]$(r/S3'9#!nh9'HLdW'ZrARL5,X#Qnc3lDr+.X)"C%EK=n'8O]l"9s9C;!/Up<6(KO8Mi7RKNV.#fXOl-lQJa#2IRHeWDPI.GA_s7K`KH2$.hp[$Q@6N[k/6,;"H+Fq=u.TaDeR@1a^[4f,Tih]:TK0H,(QV]d]3q'T=c7?*2$>L%7]'HMgVU0FO":kT@dG2;6>eh`.dFu!8cC-Wf[*qc'aR>bdbOh1>2";>Nd1[Bt\01"/rC[#(@&LNEo[[5brV"ua"+b&`n7$%%fSgE7aeIrunG#99Bi'd$!@<8S_89BdEn)gmq>[,aTK#4t;cD-GoP!C"&`BP4Q^3oeBAgSAkFXsS,RCnNf/Gr=Jh#7'lH,'1"DWFr&4@&i\uDZCkK_ne]_q'0>s&#WiFhg6.S3G%%2Dr4:Fhf!fY;AI=q!g&TV,uNYZ%^9lC+&GH=d!Im0sL6((E19eo39#rZ$Fi0^Z?aI;m8hPL@q/H.cjM@f(+V5f?KS2WZtE,O;.hL->S7$dbTUAUa[Xs+NLsZ-mE9$Y=e4s3R%P%uPgF"Q.tg[GZW=5)f.b^/E2=>2-'^]eHhfE0URe^$DQr:&YiJCSp&Oc_JDnf!qS9ghb7+5ho9n!jER.d%/?M_0_)6LA6@fGe:=j5@a@TV@Je3P'.d!aeQS21JUq\>4@H[kttskf!aBaj'4"`YiDPo?8:,.Lq)CDHi8@gVfp@n-R[aYCHM?If0IIeQ78,NulK/DV='@X!*3),B+*\nFG\ElaF,#V]Us)>9eD'<4F@A_In=Hi=f#b*XY/Zhd+]eh:9V+H?8<1,q1D37su3ChLu=R6#WVGVdhotr9t@0HH:F=OuuNDG8O?K^3_2?_MlR2>n*MMr6]E9"iW<+l$`I&h0\Uo5j8!AJPb$XTVXgfH`;0SL29dAo8\R\5c)-RN]R^l4;cNF;q*^>"_^^OC_*C62aiU<[WXm-Vg?CF$SGIce(Kq5^6r^KV7Yb^L\H-Vbhd0o;j:\0M'Q=X]Vn2X\'Ga1$3HH5C345d;<3j#k82Y\hJ;F`V@"AXTJ+C\bp%=B;5'M3pn6l"lD_Z3+$P90roB9h5\1SF+Z]fCcoiX%SiDrY,X97A3CKO@)'b[$0_H_Y,Si!BU10e/JggG,kbb(EFVR:fP9E:S'Vl-G``PhPmmJXT,Nme^"%khR!&7WkIQ^pD0PK"8BfUm?'7AH?![Asee_Y`KI9d]-Toc"%a#0@A5&e>\A,+i`@1s`Rd;_kq.KM9f]7c:bRh"7ZFKe"tDqM9m[VXWK""o@h=P?9\>Hi#-c2/OU^jB%Y,ql\-ATY_.cnnE:9tO^bF8u6YQ'IWI!391NWqe7Q97*`@Mp-tXD2YeXq(B7=Fs2+.LCP=sa&W4i@tY5i3Da$KYG:V&eH#9O!+NaR':!4iJd^d4c9,?Y"M4cCMtc+Y+&kjrQ"8:&CgiD4$aFd^&$V4pqHI@-A]pA?5=b@Vl+$BQp+]$eFdnj&0>-d`HK^hLGV^<1kG_@tfnPQ!@#UoX1?k`-g"o:;.9pt/hZ[&3_hDrg@s`6'&Cnc(;+230,g4@;AmQX>30O.l(r<,2lO&3L.^%1Nb2rp_9=HJ?F*69C3:4*>0BaoaO'FY+NW"MJf"SekWc%a)SP*'0E3'U[`CGK8^^9+2%uP3GE?^kH4!#[M049e?+u_*_C0JmWr6&YKl2G>b6K.pQJCS931N!"AlC+U2GEH85'uu*:7T3N0($N[*RoQ$;t-$VOiJ"A9qZ,>C)rt1k/IX)YHm(3rPK.1jK-d,`eYaT\7DP3U$:?RcSMi>Es#St&T+,_r##/B+i[utgF+=nMh,.E3_%'#,f>qpFFqj;qtEHZdS;W\MEnaO`sIHq&0W=!#1&\nBB@:$TGMlQ_hZhF-P5\3&RTa6$gMV]?DG93ar$Hc5s=h&M,=W'MD0>bH*f.E2QWlRFfC:e4..[?@ZE;r9s[bIm!QAVp^!$$jrc3-"j8lR#DL^,@2@/Fg[DUZUn`Y-gRtMqWG^0M#\7>*W"Q4c_[G5+H$S:R?KTi?":S3W2E\4!cdKt&s:_lfBk,Jh$bod:-SJa"BG)-E?*o;og&8pc0\_5;?CIRkg;TtL7CAO$IC'.](!Sq_hT$E(M@;jq0YC*'2LG:Qh$goe>-"u19rfUr0NUo0FmK%k`][IWJo!e,Q#bnt!5E0JGaD@eLpiSI#?q$<>kfYa6M2i_+KFp]+D?C]&VXOHScc=&LcS)rqVOMbsgrV.jBYUsc"%0l@Ko:H^9PCN8Xi]Nn2-B2ipdn'!5ek'f=nX8[kE2MsY&If."euI/0^p64!!d+KkCO:&B?m#YbEi1g+9,TQB[NZC:5*/-//Z)t11S1b@J*jqUi6>Fgj\"KTodNr2Hso@hZ^CK2:l)k*Gr.fFl(h;\ecHC5/$O0X$6CD@mE9B+@o4$bqPB`?b^%7e15LK'Tl!_@cI`K%"*ZBK%SG;`;X>79,qk.pRT^!Ne;.pkZ,fg;s"$`pWT*hVgDoWbOM&\;2p]SHX@Nc'l&KYDB&]fY`Ccn&PLE5G0MnX_i8=5UV18gi_6)g^e>IH4^+S[JX-iDga0T(1K(dBb9q.h#??PDabj&0`9#Xgg2FOLO\E&grlK[Z9qg*L@TWRMF)m?mAqUF"oC+Sj'-Po7k":FP$A(A!r`l/Bh!hO+[99ZB:>dndGjh$/j/BBPh8*dnn^cXc4ah27kn43gq=kmYka5n?-N#^Mt,Yo=qIcq2pr60XY9rgVN.P-p.hbKE3#T\^Mq!m%o)8kk-t4DWO7W7-HjNZTmTQk-BT@8ph8ABRpX>t;r+_o@Qb4qOo"nV40c_UQgW4NIpVd%H[W?(.(FAl<$,$>c;mJ73leaO/R?@&Jr&2Z_NL`[)2sO1Nfp$^NR?VS7Z-AnNWd56@kp?AF%alqQoQE"P"L\ARZTB(Bl-l\\`;rMou0]A\J`S`]1l38^26]Zi=+*57.P!"O9cI(WpE$#[%$Ioo_2rFi"G4K(UBS"Q`ka7Y$^NT3M@mBl[YTCq.9pAqiZ(*3mD)Jd7=iL!]D[$0nRgf>UmAI32g3i'J,%ZSZsX7ED*M\jkKq)<#of.7cKc7t#eKPfg@Eg\&7%@0r:4[;3OaZDEhH+"hO(2/7t(B?nH774o7N#T#Il??kEt>ZYq(,5ajI\DVsY=FQs;/>-`cGY1TNXBDlGhZC5)N&25_t3%UN`K-jLC:`VdR#';%(2%CjjN;`>2/3WBDKs0Gs$$hfKSN`]'#Z3;-g)*)7>=pm5r,(BOc1`h0\BZNFh_1DE30_1]E]>?Y3*55A_b%("\la`Tg"<#.;7pPp#,nc1ruh0F;A=T7OLV67pj%`Z^(UgC:EMjN@D`)02m^X_20MZ'B0r#\Am#M\]@"bs/uM.?g,SG"_F(@kA^R[KYtdc]mDOj12s6-N=fTl8!=B^MeUY;a3lN'SH(9e_qoLac+9+cB$O8Dh:Y(iTHRneY[0bQ#3?:>eLDhb-TIp$GtFPEXV1GBRSQOtneX"="LS?t0rd'U4oLSp&h%5Ps-["q2oRE']Hbqt=++c-J&EX2Ap/5.I7W(bQuFpu4s1W3N@qmd7o^[:3Vu:\X>JeWRr+C"6X4nDL"=Y=bJVJnOkF^\e7m)qB9*&CX3*%=Dm?QK9Q=m:pF:`=9MqTMp1+d25:HnTmg<3H"G%(P[Q`I=(3c:Q]GD?PqP`>8)o(hn?NuBk_`aX'>:3p)I)D6WlG%qu<=F3<"k/,%*PEb-M3g?"N_kI"D63RN]>R02Xef)%Pmk[D/[(;Ue[OG*@Ef9@COWec)5K/@5nn#hF3ol2_6f8#t%I.Rn0AMV[jlb1LnF`&Xk*^B%^o%-S%eZ`skhm^juT->6.a%UK.N`;HmA+c/H[FeT<%GYkf[@:!gKnIItp\6\jgbj8_@h-eg2rUH5NB=1r/#/EM%`K9Flb2WaCOSD&\24suc$)BChYZu)1afYb&2kMqUfkl_eDo@>qfWj'$T+6M$,/efC4;#c':FocdF)/#JU"1&@Y=DdZgf0J@D9PO`9d"_Dm[Fb(,Y8VPe"Wq;@0,6872[;TFM3W2P(`c@U=@$[2&oG(O"2HimfYS]j>KQV0$L@4TCN2q4eJ7So5Q*T6heE`l.j4bRQ^9(9YrQj3.TKcij'I1E'Z2h+(QCQUo[>es+'2b3o+t\SZ"_+3b2bl#_X7XFL4Z>t82(lcY[G:t!@;uR#ShW3E$1VW"g#N5'Xo[7\b%'hE+-C\^]&W*\el=)KkbBAdo*M7mVu+r7)S7S)DP\(^3bo+1PP0I?T,'%KpC;W:j40d!klE!&GYZ=t4rCMCFTeUZgWOuDkoS%538="nY#WN]B:jU,$>Sp&.`"`*p=V\#m4'/uFGoPr(V%CM2p1D=\6p9eqLST64o_l2.@AJr'C\D\$W-T1P6G,1!#J%2Z(*namuC`u'cF!J\j;1Q'TZaTQP5f%Qj9CK40`\(iIXG(H"M`shd6lR[BdP&)I-,+_WUM>Ia4>DN0p\*qt;dQ9,ba-T%/FmQ_8t.j$Mrk)IEPYd%#X'h.;g9\3O0fV.>%i\%L71J`^0BD%kMRie7cD)T3KN_Hd?ZX'P&pRI/HnO]PUqhM_7me-AlM;]DC"n\>=7=Le8%QY5LBi>QW7Hae)XEU<0V+I+e/1ZYu^rJ"j*kEjB9Lt?t(M-Ag'm+f:$pG2=h2D.oO6?VehSTir.))7?P0"UMGX)9Ye?!1K?;,l&;#)An1qF"Z?JHG"&W7lc;)r_MQf9BCIi&m=jb6#0bQm$Xik5d3"E4Dd9[P@F_NsdNj]s,4!Z#HsjlaEmr/FL.>\7ugO8Ob^=e'jug6h.XKd9MXt5B&e#Ie7VXC78k\ZAq3rJ!qh"dU=ZE]eYa3n$d9^(^o!:gn7M^.ig,B.o;I(GuX.1Ie`#HZ*ZPN]f*PN!gF&>UU2Xj'B-hQ;`;A>=p#C^e;+QgQ@nlagDM'\0-)B7NV/tV/j*(>gnRbK'JUC4Oba^^sgI]^7W2]S9ZMfn9hrTpJl7&Bk2F%#HT/r3@h/VNZC1b[7BFWgRH&]cThF2L)$GH,L1_e*J3bMRm6_jPod9X_)dL*ZGuK8HtC6Q!P2igH6tn$@:?q!dQo0*"8V,1rWq7a>`PEeHLD>U8E+?i/NKdTU(L5AlmGbp4K=SP'!i4JcL"9MIGG0(g/*E(=n(F2$PAf_h-T4e.aqqM&+C8>Z9Cqt*bLRB"Z-1\2]+(*q3o4F[p82&:>-0>]H0&$q6iuApEum3M"'bingUBt8H_?D-2EYIeqK3(o@Z`tR%i]]7/[sO/ieoIl?b`;/ic&aOI=6Mg:XIMHJ%m)T^KnJFI.>0:kc(Vc\qZ"<[H?h=&jDH#RHK8??8QR5M$#AlhnY1fNU`j2iJ]SR37"!#I=eCMO-u*bfuRdH:aC37tQMY>YaE>DAPo(\"Dq&t%q39t3ris3&diIY&qSo5)UmG57lD3g!^m.p`4'(,'"R>S/n!TQT2uY^/$/UpK27Zt`Zt$Y:QklD`?LmAf"$dM0Zl9hc]mqM-/Br,H4V,OT5gk8tgq,_X/J0a,*Z(gL/ZS9pFE3G0&GST[n-$#(@H-pbhM9q*1G:_;m$kb=""=hV8.=L\?B"r':,?0Mh8f\MWqIEb87LO3Ddl`[IB_[`Uek\@F1(I7$thZsCqk*g(bi!WiW'^-&l,O4hg>h'_hg7`Ba(JRWKWcau,m3RdU4rWSqj-=o?]g%QAqB*u,!HX`#hor6;EFtGK+1Ug%$%8DM*N:BF)?"W*,=.\Sr_MX.6?YMe/h\:WnNUX5c_dCn86c9XQ7Ca,fQ<`U(FX$AG-2`1/(WAVJNuPe""C0olf+Yg'=@/ZZ/_tT.Os`PU!>'aTWE;sKB^'Y`&Mi9$*.A5W5%)n5O)I5#;4rg]#>*F5rW=1n+YcCb->I,:0?f"#'g0+0@jjR=rduhC)f@]B$$2^%;Zla4/))C$:9nQr?'Eq0fd+Ai'2Km,kEGMdfj_u.*`Kc9U34F=$pRu?C\kZ5S)Y:RNo2b&=@n,?(=l4XUZ4Ckc/Dl`Eg-Sc]D?,O,i9rIIOAJ6Fd2B<9@o4m9rehDFGknnP'FY0tSK>Z#:ak6@2f>FB"9l=!QEEu_DtiL[6c%PkA@m6!6pN[oqWO\*g/Jd*D1:uaI3,aE1fQT/oA[h`KiJ0_WGqNF8W(J-&`[H@q\T?rFYd_D%fHV2>Hta!ODf::UC5\KM%#(UuSH'=;rqsgIn-[r'^]jb>W&QnYi*_4%bA^$giT"[]Y^?WR"f$VE3SPH)kZ]*Un3P);@-"eK1#gT5VXdDi;)"@U'_h7KcTiJ+,%:\G5f*5Vs-W7cj(KKGf-"\4$3FHtb0.t4[r.a0QsrsId&L*H[CD@ebJUnE>Vn;q+m*:jWJB@L+cWhQ\8gP^XK9+WbkV,0gMcu]V)@ZFCg4f2a#kT!qDO:5f3NS`=9l?m`n&!.mTQr/c%#g@`if6l(6AfC,&+#Z7up\*ZHF[OE+'=cDN"joGPLZ9*_Dj$Ph'u'[,fm:1M5Ep1Rh6O'`qF[Qn^rigkW=j^1u/b-*\jS)&X<*M-+-TMdP7-%j83\Ke46?a+!L6fag2!Vlm0g%g%e4XaIu[BY(m(pYC;q*@=?D:P^_#iZ;[0MnfMgK`DqAQ!3g)ZE)KtgF0i#i;o4FWiAP(+"*Y2[e\j6&!cB_o`Q7>JF+OT[W#*EL;sn_d^j*q`kT*%MpBYsdQpYkn\gP77mKUjLf#;igX6^ND"MZ&]]Ij_Y>`_%dt@Eak>.$6nlH>D4ou7LF0^!L,s53Un#YiY^OaD.j2,RcJ0%DjX+os?!VYupEsD&kZ[OZ>F$\8l\)$3HJ!Rihjcrm^(%nKfSP_ihp-*_q:6]j3\:BLmgqGE/9eoA,_O't);kJ6el-QZCH")?`)I!-Z(LKLq3*c_8N4//ET3kDo>A*!eM@2$NG2eX,c"].J#/:#:?b_'QT7?jA=gO]Io#ZRn(XATK0X)".1uMo-G$$4#VIsHW;?kU94ae0$*0r6bmZ%os!>fjS6"T.TmdT:QXg&4&:]cPuJQ2nL(cL`F^]46S9hikd"QML1&bZ&W\-)]DHM+3!S23cs^nqZJckS4`T0VcaYJ,]n4XS\r+DdP2o[?SPN"P=n'(/]lTJ2'ZPEjZ'PXakJTL"27jl[G#NIjJ"D$j4/Mk71IlbjHlWX$V.P@E=3H&kI&]`Z"f1#gF'5Q:e>>orp8.WV%f55OL'Z"(ga'G2;7--?@nOT7!HZDnSa_tBCF%cXBVF3\Rk7#08JP\=[c\=hjdWDca#bA)4`"[Vmg'^OF()DuFP0]\e\eFflcC`LEZeWM>/Y>.U0C"W:W$IJPUaK<^&g[X\=+@9u-tYPES8=P%_>EOZ"NdKjAL'PpXLFj\5!Pk,Uu:ZKJkr;H)V>.J\([V\*Lm+Aj[b>p;[J.G/1*,R[Qc(hKSG:UgpN1/*13?G[A!Qp?6Pas3UGtB8fC4KN5_dTAQg!#@Ao*[4aaE]rbDdd,6K"__R"jk0#_?nV%$f+u,[,!Ee4pIO=Q^85Td-8K[nY/C9/r_[`h10JsGQlF(?bZV$B4TOFW/buVH"4L1iDs4]p65kDT(<6C;]ib8R@JYf)5&Zoc.JdYs34C1Y9YS4u(n;rbK\"oFCf-,G8o&@;g(L=$GbhDf4`Bj;FP34MbEZk6R4$[D?=7>pq$l!>!Ef+G^hcJk>4KJnBN1QBnt:sDP.9jn1C1OCggl?VT@RU1M%>MS-nHhM7aCdg6DgXq6%\fF%Q+2\_hRL+,?R@2`$2RB=u?B6I*hun79kgFFde/\\%>gm_&LmY]QORA1f$E#&F\uA#CJR6.(p];D45-dmC\UDX3*jQR\aO-GW(aHbZN3(5CD0F7,?ijl0st@oQo%TqET9QR1G/7*l@X%/r0KW9:]_>R,RWSa,:m=C9DRc=k@KRETRRk)^`6Be+F<(A%0WXKT*L[?dG#(VO997X1n1I@5S4pA+Xa6Bqci(TsFrGY$n:J\c#W&MZDZ``l?XpHlkiD$1Z6%,%=NkjlnMLQS,3h'J(%+5N;8L_p1$D.MV$BuE^1B/'2c4Ri':rq*,$<5M3-;+V-#B=DDBFCp]X5#XZQ_h>RkZ)ITT['Yd9hKam['D%T8(HMj7l;ms%3_Cp&SH]mLUXa<\TtlAfADQ#f*%k\TP_;ul4M%TBf#%pg`Z&ilVl/#C2%9lqLX@J#8e)9&&W-$JIph=sbXW]nH,`-&Y:pQsIamf"UXjMd4TE+FtFV>.Mi3)BOgZ+UgpJ37R#?.TBDJ0oK?YQ.j4p0ei[+>AgtTfRO=:&ZGs\Obf:QBo1/l$6';eDYK);,9u6/479>\4/,V@>8H(gS>W>VWhEOWUdq((c;fe%@`:Tq%iSSU"a^%0BAedJqXrn&Pa8l9"KpB+hIKp(ckHn=MdT)XDsOfhbq.WmBGV6q/opMmJd\WH6p52DlDq,^q9jSW(Y>'C_c?FB36/)'QDED)42:F9/+B]KrplDtqXHBs_?H1kXge:A["VhO_j+4/>U63I@L+9bKaZbP^f4OIDI_tj17CUp=W=AK#^*UWhfR=Xn9QL9An5GS>PAlT64dM#X'[T20c5E54o?%[a;'QH/r'7TNkC#1+Q+Z9uG3ViHcta^`<7j>"dh/Ob#e@ZJ4.a7kS_+Ok/XFM%WF]oXgY\;bVRT-L,n^<>?"*ehR)@cJc5AO0E]M3=Qc56VS9d9:3Nj$6%_AVf[tH:\`_oX+?732I%'(%$Pk&bmVl_IAU(@`!9Pq?qAL+aA.%X65LS5m`XdN;RN=+Q.<&+'FK.+KYda:E!SW5RcGcM@.`1g`:>,kqOPXutSQZb%g;VIh[#A<4YD5B,Z2TLgO[Qg3gi.Q@H>;`pWOTX(J"lLD".2Jqo[ZQ%XPgBOp:C*XMY\F%F4/''D$LlA%HsC*pft@MAT;]E5;eo?+/TcjFB$fR,IF]EHD>18]RGjb!]bo#nBZU`e!:_OS;9JoUZ)'KVk2&TbY1S_=OFLJNjPJr_piHt-?8J`S_rC4g!\;7'buM/?m,#cH$PqC9p(PhVO9VRX1`)gQj[S=6+$uQeRac]1Ge#!(\(pf)(o`R(IIT'rqbr/qt;m=Z"gj2D@Np'NUr5C[jS%I9/$n`nlr"rGdM_'S*3GMX9$GR.9%05rf"-Wmh$k_V^a2S4Ak0G3Ah_?hU(rUr?qt5Am0^QE6G_'9gKK$0C(OMUp$2hcsJoJTJl_2;YHK,)S:q#ZtA<4)N^DS=D\M1[?bIX>4C8FOYr<"ED8V);MWIT$N2kG18l3%-pu4q\YncX-\6<$ZdH[,3"YOV(7WS)-A)e?RbSO6PTV-g:QR&'W+ag#oRd[lW5/8%Y%?G`l]i@aJrEPa#!20MlpZo#tdC=cWCJhr`X/Jd\RZ,JI.D@X1I&WO,+o"sanIDGWPZ3+j9hHF&>Zt'1+#0,X@)_*#j>:FO`-)Tr3RNK;f;r,u#[lZEqV?AQN?8$cIMdsN#fl"$\!_6R$SE,@SM]\c%mEs40nPoH846]LdFN8&7qZEO6k%'F74KgK55k+0'.6NZ3s#h9D)VnaAr(4C>h7g`Gc#uj@Mhn5Hg^\sLFNCWJ@XqlXGC/oYdPTYaWQfi^1hHpXBN%.Va(,_^O?9pX_g-LWPo(Z3N]g$'L69tg+PaeTKPi*[CLAAC2:_CG(FLJ*MKi[.OjHq^UT,dgi.E4/'D7K(rX2gWStYs-aYEAMQ-D#-,G<8WDh^V^282]P_Q)j_o!Fc^PC?ea26*[E%oL0blUe/S!U"N!ZPGIV$mAqp#1/hSY)RlPQP.Ar]!SXg-lJRR+A2[*h)YWIRL4aI&)a(oGToNd>hCGRh:1p98>+LHLAhJ]i?g\U;\88nTDb;\>,o_"NPGR`!7^B_n3i.jX=)]J\,9q+?3gsHc^9q3nG&u>%99iRfpgmh`gu-_h/1)eiYs)2^X5$Y9$sSCth&?S5E=q$hD1d"\H(I$/>R5+Ad7\:=QDi>ekQd%L)>a:`0QsX,^L>6IV9>4?^1bp#ZY%Gd=Fbo$qU[YlH)msFJS0L_i;"2ll*LVf)?]=J%#4*6r+.t`]_:(Z4S$R'1M5E`hgP7VF3hO]^t`&)Gf_o%I,!#pKOnc,6^"kX^P;/Gju8>MU.4)fbEGn\s'rEDW^&%TW@ZO-Lr&BN.V_HO5/m+"#qhHX2=YJW=bi6Ze^ap7nH09fgpnBRCrl+&-[n:,p&fgDo7+LE`Z&^FY-"k0#.7/1-(B9qS%"EZ-01e_E9K69Z,?n@OD1@"RGm,dMmIhNN#9r;94SlP,bgE@dUPsWV%bcWE0>)%).:\f?k8>m8^doUIW]W##WCTR"@FAqE$RP%04.hMOCot]q>RfmR7RnJ*D4e;G/O%0-/G_fP."V1`S2ZLuCX`Ar'<$&f$Y7YA'.50M(pX%kbTS-EkI,]B,Ml>/pSQKt,R^FW#H?X*2)B_a%1KE;]70^)o]B#3Y.[_!r(-$[-k=F>D3IQ/>[=E>`2]U!7c;pLRGupl)%kV[Iop8\u$$fDU$!I#Zf6Ebh:R%H0^D$>S7-N'Sb14#Z2@PlRn3OYTKtsNA*H\?#`S)qPB?HdD8^?nDP&^A@*t(.JN6iu7r/*RstB=4=$@"#D)VZhHKCN*^3qODF8].<>I?#UhsW=H1Z,\MprIA,:lOb>H.5P?7^%]ia.dR;hO;giCSTCY#T+F]PaUE.ZGj6D7D[De>3C$^%0]5Zl@eqbIo_B/SmUH\,R6uM+&#=hfoC9@@W^@q"tEe=`]!26GD!CkMddg$9u:o[Db8P,mIK@CUm[@W"k?!LY4UEBF?c\q-<6GLIKET>Qaj%7lY5$qK:G4*.sK;VE=nP`48gq7o*?!ROqY0N>`Y5o0CDVb$U_iG9HFp\3Q4fK)0$l;W6ZNlI9HqGORRr?$/=_(ZuUr6/9E+/=P)/I@h4pV\p4J%5r'tmaQ=WgifgHI$0kF?URZ:E-O/_Zu'bYLr-ccO9J0VILF'8MShrPQf2]DRC&DO`leJ_>]AU*i^+Gj;9G!=X7d/CSce1>h.&(YmQB06Lf_+k!*fdW7CGFSkRAIh9E@U4[WZ)7E>o;Cmfj\dRM=cO!/9P5?4uA;6Ol$&>LM$ZVF-L<9H`*UY.Mt?GLJhe-E0(*.je/RUD[6p%"eB%N#6f1S"&0kg'&jc`'K"[#n`0DeKCGg5[4X!'9!L[_WG;n].iu5%:"/&a3&ou`)R2PSNF`2P,)tenK+ZGn^ra3Y&'K_oih6L"YS`-:S/WA?ZFuBZEU#s.1cc9Tg11.?DA?hJ^<;L_[23_T3o[Y?T`n+=;IdRZ#$M=NJ?@VN=e9W9'?ZKW=ud>DWJmd_@]F3&htXXSDmdt6,kuL(mOgM`5)VUfpr6ulK]CqZML6hdtCVXAq_ZfR_<-=+*SWoW4$P\>%jVl5B,Q=lKVPZ63/Y`<_-s5C)pQ8C@cF1KFn.4UJDSUi,H2^6oulp*=/H=3?]<%9=BN82"1OR#X'N40U(KB#9T=nb9<95cA[j[lG5G00[XiU+JQ;0+;&6I&2*IdLU^5>GYp7g:X:"FIUZSg"-\YK,df^bFocQuYsLQiNRqOu'O1p^F`jKc;+O&O%9C(2J^iRgbf8?p",Y:T6EObM"=JOHpYW^rsO5PE9@U]+2)RN]^Mq2OHh]mLN%p8/eTEcJ8a=0Gl73\rb&Mn,5n%k"[lM.2]q>HBDrSCmQu+h<1B=QLhL"]cSN=0SA0Bf">$=BfMD9f70'"A$a[]bp2[I'(6Nc$!`Sr>uYPlS/`oo2%WmXFK([iTqd_94ICr7"Z#KC2T=fWTMfCs\)*l9Y>J0_)t,huHPeC!%2(G^r#BSXitae0"%nZd1i4WiN:k5QC9(X$6bn!cZQp"h&(ePm^1N7M-pnH)RPcf\@GhZ%Y2\^br(hGYPH;A&h=Bm>f#gK#',HGYLn<7E+5f>IU_;ZhDX&hd3\RfgUQ0/qg%IJcuNgIei+"hYTAs<`ZZpaH9u?[C(Iu+&?4$Td1OJXH4^,#EkSlQ.3o)d`JG_gER1@at/dl'm5@(\<,4NW?WP%NB4X6iZOr=6MXh_Q\^;&8Wk@<7M7=!8Wk>j;V.cF&'+95(B~> +endstream +endobj +7 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 595 842 ] +/Resources 3 0 R +/Contents 5 0 R +>> +endobj +8 0 obj +<< /Length 430 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gas1Zd8%P4'RfFOgc$sMdbCqlq?SPWL'34L`/"qF%+;XG*J\,^=i=?rnQP=;ArG,QY0n6*@2O+_W4%$,_KSbO")_AaMagg;31GANlS)a4s2GRqPNUjG+mF;8ts/30e/BCUY]a89-JQj9Tr5Gp9"E(BrcO?d5P(hbc^t;Z;kOj.aYkWOnRgd*$9#=&:qrbc$/e<6&RP4VN9)7)`iT*DoY97.WSlG&:#d@B3F9f'^"]\Nejj?]'BAgrI.c(5].8=7sVOdpcgnptZ#[3i'LUq\%SADs"[=4_&,/*hM[gru +endstream +endobj +9 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 595 842 ] +/Resources 3 0 R +/Contents 8 0 R +>> +endobj +10 0 obj +<< /Length 2747 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GauHNh/D(,&qBX_Tf5&`QPN.i++9':9@!hZmD[(NJSlQ?/_AQR.rP"4Vh&e!Y]*kYj`*faGWBU8,Y/8]E-f'g6\Mdd73g.Cm@>dd@5j@u(E_#;N)r!1G4kqpXE"V3l-+51cUIc%+u9E"8Ji\MGE_o8goJ\Z0/alaq0Km3$>?mHBD`$meU;uGT;>l=3QG$#]Clq+UF0_@r$kW((H`rG]'+5*aA*stW7&5B>G-aO2A;LA*_+UjG<=\OF/&$t0>_3LOHdNBk\$#Eb'f%bX0%S2aN[a7lPLMi(jmO*[C4;?Z&Q3Y.K3Mof?=#Ou@fp4N$>i?uqcEOZu#-$mL3YQs=fr\/egWX#R]XJd$dI^!o1p0F8WKF#ml(X_3<$ON1+?kk"&0-dmkk)kNiHNR$)6R[`Zt=j)f7mHBrV=?$1fC`"PPY1:O8!2=haMH!<k$f[#X8ho]-a?'qe*ZNpXGE#_UtB.f^+Gltjs=H\UYi.-+amKVM_[>+A0V3/(\Vb2j^n(#f0r.+8rf$P\RXMa(S,^r(nX/8M4H@S_&,kGp*>,:jEo/_$6(XaLegDUZN7'.S$Ct?&LBoAa&/%R=g^:SR\PkI6:1iJnTrEY(Cq-JfSJKm[X$72h68.O0nm@sKc@U@r[]&?0+[fZ4+W64POP!ILT(K1iC&''Y)oo0g^>JZ+-d0M8q>ZCDh<(oY(*KJ9W9U7^gS.91J[K6"@%Y'_c@Wc;gr@toFD`%QF>9.F4AY*S&j81=C0tP/nr+'48IZlZb'MO?!#-km`/>n_"oEJV51*T3:[u?0O>/u4nRD$22S$^tIeS_MK6.1S!,PiEe43eWZY#4l53NBNno(USLJd>sNF(&/T(08O%,VQ]"eQO@t7M>+p^L:h4$^lKUq9lM/SQ1K6[U0Sc4N[^e_kl)UV]Ot'-4YTSmf$^a%ORPU;XPmf*V+4[.?Nkd!6]jRU^!kR9V$SC)AVJn]:h=f6K:8,cN46m!$K>UWQ7#Xb[/HiF":>`W#2$0C\VM'oQHoqJt?JZEtK&Kj6=*[[/BMgbL:1`7s$]VuF8$d"FA#AuZr#)Ng`WYa"!_:5"HJeO]6q!^dBr^="ul;Jn-#7LkB[8sH"dc->C)44!*dI"*\9Mq_-rX>!fgX0\IO4&"pFMf\H)ZNf5mglXd8nW\[I;BZ+cH%Y6la+p&>Z1FSo?)@=@0BHRdS"H+I'&DJ=;ktm/1W_[`DN]Cd\-h+nhRuT#s[sW4Nl)P.,#,]$/T^N\Mkk.GR`_2a02cGGi*4?Dgk.l+VO!mnqed"KBYG5-j#;ODqLNB/ak%#(,(-V,+,Q(l&`Vc'N&r+5nSDI"a/]]oqHEXNW"6.[,D;;G[DW:Xfd_hbtF4\rrOAR+>QESqq=BOTi4E>T&TtqV)?PPL8W*h:R\cAh9-g4kp>'=1cYggiXWZAb3t.>Jm^!iUIkKf$7`LaFhiM%R#*!@HGdp?K0...$[`CJGX'\@S@EH0ptAbCtqP+[0@:#MECgE*r7(P5DmKeF'V0r"Xgu6;2*bpM&IE4300B42U-VPXZ/O80SgIE7^^pJXJ?0:-78_eMYQG?^#ls2^[=*QHkBM@Bd18`aJZu$$&_PjZ)C"6H-Eq%K83N]=Z'b/u-0dnH))Qm<-hUL$9R:^ha0C^%ZF:>"&`n%P"EPM)aW0"4u#>8bo"NWi1lHC'2J^Ih?cU@gC+aoA!N=cE;EW!7S^7,u%0U&3XB,\[@"o!]jZ!M"rfUSr-bDOqjoG,)KSA='q+0W]o7q[bZB%>:o3\+r<\R8ON=hma"johc4(@(e1JnV^u8";ah+hFkP6aM?R\rpN_F;XUnXd6mtr:)0YP;p570KqQ/qFrIdjauk5u+N_A9P&G2jnE]oo@eqV(F9IRb4j+&O5fLnT2K6%e\B!4&onE(8oO@'?QK,Wh_f#/^$[0Y0)KIU=H6bk/C;_%;YUa,oAX$mAT9NI86Fb$Ec0(U?>D`HL6UUD\J-D8EN@U:1Eh0LVCkJg*)X(fMt#n\h@>I8%K=3iCdIW$V/lHAhaY[ag11X6lAGT-@SH>9$eQ1[jYUH:]b^/rX+OZjZ&"*mZN[5!`l8&%4^KJ2'I +endstream +endobj +11 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 595 842 ] +/Resources 3 0 R +/Contents 10 0 R +>> +endobj +12 0 obj +<< /Length 3758 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +Gau0FlYkP!&c_:66HBs)J@4A(neq(G88q:m_X60u^*5hu&%"_b`)38GLLL5W*HGLC/!6!uB_'!.+#uEh]q9oMA&U+9jW"^[d^,s_+[m80t$XYNdoTN)-VZ&PQB/&L&,%e]`(S5NPg*i1;@]Ni!^S]\O*F^FD0RmQ[^l8o+BF02NE5C.Xm0Na^#CR3;n_`RN/LLaFrWKNn?K-G#>Q]obCYZldm:cD:<6H20ZnFWRZa^k_]8(2Q[;Q9h2E#2i(0"VU=rZ@@gR$hWE4K$D=WL>0Vuu^8&SK#T'L^3ZTc4AX`>LsIe@kk\)trq.ibG3#somT[kEcchQ4HQg\o@GH'3ai&9O9lD]XgSB$N^G/;b_7b$VN446acG*:f=q`IL\O71c[KoB*GfDe?A=6F)D;Pbmg2KKumOAP>+uFgFq8`fd/^cS_8!iQ_Dqq[pu4"[&VZT%e!t2aYkbb)GmVY0n&sK,mg%f?q3Vl`",_)4HLiZr"J07g/"a%R%-+V^bg(hV@qS_E);F),FlbZOG;;SWJU3h*"UV_U6:V,M[Lekg;@M7(WcNa>">sOEShR6&lhVqNPB`)3e>Th7[I8'QBc\(d.T`*=O\=Qj%s(eMo9V6o*!LZ@2e+.3"0#2oWM15uKdcNhS4<.2R(/lNdC=N3\g^?@#jHPp9GS]L$'-:JLrHSN7,JY!74'ajAO:[H7mZ\r:ES[qn2.coeF@Q93aU9/3!pbo6jig'ZomJZF?UV^S0d=2?i-RL[6t=4nQ\>9pA[fL#6XQ[giQp^PJ]M4qU*JYTYs`3N"PrB2\7Cp3-OG0lD:!DYi`9r1keH,rE0D-PC"0s_P5#Ne'721RaQQ?6](_naaL6->(H08.IS[BKG8KZo>]4iirnERC)j7R!$I$l&f6qmf:?,R/e'k"isR-o(LV@qBJD^nMdN/N?Y57H`,FS;&pNl!\.Mb)m#@8T,rS][Ni8%*j:(CF&Rn$u8lePZWK:DG-?mclapTpEai_QrPFK@j%1YJ70-R?UDsLFA-t;bgHLF/.IH\dU:WW%A:toO=u:0#t<+e%cEhQdtH,6`!rWq*h`X)"djUN"3-Z+iq7.EAdTRDTa6b!Mt2g'nTHqXs$WL*2tb'=u)BG]j;DV!I)`oPGCY#kS+ON)>?Ed.'P!XdX,%HT923.j>N(Q7EqE=Dj;f>Rn1\;W5b_\*^iHo1TuSh56-38dN9Ge!PAioAk]fFrlG3s#M#c57[(!t;;%W+uXXTrq3!SA?:9O@Y;nNt5W1T_XYpi8#ae1!,g9j+.r]1X9KA7K9I$K'l5L^qYU!bK[10^j&q4R&I?E>UYWo.sJrOjOLjd6cfu94"s"KWYKctY5I5ZoF)0.bcVqr6I<=g;deUIg6F>12K)PM/qtF)aU6Se/Q@"U;EZo1].WrXAhFd4?S,b9[tPUkS%9@8K?8^=h^&s>b'/.(d[E^>d+](<$#S[U*N7k3b#UG-/8@PJ!?1(!`eq;UkVM7L%"43lRg3`/Yk-\0i&@!K.^KdkpW)*nN$QTjWYqF`g(.\qCpSJ52GO_W`-p$L$eu$.WPgdrE^SRP5t%)/u'Bs<#L4]NBiB#)O7'-$Y8c<\k%&7HV3QuM?@t4j-l^Wr:J)ulCQFR]@/nT#Mg*7-MRAINOMBt/70Y7P@d88K:Qj%*LJNSQi_?YDod7E'S>%T5&hRDHM6Q1Gs`WJL2m_^HNU9eP)lC1[jiJD'8L'tDn#FteNTO!!>Ft!ED5!Je9,F]FFeh:M8X^Z9Z!6>hK7nc7jpm&]"j1i(MF0&q6Qs^%Bi'Uc)+Tc4[R@ueO\3421AaUM&Y`qmI>.L2Lk5(q,=iq,Du7#f._&84r_hZD8j1l3KnRd.bhg@Hk#jF4D2=9:=0^eOhoP0>b7)j750mFG:e%2kJh=?P)H'&*)$WpK)D_&!iVP_OHCbH7&K%6\0$Dnl_4ic[nO0qmWa]H2`Rc`A\s374a=&B0q7VI,j.*_1ZAN@khmTOC,;PB648UV4h=TJul12LuYNjrDBM;4QiT8s6,lb$D9/7g(@+,$dE.j'.>UrFE0cc&n4@\]tIQtqUp3c"Y9mpL1_ek^N"4Wp_4,4Kn%!L]e&6Dh,5Uf&K3l=9diN2RbjURe9`[69UdV<6WJHRY8/(c_^T$Q2+K%O:T#eO+gH1\#(^\aR8VQ!oB*.cc@Za'pZOg`.F!g7g-EVI8]5i)_ZD&*0RJh"4MrlOM1n+1qj.$TJ(ihH&qSo_,!ZPWKo-39C'5ncY[dB=dGkJ:UNNOoRf0NQ7.3&j!ek/&AiHiD,8$90(h`1*oDl0@GDd-nZ=V__A/dP4Z7lB?_-GKB`+;J?@/l_bWF89rq,emKTs>"[-'nLbVPJBUS-SWFDSn@L<)>_@VFHQ+\3j,%[5XC/hKIY,^Nkp%Mli''#>h],5eK+#8A?oC(@'D%RMFeVXkKOj1&ZV^_I:A>Cr"&b*_a;JD6!b@D(qW!M7R04SW.g%&0WUNC(&Q/g\0Ett:e<9O+#`G2YO"`B3WJiXM,6SLKCCH8!m"spC"qpK^Qk",q9;ta +endstream +endobj +13 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 595 842 ] +/Resources 3 0 R +/Contents 12 0 R +>> +endobj +14 0 obj +<< /Length 2533 /Filter [ /ASCII85Decode /FlateDecode ] + >> +stream +GauGbfl#h>o%dZH2qu-P9sWG7p2),i#IEo/Z=@ea+NaeAC>"8c-p3IA^Y`e3>HDRsP_B8B5F>_e*F3lS5!<3-h2@9U0mE5r^N)9Z=5LrN5Au`2bkJbE`$=F9Gk4mPrj[6PS+a$lhJO>$$cYOTMTnk(SbIF'P08R]GLf9r/Jm7eD)r#iXT_7BMg4'BWV+Lpq:L+gTY@.5i09PCdd7r5Hdh(Z?d'deM/l/A<_6#Z>9:;?5-Fc80Cga?D-h'tnS$D+c(CK'Iiajr$g*&H,P]258h]buC*;R`9EZOFN&IST:6Ec!*fdB`XNrTWUke?Z08#-R':0=.f_Ceq(Xj2:moKi24%(G<5n9mohsC=4`<.g-nU12HFjJ",QF::>##5fGG^$iiFdRP7^;`BjC6#)uAihY5JT.#-uEh;.[^(Q8B0/h'+&-N5?N,3C5oGY+M2b5Qi(.g#aeQIi?,qteujPs4W_ZgfBdhkU)oQc7mu@1Y0]nqk,:,l">k%s?@C;@^^qd'a&)BsTl6(Gk&3o7VS.\>P2`4GY%F=N"P4:LlXcYSDNKc1^;@0q!%Rh,&Mi=dH8'3a33FkK+]XHV<$5UW=(G\*ekgB*++@JH/%q`)n?*,1s)kmhpgAN#k+_Ae?`1dSZjt/$)[3'm`'r8)O&;pW2)F*"'[ij0>_ec3f9E?t0s^m1:HGKcA$4DUTj8=M#-7LSi@I^;LZarqPuijqqM8[LFYN+)TCS=t@>'I1?9eiQ:Mp>b`$j=SH0(KF6M%Gu6nbn*@lK4FnTZ`("1u"'gL3oDEh?E$#8Yf7S7>F-/#HLH(U+0?$9S44J,:J&dG_ag3"82Tth?]oHN3S?Ds35_,je^LQHZ?.T<3ktC[E0dFu3RuE.Ws'b^OBU/*)/?W`P\a.i@`JPg%PrWY#8#[bUO_:aDfS`,4ZmaH&C8u?C5ND!MC%El/iQPTD@[dkP#,b0Rp\Y2I6g_tBH$aVbm6=;-Q`_mdEL2*'h;3T_ZAKU*0YYm`(rp@AX:Vn#EslL.$D)d"53(TY6U33o8O=3FI,:Xi$i6-(W7K4TrYNF.m?d4<47SL]#U&fY(Bt)[ESa_j!"+EJ753:e&:,m`I#EdOQ599+ZEa"r/Co\C,Y%3U'O.%n5bT0uktV_&K*$sq*&U+)9,+c]a0?@EYDJespi_WZ[>WEeoT53G6$mFKBu>;/8^1R@ehI'Yr;FjOW36]jBDpJAckM$Jk#L.nI:d]h83lCDo!-GE:&mTD6b9kUq_4%oYBlhegk\mf1C515,4mH.%[l.TDZ]34FTP\D1.&_s7A9LO@A^AB)pFim-OUN*/!kVr$lbV8F\U]X!RMZJ`NFa_RI6GT\STYF\7!FT8I=E:8rujp$jM"f'7H.3Em7H*Y[%f<)XECb$-!^o`RS\7s+2t3jB/bGc!OIfe^"kCg3:&RUgd=9oZ!so-A]A'5]9PH*d_`4fi]0RfXiBL\1j;qAsAa@FP;dT)fDgXB*4B2[^18,[!Pf>=#^G.Fl1;hSKkVmRP6%.g.%UV@Y_c1SLG-(Q!=InP$FHV0TL2k)S'N`Q5H5Z!2p5&R[:g3#P0(97+]%CQnM]E%Z)%JY]fpDADof_PtY#sa#Xj$I?7XX8IK/,ok<'*'ej4,2Psd\WqBb0USRjLg#o?@i,0P2ZXZH_lc()&-9bSgU%8g@kcBDI"[`M$Jdaqsc6c'nBKON%R*6-$BpH1$\(.naOggkb"V"Z9?#n:tm)u!8N/ifBKuO.r"6[ii&!MqC3Pf]Ach.%MpF+&75!KU``PZtdo&/m#eIW-lPR*.[gcg\:(?elZ28l;dnMK!S78r5'5$-rn1p9).2G5i"\NjN]TZ;4qF21rg4KkN*]d+i/ET5Y-/[0="\al^36b?r;nk00*%B:056eFh1Xt?J;fOZ>J''MNA@`5FgIVEOEs/.q;=T`mm8&mMe9lXR)5M"Q8SR5r-#`R_8Vgj2;F@='$,N24)lVI`,B.>l"s0")Z]7#=3tg?:j+\V1:Ba:-dY!k0);?a34p$b4H]Y83_)s@cK%/KJ-f%8H/#r@A`?@9N?]Y)eJOp!GBf*o*h40OA/g&qEIRMJ2D=og#iNiON!K"c)9S(\eDG+Upj45Z\/\_op7fiPhKm$Xt(SAUR57ioX\H`9Y`=4GPV,hfjSs*gl9C5'-IIbM3/Ci9dCT:`:c\cP>-bUX$OLZ;,6WkFa8U*sOqFE1N0Fn_a)2P9<9Ip[V%5--/%Xo4*`HPfg"UEf#.6Dcl~> +endstream +endobj +15 0 obj +<< /Type /Page +/Parent 1 0 R +/MediaBox [ 0 0 595 842 ] +/Resources 3 0 R +/Contents 14 0 R +>> +endobj +18 0 obj +<< + /Title (\376\377\0\61\0\56\0\240\0\40\0\117\0\142\0\152\0\145\0\164) + /Parent 16 0 R + /Next 20 0 R + /A 17 0 R +>> endobj +20 0 obj +<< + /Title (\376\377\0\62\0\56\0\240\0\40\0\102\0\145\0\163\0\157\0\151\0\156\0\163) + /Parent 16 0 R + /First 22 0 R + /Last 28 0 R + /Prev 18 0 R + /Count -4 + /A 19 0 R +>> endobj +22 0 obj +<< + /Title (\376\377\0\62\0\56\0\61\0\56\0\240\0\40\0\101\0\160\0\145\0\162\0\347\0\165\0\40\0\147\0\351\0\156\0\351\0\162\0\141\0\154) + /Parent 20 0 R + /Next 24 0 R + /A 21 0 R +>> endobj +24 0 obj +<< + /Title (\376\377\0\62\0\56\0\62\0\56\0\240\0\40\0\111\0\156\0\144\0\151\0\143\0\141\0\164\0\151\0\157\0\156\0\40\0\144\0\145\0\40\0\154\0\141\0\40\0\146\0\145\0\165\0\151\0\154\0\154\0\145\0\40\0\144\0\145\0\40\0\163\0\164\0\171\0\154\0\145\0\40\0\340\0\40\0\165\0\164\0\151\0\154\0\151\0\163\0\145\0\162) + /Parent 20 0 R + /Prev 22 0 R + /Next 26 0 R + /A 23 0 R +>> endobj +26 0 obj +<< + /Title (\376\377\0\62\0\56\0\63\0\56\0\240\0\40\0\111\0\156\0\144\0\151\0\143\0\141\0\164\0\151\0\157\0\156\0\40\0\144\0\165\0\40\0\146\0\157\0\162\0\155\0\141\0\164\0\40\0\144\0\145\0\40\0\163\0\157\0\162\0\164\0\151\0\145) + /Parent 20 0 R + /Prev 24 0 R + /Next 28 0 R + /A 25 0 R +>> endobj +28 0 obj +<< + /Title (\376\377\0\62\0\56\0\64\0\56\0\240\0\40\0\125\0\164\0\151\0\154\0\151\0\164\0\141\0\151\0\162\0\145\0\40\0\145\0\156\0\40\0\154\0\151\0\147\0\156\0\145\0\40\0\144\0\145\0\40\0\143\0\157\0\155\0\155\0\141\0\156\0\144\0\145) + /Parent 20 0 R + /Prev 26 0 R + /A 27 0 R +>> endobj +29 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F3 +/BaseFont /Helvetica-Bold +/Encoding /WinAnsiEncoding >> +endobj +30 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F1 +/BaseFont /Helvetica +/Encoding /WinAnsiEncoding >> +endobj +31 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F9 +/BaseFont /Courier +/Encoding /WinAnsiEncoding >> +endobj +32 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F7 +/BaseFont /Times-Bold +/Encoding /WinAnsiEncoding >> +endobj +33 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F6 +/BaseFont /Times-Italic +/Encoding /WinAnsiEncoding >> +endobj +34 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F5 +/BaseFont /Times-Roman +/Encoding /WinAnsiEncoding >> +endobj +35 0 obj +<< /Type /Font +/Subtype /Type1 +/Name /F11 +/BaseFont /Courier-Bold +/Encoding /WinAnsiEncoding >> +endobj +1 0 obj +<< /Type /Pages +/Count 5 +/Kids [7 0 R 9 0 R 11 0 R 13 0 R 15 0 R ] >> +endobj +2 0 obj +<< /Type /Catalog +/Pages 1 0 R + /Outlines 16 0 R + /PageMode /UseOutlines + >> +endobj +3 0 obj +<< +/Font << /F3 29 0 R /F1 30 0 R /F9 31 0 R /F7 32 0 R /F6 33 0 R /F5 34 0 R /F11 35 0 R >> +/ProcSet [ /PDF /ImageC /Text ] /XObject <> +>> +endobj +16 0 obj +<< + /First 18 0 R + /Last 20 0 R +>> endobj +17 0 obj +<< +/S /GoTo +/D [11 0 R /XYZ 51.692 679.701 null] +>> +endobj +19 0 obj +<< +/S /GoTo +/D [11 0 R /XYZ 51.692 592.376 null] +>> +endobj +21 0 obj +<< +/S /GoTo +/D [11 0 R /XYZ 51.692 544.751 null] +>> +endobj +23 0 obj +<< +/S /GoTo +/D [11 0 R /XYZ 51.692 101.551 null] +>> +endobj +25 0 obj +<< +/S /GoTo +/D [13 0 R /XYZ 51.692 327.769 null] +>> +endobj +27 0 obj +<< +/S /GoTo +/D [15 0 R /XYZ 51.692 693.551 null] +>> +endobj +xref +0 36 +0000000000 65535 f +0000035440 00000 n +0000035525 00000 n +0000035617 00000 n +0000000015 00000 n +0000000071 00000 n +0000000782 00000 n +0000022801 00000 n +0000022907 00000 n +0000023428 00000 n +0000023534 00000 n +0000026374 00000 n +0000026482 00000 n +0000030333 00000 n +0000030441 00000 n +0000033067 00000 n +0000035790 00000 n +0000035841 00000 n +0000033175 00000 n +0000035909 00000 n +0000033308 00000 n +0000035977 00000 n +0000033493 00000 n +0000036045 00000 n +0000033689 00000 n +0000036113 00000 n +0000034073 00000 n +0000036181 00000 n +0000034376 00000 n +0000034671 00000 n +0000034784 00000 n +0000034892 00000 n +0000034998 00000 n +0000035107 00000 n +0000035218 00000 n +0000035328 00000 n +trailer +<< +/Size 36 +/Root 2 0 R +/Info 4 0 R +>> +startxref +36249 +%%EOF diff -r 000000000000 -r cc367abb080e doc/user_manual.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/user_manual.txt Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,146 @@ +Manuel utilisateur +================== + +:Author: Sylvain Thénault +:Organization: Logilab +:Version: $Revision: 1.7 $ +:Date: $Date: 2005-03-29 14:24:04 $ +:Abstract: + Logilab documentation's tools user manual. + + +py2dbk +------ + +Description +``````````` +Transform a Python_ module into a Docbook_ document to get it nicely +formated (and usually to include it from another Docbook document). + +Synopsis +```````` +:: + + USAGE: py2dbk [OPTIONS] ... + + OPTIONS: + -h / --help + display this help message and exit + + -r / --root "rootstring" + insert "rootstring" as root + + -f / --format + set output format. Default to docbook. + Available formats are docbook, extended-docbook. + + -s / --stdout + write results to standard output + +Example +``````` +:: + + py2dbk --format extended-docbook myfile.py + +This example should produce a **myfile.xml** file containing the Python +source code from *myfile.py* formatted as a XML Docbook document. The +extended-docbook format will use special roles that should be handled +by specifics FO (PDF) or CSS (HTML) stylesheets. + + + +xml2dbk +------- + +Description +``````````` +Transform any XML file into a Docbook_ or HTML document to get it nicely +formated (and usually to include it from another Docbook document). + +Synopsis +```````` +:: + + USAGE: xml2dbk [OPTIONS] ... + + OPTIONS: + -h / --help + display this help message and exit + + -o / --output + write results in file . + -s / --stdout + write results to standard output. + -e / --encoding iso-8859-1 + specify encoding to use in outputs. + + -n / --no-head + do not insert output headers. + + -f / --format + set output format. Default to docbook. + Available formats are docbook, extended-docbook, html. + +Example +``````` +:: + + xml2dbk --format extended-docbook myfile.xml + +This example should produce a **myfile_dcbk.xml** file containing the +original XML document from *myfile.xml* formatted as a XML Docbook +document. The extended-docbook format will use special roles that +should be handled by specifics FO (PDF) or CSS (HTML) stylesheets. + + + +mkdoc +----- + +Description +``````````` +Transform ReST_ (Restructured Text) or Docbook_ files to html ou +pdf. You will need some external stylesheets not included in this +package to get the Docbook_ to HTML or PDF transformation done. + +Available format depends on the installed transformation. FIXME: write +doc about this... + +Synopsis +```````` +:: + + USAGE: mkdoc [OPTIONS] ... + + OPTIONS: + -h / --help + display this help message and exit + + -f / --format + set output format. Default to html. + Available formats are docbook, html, multi_html, pdf, pdf_ao, pdf_iup, pdf_manual, pdf_psyc, site_html. + + -n / --noverif + doesn't verify XML correctness. + -k / --keep-tmp + doesn't remove temporary directory where transforms are done. + + -p / --parameter : + sets the stylesheet parameter to . You may set this option + multiple times. Parameters are given to the xslt processor. + +Example +``````` +:: + + mkdoc --format pdf myfile.rst unautrefichier.xml + +This example should produce **myfile.pdf** and **anotherfile.pdf** +files containing each original document (one in ReST and the other in +Docbook) formatted as a PDF file. + + +.. _ReST: http://docutils.sourceforge.net/rst.html +.. _Docbook: http://www.docbook.org +.. _Python: http://www.python.org \ No newline at end of file diff -r 000000000000 -r cc367abb080e editor.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,48 @@ +""" +Main script to launch editor's IHM (depends on PyGantt) +USAGE: python editor.py path/to/taskeditor.glade + +(Note: taskeditor.glade is part of Pygantt) +""" + +__revision__ = "$Id: editor.py,v 1.4 2004-11-02 07:50:52 adim Exp $" + +import locale, gettext +import pygtk +pygtk.require("2.0") +import gtk +import gtk.glade + +def run(glade_file): + + + import sys + if '-h' in sys.argv or '--help' in sys.argv : + print __doc__ + sys.exit(0) + APP = 'task_editor' + DIR = 'ihm/i18n' + # GLADE_FILE = 'ihm/taskeditor.glade' + + from logilab.pygantt.ihm.taskeditor import TaskEditor, \ + TaskEditorController + + + gettext.bindtextdomain (APP, DIR) + gettext.textdomain (APP) + gettext.install (APP, DIR, unicode=1) + + gtk.glade.bindtextdomain (APP, DIR) + gtk.glade.textdomain (APP) + + + editor = TaskEditor(glade_file) + ctrl = TaskEditorController(editor) + editor.set_controller(ctrl) + editor.show() + + gtk.main() + +import sys +if __name__ == '__main__': + run(sys.argv[1]) diff -r 000000000000 -r cc367abb080e examples/mkdocrc --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/examples/mkdocrc Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,18 @@ +# sample configuration file for mkdoc +# +# Copyright (c) 2000-2003 LOGILAB S.A. (Paris, FRANCE). +# http://www.logilab.fr/ -- mailto:contact@logilab.fr + +[MAIN] + +# default target +target=html + +# path of the fop executable +fop=/usr/bin/fop + +# path of the xsltproc executable +xsltproc=/usr/bin/xsltproc + +# directory where logilab's stylesheets are located +xsltroot=/home/logilab/lib/xslt/ diff -r 000000000000 -r cc367abb080e mkview.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mkview.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,249 @@ +#!/usr/bin/env python2.2 +# Copyright (c) 2000-2002 LOGILAB S.A. (Paris, FRANCE). +# http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# 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., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +"""USAGE: mkview [OPTIONS] [output_file.xml] + + Will create a table in which the project's tasks are listed with all + the main informations (duration, cost, resources) + If output_file is omitted, it will be automatically generated + +OPTIONS: + --h / -help + display this help message and exit. + --verbose + Will output a lot of messages to stdout. + + --format= + set output format. Default to docbook. + Available formats are docbook, csv, html. + Defaults to docbook. + + --group-class= + Will process only tasks which match this group-class + (This option can be combined with --group-name). + --group-name= + Will process only tasks which match this group-name + (This option can be combined with --group-class). + + --dump-groups= + Creates a table with tasks in rows, classes in columns + and the list of class-groups in the table body. + --dump-vcg= + Will dump a vcg file which will contain the task dependencies. + --dump-tasks= + Will dump tasks information. If --group-class and / or --group-name + are specified, then only tasks matching these groups will be processed. + The file a_file.xml will be used for the output. + + --resources-columns=(on|off) + Add / remove resources columns in the tasks-table. + Default is 'off'. +""" + +import sys +import getopt + +__revision__ = '$Id: mkview.py,v 1.13 2004-10-31 02:18:06 nico Exp $' + + +def build_filename(base, group_name, group_class): + """Returns a filename for the tasks table + """ + + table_filename = base + if group_name : + if group_class : + table_filename = "%s_%s_%s" % (base, group_name,group_class) + else: + table_filename = "%s_%s" % (base,group_name) + else: + if group_class : + table_filename = "%s_%s" % (base,group_class) + + return table_filename + +def run(*args): + # Long options list + l_opt = ['group-class=', 'group-name=', 'format=', + 'dump-vcg=', 'dump-tasks=', + 'resources-columns=', + 'dump-groups=', 'help', 'verbose'] + try: + (optlist,args) = getopt.getopt(args, 'o:hv', l_opt) + except getopt.GetoptError, e : + print e + print __doc__ + sys.exit(1) + + group_class = None + group_name = None + format = "docbook" + vcg_filename = None + tasks_file = None + verbose = 0 + check_integrity = 0 + list_ref = 0 + group_table_name = None + resource_cols = False + output_file = None + + ## Browse command line + for opt, val in optlist: + + if opt == '--group-class': + group_class = val + elif opt == '--group-name': + group_name = val + elif opt == '--format': + format = val + if format not in ("docbook","csv","html"): + print "[mkview] ERROR : unknown format : ",format + sys.exit(1) + elif opt == '--dump-vcg': + vcg_filename = val + elif opt == '--dump-tasks': + tasks_file = val + elif opt == '--resources-columns': + if val == 'on': + resource_cols = True + else: + resource_cols = False + elif opt == '--check-integrity': + check_integrity = 1 + elif opt == '--list-references': + list_ref = 1 + elif opt == "--dump-groups": + group_table_name = val + elif opt in ('--help','-h'): + print __doc__ + sys.exit(0) + elif opt in ('--verbose','-v'): + verbose = 1 + else: + print __doc__ + sys.exit(1) + + # if len(args) == 0 or len(args) > 1: + if len(args) < 1 or len(args) > 2: + print __doc__ + sys.exit(1) + + project_file = args[0] + if len(args) == 2: + output_file = args[1].split('.')[0] + + if verbose: + print "[mkview] File to parse : ",project_file + + + from logilab.pygantt.lib.readers import ExtProjectXMLReader + from logilab.pygantt.lib import writers + parser = ExtProjectXMLReader() + # Start the parse. + if verbose: + print "[mkview] starting parse ..." + project = parser.fromFile(project_file) + + from logilab.pygantt.schedule import schedule + schedule(project, csp = 0) + # project.schedule_reset() + + if verbose: + print "[mkview] parsing done " + + + # Find appropriate writer object + dumper = None + if output_file is None: + table_file_name = build_filename("tasks_table",group_name,group_class) + else: + table_file_name = output_file + + if format == "docbook": + table_file_name += ".xml" + dumper = writers.DocbookDumper(project) + elif format == "csv": + table_file_name += ".csv" + dumper = writers.CsvDumper(project) + else: + table_file_name += ".html" + dumper = writers.HtmlDumper(project) + + + # XXX for tests ... + dumper.dump_gantt_xml("fichier_gantt.xml") + + + if tasks_file : + if verbose: + print "[mkview] generating tasks description file ..." + try: + dumper.dump(tasks_file, group_name, group_class) + # p.dumpDocbook(open(tasks_file,"w")) + if verbose: + print "[mkview] tasks description file generated" + except NotImplementedError, e: + print "[mkview] ERROR : ", e + + ## Task Table + if verbose: + print "[mkview] generating task informations table ..." + try: + dumper.dump_task_table(table_file_name, group_name, group_class, + resource_cols = resource_cols) + if verbose: + print "[mkview] task informations table generated (%s)" % \ + table_file_name + except NotImplementedError, e: + print "[mkview] ERROR : ", e + +## ## Integrity (Class / Group check) +## if check_integrity: +## if verbose: print "[mkview] Checking classes / groups integrity ..." +## project.checkGroupsIntegrity() +## if verbose: print "[mkview] Checking integrity done" + + ## VCG generation + if vcg_filename: + if verbose: + print "[mkview] generating vcg file" + dumper.dump_vcg(vcg_filename) + if verbose: + print "[mkview] vcg file generated (%s)" % vcg_filename + +## ## External Refs +## if list_ref: +## if verbose: print "[mkview] checking all external references" +## ref_dict = project.getExternalReferences() +## for ref, taskid_list in ref_dict.items(): +## print ref.encode('iso-8859-1')," : ",taskid_list + + ## group_table + if group_table_name: + if verbose: + print "[mkview] generating group_table file" + try: + dumper.dump_group_dependencies(group_table_name) + if verbose: + print "[mkview] group_table file generated (%s)" \ + % group_table_name + except NotImplementedError, e: + print "[mkview] ERROR : ", e + + + +if __name__ == '__main__': + run(*sys.argv[1:]) diff -r 000000000000 -r cc367abb080e py2db.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/py2db.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,204 @@ +#!/usr/bin/python +# -*- coding: ISO-8859-1 -*- +"""%(PROG)s: format Python source code to xml docbook using roles + +USAGE: %(PROG)s [OPTIONS] ... + +OPTIONS: + -h / --help + display this help message and exit + + -r / --root "rootstring" + insert "rootstring" as root + + -f / --format + set output format. Default to %(DEFAULT_FORMAT)s. + Available formats are %(FORMATS)s. + + -s / --stdout + write results to standard output +""" +## Original code from active state recipe +## 'Colorize Python source using the built-in tokenizer' +## posted by Jürgen Hermann and modified to obtain docbook instead of colored +## html + +## ---------------------------------------------------------------------------- +## MoinMoin - Python Source Parser + +## This code is part of MoinMoin (http://moin.sourceforge.net/) and converts +## Python source code to HTML markup, rendering comments, keywords, operators, +## numeric and string literals in different colors. + +## It shows how to use the built-in keyword, token and tokenize modules +## to scan Python source code and re-emit it with no changes to its +## original formatting (which is the hard part). + +__revision__ = '$Id: py2db.py,v 1.6 2004-10-31 02:18:06 nico Exp $' + +import sys, cStringIO +import keyword, token, tokenize +from xml.sax.saxutils import escape +from os.path import basename + + +## Python Source Parser ##################################################### + +_KEYWORD = token.NT_OFFSET + 1 +_TEXT = token.NT_OFFSET + 2 + +class Parser: + """ + Send colored python source. + """ + + def __init__(self, raw, tags, out = sys.stdout): + """ + Store the source text. + """ + self.raw = raw.expandtabs().strip() + self.out = out + self.tags = tags + + def format(self, root=''): + """ + Parse and send the colored source. + """ + # store line offsets in self.lines + self.lines = [0, 0] + pos = 0 + while 1: + pos = self.raw.find('\n', pos) + 1 + if not pos: break + self.lines.append(pos) + self.lines.append(len(self.raw)) + + # parse the source and write it + self.pos = 0 + text = cStringIO.StringIO(self.raw) + if root: + self.out.write('<%s>\n'%root) + self.out.write(' \n') + try: + tokenize.tokenize(text.readline, self) + except tokenize.TokenError, ex: + msg = ex[0] + line = ex[1][0] + print "ERROR: %s%s\n" % (msg, self.raw[self.lines[line]:]) + self.out.write('\n \n') + if root: + self.out.write('\n'%root) + + def __call__(self, toktype, toktext, (srow, scol), (erow, ecol), line): + """ + Token handler. + """ + #print "type", toktype, token.tok_name[toktype], "text", toktext, + #print "start", srow,scol, "end", erow,ecol, "
" + + ## calculate new positions + oldpos = self.pos + newpos = self.lines[srow] + scol + self.pos = newpos + len(toktext) + + ## handle newlines + if toktype in [token.NEWLINE, tokenize.NL]: + self.out.write('\n') + return + + ## send the original whitespace, if needed + if newpos > oldpos: + self.out.write(self.raw[oldpos:newpos]) + + ## skip indenting tokens + if toktype in [token.INDENT, token.DEDENT]: + self.pos = newpos + return + + ## map token type to a group + if token.LPAR <= toktype and toktype <= token.OP: + toktype = token.OP + elif toktype == token.NAME and keyword.iskeyword(toktext): + toktype = _KEYWORD + + t_tags = self.tags.get(toktype, self.tags[_TEXT]) + + ## send text + self.out.write(t_tags[0]) + self.out.write(escape(toktext)) + self.out.write(t_tags[1]) + + +## Command line ############################################################### +_TAGS = { + token.NUMBER: ('', ''), + token.OP: ('', ''), + token.STRING: ('', ''), + tokenize.COMMENT: ('', ''), + token.NAME: ('', ''), + token.ERRORTOKEN: ('', ''), # ? + _KEYWORD: ('', ''), + _TEXT: ('', '') + } +_STANDARDS_TAGS = { + token.NUMBER: ('', ''), + token.OP: ('', ''), + token.STRING: ('', ''), + tokenize.COMMENT: ('', ''), + token.NAME: ('', ''), + token.ERRORTOKEN: ('', ''), # ? + _KEYWORD: ('', ''), + _TEXT: ('', '') + } + +PROG = basename(sys.argv[0]) +FORMATS = ('docbook', 'extended-docbook') +DEFAULT_FORMAT = 'docbook' + +def run(args): + import getopt + + ## get options + (opt, args) = getopt.getopt(args, + 'hr:f:s', + ['help', 'root=', 'format=', 'stdout']) + root, ext, stdout = '', 0, 0 + for o in opt: + if o[0] == '-h' or o[0] == '--help': + print __doc__ % globals() + return + elif o[0] == '-r' or o[0] == '--root': + root = o[1] + elif o[0] == '-f' or o[0] == '--format': + val = o[1].lower() + if not val in FORMATS: + raise 'Unknown format %s' % val + if val == 'extended-docbook': + ext = 1 + elif o[0] == '-s' or o[0] == '--stdout': + stdout = 1 + + ## transforms source files + for file in args: + if file[-3:] != '.py': + sys.stderr.write('Unknown extension, ignored file %s\n' % file) + continue + source = open(file, 'r') + if not stdout: + output = '%s.xml' % file[:-3] + dest = open(output, 'w+') + else: + dest = sys.stdout + sys.stderr.write("Formatting...\n") + ## write colorized version to "python.html" + if not ext: + Parser(source.read(), _STANDARDS_TAGS, dest).format(root) + else: + Parser(source.read(), _TAGS, dest).format(root) + source.close() + dest.close() + + +if __name__ == "__main__": + run(sys.argv[1:]) + diff -r 000000000000 -r cc367abb080e rest_docbook.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rest_docbook.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,1054 @@ +#!/usr/bin/env python +# pylint: disable-msg=W0131 + +""" +:Author: Ollie Rutherfurd +:Contact: oliver@rutherfurd.net +:Revision: $Revision: 1.7 $ +:Date: $Date: 2006-02-08 15:21:17 $ +:Copyright: This module has been placed in the public domain. + +DocBook document tree Writer. + +This Writer converts a reST document tree to a subset +of DocBook. + +.. Note:: This is an unfinished work in progress. + +Document Types +============== + +This writer can create 3 types of DocBook documents: + +1. "article" *(default)* +2. "book" +3. "chapter" + +.. Note:: When creating a "book" document, all first-level + sections are output as "chapter" elements instead + of "section" as in "article" and "chapter". + +Mappings +======== + +Option List +----------- + +As there is no direct equivlent for a listing of program options +in DocBook_, as defined in reST_, a table containing the +option list contents is generated. + +Field List +---------- + +Like `Option List`_, there is not direct equivlent for +a Field List in DocBook, so this is done using a +"variablelist". + +.. NOTE:: It might be better to switch Definition List + to glossary or something similar, so Field List + and Definition List are generating the same type + of output. + +Bibliography Elements +--------------------- + +Here's how reST's bibliography elements are mapped +to DocBook elements: + ++--------------+---------------------------------------------+ +| reST Element | DocBook Element | ++==============+=============================================+ +| author | {doctype}info/author/othername | +| | or | +| | {doctype}info/authorgroup/author/othername | +| | if nested under ``authors`` | ++--------------+---------------------------------------------+ +| authors | {doctype}info/authorgroup/ | ++--------------+---------------------------------------------+ +| contact | {doctype}info/author/email | ++--------------+---------------------------------------------+ +| copyright | {doctype}info/legalnotice | ++--------------+---------------------------------------------+ +| date | {doctype}info/date | ++--------------+---------------------------------------------+ +| organization | {doctype}info/orgname | ++--------------+---------------------------------------------+ +| revision | concatenated with ``version`` into | +| | {doctype}info/edition | ++--------------+---------------------------------------------+ +| status | {doctype}info/releaseinfo | ++--------------+---------------------------------------------+ +| version | concatenated with ``revision`` into | +| | {doctype}info/edition | ++--------------+---------------------------------------------+ + +Note: ``{doctype}`` is the type of the DocBook document +being generated, one of the following: ``article``, +``book``, or ``chapter``. + +Todo +==== + +- Inline images -- need to figure out how to identify an inline image +- list item marks are not guarenteed to be what was specified (if they + are it is be coincidence, however unless one starts out of order + they should match most of the time). +- sidebar subtitle needs to go into sidebarinfo + +Should para, note, etc... not in a section at the start +of the document be stuffed into an untitled ``section``? + +""" + +__docformat__ = 'reStructuredText' + +import re +import string +from docutils import writers, nodes, languages +from types import ListType + +class Writer(writers.Writer): + + settings_spec = ( + 'DocBook-Specific Options', + None, + (('Set DocBook document type. ' + 'Choices are "article", "book", and "chapter". ' + 'Default is "article".', + ['--doctype'], + {'default': 'article', + 'metavar': '', + 'type': 'choice', + 'choices': ('article', 'book', 'chapter',) + } + ), + ) + ) + + output = None + """Final translated form of `document`.""" + + def translate(self): + visitor = DocBookTranslator(self.document) + self.document.walkabout(visitor) + self.output = visitor.astext() + + +class FragmentWriter(Writer): + + def translate(self): + visitor = DocBookTranslator(self.document) + self.document.walkabout(visitor) + self.output = u''.join(visitor.body) + +class DocBookTranslator(nodes.NodeVisitor): + + XML_DECL = '\n' + + DOCTYPE_DECL = """\n""" + + def __init__(self, document): + nodes.NodeVisitor.__init__(self, document) + self.language = languages.get_language( + document.settings.language_code) + self.doctype = document.settings.doctype + self.doc_header = [ + self.XML_DECL % (document.settings.output_encoding,), + self.DOCTYPE_DECL % (self.doctype,), + '<%s>\n' % (self.doctype,), + ] + self.doc_footer = [ + '\n' % (self.doctype,) + ] + self.body = [] + self.section = 0 + self.context = [] + self.colnames = [] + self.footnotes = {} + self.footnote_map = {} + self.docinfo = [] + + def astext(self): + return ''.join(self.doc_header + + self.docinfo + + self.body + + self.doc_footer) + + def encode(self, text): + """Encode special characters in `text` & return.""" + # @@@ A codec to do these and all other + # HTML entities would be nice. + text = text.replace("&", "&") + text = text.replace("<", "<") + text = text.replace('"', """) + text = text.replace(">", ">") + return text + + def rearrange_footnotes(self): + """ + Replaces ``foonote_reference`` placeholders with + ``footnote`` element content as DocBook and reST + handle footnotes differently. + + DocBook defines footnotes inline, whereas they + may be anywere in reST. This function replaces the + first instance of a ``footnote_reference`` with + the ``footnote`` element itself, and later + references of the same a footnote with + ``footnoteref`` elements. + """ + for (footnote_id,refs) in self.footnote_map.items(): + ref_id, context, pos = refs[0] + context[pos] = ''.join(self.footnotes[footnote_id]) + for ref_id, context, pos in refs[1:]: + context[pos] = '' \ + % (footnote_id,) + + def attval(self, text, + transtable=string.maketrans('\n\r\t\v\f', ' ')): + """Cleanse, encode, and return attribute value text.""" + return self.encode(text.translate(transtable)) + + def starttag(self, node, tagname, suffix='\n', infix='', **attributes): + """ + Construct and return a start tag given a node + (id & class attributes are extracted), tag name, + and optional attributes. + """ + atts = {} + for (name, value) in attributes.items(): + atts[name.lower()] = value + + for att in ('id',): # node attribute overrides + if node.has_key(att): + atts[att] = node[att] + + attlist = atts.items() + attlist.sort() + parts = [tagname.lower()] + for name, value in attlist: + if value is None: # boolean attribute + # According to the HTML spec, ```` is good, + # ```` is bad. + # (But the XHTML (XML) spec says the opposite. ) + parts.append(name.lower()) + elif isinstance(value, ListType): + values = [str(v) for v in value] + parts.append('%s="%s"' % (name.lower(), + self.attval(' '.join(values)))) + else: + parts.append('%s="%s"' % (name.lower(), + self.attval(str(value)))) + return '<%s%s>%s' % (' '.join(parts), infix, suffix) + + def emptytag(self, node, tagname, suffix='\n', **attributes): + """Construct and return an XML-compatible empty tag.""" + return self.starttag(node, tagname, suffix, infix=' /', **attributes) + + def visit_Text(self, node): + self.body.append(self.encode(node.astext())) + + def depart_Text(self, node): + pass + + def visit_attention(self, node): + self.body.append(self.starttag(node, 'note')) + self.body.append('\n%s\n' + % (self.language.labels[node.tagname],)) + + def depart_attention(self, node): + self.body.append('\n') + + # author is handled in ``visit_docinfo()`` + def visit_author(self, node): + raise nodes.SkipNode + + # authors is handled in ``visit_docinfo()`` + def visit_authors(self, node): + raise nodes.SkipNode + + def visit_block_quote(self, node): + self.body.append(self.starttag(node, 'blockquote')) + + def depart_block_quote(self, node): + self.body.append('\n') + + def visit_bullet_list(self, node): + self.body.append(self.starttag(node, 'itemizedlist')) + + def depart_bullet_list(self, node): + self.body.append('\n') + + def visit_caption(self, node): + # NOTE: ideally, this should probably be stuffed into + # the mediaobject as a "caption" element + self.body.append(self.starttag(node, 'para')) + + def depart_caption(self, node): + self.body.append('') + + def visit_caution(self, node): + self.body.append(self.starttag(node, 'caution')) + self.body.append('\n%s\n' + % (self.language.labels[node.tagname],)) + + def depart_caution(self, node): + self.body.append('\n') + + # reST seems to handle citations as a labled + # footnotes, whereas DocBook doesn't from what + # I can tell, so I'm not sure how to give DocBook + # citations that result in equivlent output + # as the docutils html writer. + # + # Currently, citations are handled as footnotes, + # using the citation label as the footnote label + # which seems functionally equivlent, but the + # DocBook stylesheets for generating HTML output + # don't seem to be using the label for foonotes + # so this doesn't work. + # + # So I'm at a bit of a loss as to how to + # handle citations. Any ideas or suggestions would + # be welcome. + + # TODO: citation + def visit_citation(self, node): + self.visit_footnote(node) + + def depart_citation(self, node): + self.depart_footnote(node) + + # TODO: citation_reference + def visit_citation_reference(self, node): + self.visit_footnote_reference(node) + + def depart_citation_reference(self, node): + pass + + def visit_classifier(self, node): + self.body.append(' : ') + self.body.append(self.starttag(node, 'type')) + + def depart_classifier(self, node): + self.body.append('\n') + + def visit_colspec(self, node): + self.colnames.append('col_%d' % (len(self.colnames) + 1,)) + atts = {'colname': self.colnames[-1]} + self.body.append(self.emptytag(node, 'colspec', **atts)) + + def depart_colspec(self, node): + pass + + def visit_comment(self, node, sub=re.compile('-(?=-)').sub): + """Escape double-dashes in comment text.""" + self.body.append('\n' % sub('- ', node.astext())) + raise nodes.SkipNode + + # contact is handled in ``visit_docinfo()`` + def visit_contact(self, node): + raise nodes.SkipNode + + # copyright is handled in ``visit_docinfo()`` + def visit_copyright(self, node): + raise nodes.SkipNode + + def visit_danger(self, node): + self.body.append(self.starttag(node, 'caution')) + self.body.append('\n%s\n' + % (self.language.labels[node.tagname],)) + + def depart_danger(self, node): + self.body.append('\n') + + # date is handled in ``visit_docinfo()`` + def visit_date(self, node): + raise nodes.SkipNode + + # TODO: decoration + def visit_decoration(self, node): + pass + + def depart_decoration(self, node): + pass + + def visit_definition(self, node): + # "term" is not closed in depart_term + self.body.append('\n') + self.body.append(self.starttag(node, 'listitem')) + + def depart_definition(self, node): + self.body.append('\n') + + def visit_definition_list(self, node): + self.body.append(self.starttag(node, 'variablelist')) + + def depart_definition_list(self, node): + self.body.append('\n') + + def visit_definition_list_item(self, node): + self.body.append(self.starttag(node, 'varlistentry')) + + def depart_definition_list_item(self, node): + self.body.append('\n') + + def visit_description(self, node): + self.body.append(self.starttag(node, 'entry')) + + def depart_description(self, node): + self.body.append('\n') + + def visit_docinfo(self, node): + """ + Collects all docinfo elements for the document. + + Since reST's bibliography elements don't map very + cleanly to DocBook, rather than maintain state and + check dependencies within the different visitor + fuctions all processing of bibliography elements + is dont within this function. + + .. NOTE:: Skips processing of all child nodes as + everything should be collected here. + """ + + # XXX There are a number of fields in docinfo elements + # which don't map nicely to docbook elements and + # reST allows one to insert arbitrary fields into + # the header, We need to be able to handle fields + # which either don't map or nicely or are unexpected. + # I'm thinking of just using DocBook to display these + # elements in some sort of tabular format -- but + # to collecting them is not straight-forward. + # Paragraphs, links, lists, etc... can all live within + # the values so we either need a separate visitor + # to translate these elements, or to maintain state + # in any possible child elements (not something I + # want to do). + + docinfo = ['<%sinfo>\n' % self.doctype] + + authors = [] + author = '' + contact = '' + date = '' + legalnotice = '' + orgname = '' + releaseinfo = '' + revision, version = '', '' + + for n in node: + if isinstance(n, nodes.author): + author = n.astext() + elif isinstance(n, nodes.authors): + for a in n: + authors.append(a.astext()) + elif isinstance(n, nodes.contact): + contact = n.astext() + elif isinstance(n, nodes.copyright): + legalnotice = n.astext() + elif isinstance(n, nodes.date): + date = n.astext() + elif isinstance(n, nodes.organization): + orgname = n.astext() + elif isinstance(n, nodes.revision): + revision = 'Revision ' + n.astext() + elif isinstance(n, nodes.status): + releaseinfo = n.astext() + elif isinstance(n, nodes.version): + version = 'Version ' + n.astext() + elif isinstance(n, nodes.field): + # XXX + import sys + print >> sys.stderr, "I don't do 'field' yet" + # since all child nodes are handled here raise an exception + # if node is not handled, so it doesn't silently slip through. + else: + print dir(n) + print n.astext() + raise self.unimplemented_visit(n) + + # can only add author if name is present + # since contact is associate with author, the contact + # can also only be added if an author name is given. + if author: + docinfo.append('\n') + docinfo.append('%s\n' % author) + if contact: + docinfo.append('%s\n' % contact) + docinfo.append('\n') + + if authors: + docinfo.append('\n') + for name in authors: + docinfo.append( + '%s\n' % name) + docinfo.append('\n') + + if revision or version: + edition = version + if edition and revision: + edition += ', ' + revision + elif revision: + edition = revision + docinfo.append('%s\n' % edition) + + if date: + docinfo.append('%s\n' % date) + + if orgname: + docinfo.append('%s\n' % orgname) + + if releaseinfo: + docinfo.append('%s\n' % releaseinfo) + + if legalnotice: + docinfo.append('\n') + docinfo.append('%s\n' % legalnotice) + docinfo.append('\n') + + if len(docinfo) > 1: + docinfo.append('\n' % self.doctype) + + self.docinfo = docinfo + + raise nodes.SkipChildren + + def depart_docinfo(self, node): + pass + + def visit_doctest_block(self, node): + self.body.append('\n') + self.body.append(self.starttag(node, 'programlisting')) + + def depart_doctest_block(self, node): + self.body.append('\n') + self.body.append('\n') + + def visit_document(self, node): + pass + + def depart_document(self, node): + self.rearrange_footnotes() + + def visit_emphasis(self, node): + #self.body.append(self.starttag(node, 'emphasis')) # XXX + self.body.append('') + + def depart_emphasis(self, node): + self.body.append('') + + def visit_entry(self, node): + tagname = 'entry' + atts = {} + if node.has_key('morerows'): + atts['morerows'] = node['morerows'] + if node.has_key('morecols'): + atts['namest'] = self.colnames[self.entry_level] + atts['nameend'] = self.colnames[self.entry_level \ + + node['morecols']] + self.entry_level += 1 # for tracking what namest and nameend are + self.body.append(self.starttag(node, tagname, '', **atts)) + + def depart_entry(self, node): + self.body.append('\n') + + def visit_enumerated_list(self, node): + # TODO: need to specify "mark" type used for list items + self.body.append(self.starttag(node, 'orderedlist')) + + def depart_enumerated_list(self, node): + self.body.append('\n') + + def visit_error(self, node): + self.body.append(self.starttag(node, 'caution')) + self.body.append('\n%s\n' + % (self.language.labels[node.tagname],)) + + def depart_error(self, node): + self.body.append('\n') + + # TODO: wrap with some element (filename used in DocBook example) + def visit_field(self, node): + self.body.append(self.starttag(node, 'varlistentry')) + + def depart_field(self, node): + self.body.append('\n') + + # TODO: see if this should be wrapped with some element + def visit_field_argument(self, node): + self.body.append(' ') + + def depart_field_argument(self, node): + pass + + def visit_field_body(self, node): + # NOTE: this requires that a field body always + # be present, which looks like the case + # (from docutils.dtd) + self.body.append(self.context.pop()) + self.body.append(self.starttag(node, 'listitem')) + + def depart_field_body(self, node): + self.body.append('\n') + + def visit_field_list(self, node): + self.body.append(self.starttag(node, 'variablelist')) + + def depart_field_list(self, node): + self.body.append('\n') + + def visit_field_name(self, node): + self.body.append(self.starttag(node, 'term')) + # popped by visit_field_body, so "field_argument" is + # content within "term" + self.context.append('\n') + + def depart_field_name(self, node): + pass + + def visit_figure(self, node): + self.body.append(self.starttag(node, 'informalfigure')) + self.body.append('
') + + def depart_figure(self, node): + self.body.append('
') + self.body.append('\n') + + # TODO: footer (this is where 'generated by docutils' arrives) + # if that's all that will be there, it could map to "colophon" + def visit_footer(self, node): + raise nodes.SkipChildren + + def depart_footer(self, node): + pass + + def visit_footnote(self, node): + self.footnotes[node['id']] = [] + atts = {'id': node['id']} + if isinstance(node[0], nodes.label): + # FIXME: this fails with the second auto-sequenece character + # used in the test document ``test.txt``. + atts['label'] = node[0].astext() + self.footnotes[node['id']].append( + self.starttag(node, 'footnote', **atts)) + + # replace body with this with a footnote collector list + # which will hold all the contents for this footnote. + # This needs to be kept separate so it can be used to replace + # the first ``footnote_reference`` as DocBook defines + # ``footnote`` elements inline. + self._body = self.body + self.body = self.footnotes[node['id']] + + def depart_footnote(self, node): + # finish footnote and then replace footnote collector + # with real body list. + self.footnotes[node['id']].append('\n') + self.body = self._body + self._body = None + + def visit_footnote_reference(self, node): + if node.has_key('refid'): + refid = node['refid'] + else: + refid = self.document.nameids[node['refname']] + + # going to replace this footnote reference with the actual + # footnote later on, so store the footnote id to replace + # this reference with and the list and position to replace it + # in. Both list and position are stored in case a footnote + # reference is within a footnote, in which case ``self.body`` + # won't really be ``self.body`` but a footnote collector + # list. + refs = self.footnote_map.get(refid, []) + refs.append((node['id'], self.body, len(self.body),)) + self.footnote_map[refid] = refs + + # add place holder list item which should later be + # replaced with the contents of the footnote element + # and it's child elements + self.body.append('') + + raise nodes.SkipNode + + # TODO: header + + # ??? does anything need to be done for generated? + def visit_generated(self, node): + pass + + def depart_generated(self, node): + pass + + def visit_hint(self, node): + self.body.append(self.starttag(node, 'note')) + self.body.append('\n%s\n' + % (self.language.labels[node.tagname],)) + + def depart_hint(self, node): + self.body.append('\n') + + def visit_image(self, node): + atts = node.attributes.copy() + atts['fileref'] = atts['uri'] + alt = None + del atts['uri'] + if atts.has_key('alt'): + alt = atts['alt'] + del atts['alt'] + if atts.has_key('height'): + atts['depth'] = atts['height'] + del atts['height'] + # NOTE: using win32 port of xsltproc and docbook-stylesheets-1.51.1 + # I'm getting the following error when transforming: + # Error C:\home\igor\src\gnome-xml\xpath.c:8023: Undefined + # namespace prefix xmlXPathCompiledEval: evaluation failed + # When I switched to version 1.49 of the docbook-stylesheets + # I didn't have this problem. + self.body.append('') + self.body.append('') + self.body.append(self.emptytag(node, 'imagedata', **atts)) + self.body.append('') + if alt: + self.body.append('' \ + '%s\n' % alt) + self.body.append('') + + def depart_image(self, node): + pass + + def visit_important(self, node): + self.body.append(self.starttag(node, 'important')) + + def depart_important(self, node): + self.body.append('') + + # @@@ Incomplete, pending a proper implementation on the + # Parser/Reader end. + def visit_interpreted(self, node): + self.body.append('\n') + + def depart_interpreted(self, node): + self.body.append('\n') + + def visit_label(self, node): + # getting label for "footnote" in ``visit_footnote`` + # because label is an attribute for the ``footnote`` + # element. + if isinstance(node.parent, nodes.footnote): + raise nodes.SkipNode + # TODO: handle citation label + elif isinstance(node.parent, nodes.citation): + raise nodes.SkipNode + + def depart_label(self, node): + pass + + def visit_legend(self, node): + # TODO: explain why this is empty.... + pass + + def depart_legend(self, node): + pass + + def visit_line_block(self, node): + self.body.append(self.starttag(node, 'literallayout')) + + def depart_line_block(self, node): + self.body.append('\n') + + def visit_list_item(self, node): + self.body.append(self.starttag(node, 'listitem')) + + def depart_list_item(self, node): + self.body.append('\n') + + def visit_literal(self, node): + self.body.append('') + + def depart_literal(self, node): + self.body.append('') + + def visit_literal_block(self, node): + self.body.append(self.starttag(node, 'programlisting')) + + def depart_literal_block(self, node): + self.body.append('\n\n') + + def visit_note(self, node): + self.body.append(self.starttag(node, 'note')) + self.body.append('\n%s\n' + % (self.language.labels[node.tagname],)) + + def depart_note(self, node): + self.body.append('\n') + + def visit_option(self, node): + self.body.append(self.starttag(node, 'command')) + if self.context[-1]: + self.body.append(', ') + + def depart_option(self, node): + self.context[-1] += 1 + self.body.append('') + + def visit_option_argument(self, node): + self.body.append(node.get('delimiter', ' ')) + self.body.append(self.starttag(node, 'replaceable', '')) + + def depart_option_argument(self, node): + self.body.append('') + + def visit_option_group(self, node): + self.body.append(self.starttag(node, 'entry')) + self.context.append(0) + + def depart_option_group(self, node): + self.context.pop() + self.body.append('\n') + + def visit_option_list(self, node): + self.body.append(self.starttag(node, 'informaltable', frame='all')) + self.body.append('\n') + self.body.append('\n') + self.body.append('\n') + self.body.append('\n') + self.body.append('\n') + # FIXME: shouldn't hardcode everything... + self.body.append('Option\n') + self.body.append('Description\n') + self.body.append('\n') + self.body.append('\n') + self.body.append('\n') + + def depart_option_list(self, node): + self.body.append('') + self.body.append('\n') + self.body.append('\n') + + def visit_option_list_item(self, node): + self.body.append(self.starttag(node, 'row')) + + def depart_option_list_item(self, node): + self.body.append('\n') + + def visit_option_string(self, node): + pass + + def depart_option_string(self, node): + pass + + # organization is handled in ``visit_docinfo()`` + def visit_organization(self, node): + raise nodes.SkipNode + + def visit_paragraph(self, node): + self.body.append(self.starttag(node, 'para', '')) + + def depart_paragraph(self, node): + self.body.append('\n') + + # TODO: problematic + visit_problematic = depart_problematic = lambda self, node: None + + def visit_raw(self, node): + if node.has_key('format') and node['format'] == 'docbook': + self.body.append(node.astext()) + raise nodes.SkipNode + + def visit_reference(self, node): + atts = {} + if node.has_key('refuri'): + atts['url'] = node['refuri'] + self.context.append('ulink') + elif node.has_key('refid'): + atts['linkend'] = node['refid'] + self.context.append('link') + elif node.has_key('refname'): + atts['linkend'] = self.document.nameids[node['refname']] + self.context.append('link') + self.body.append(self.starttag(node, self.context[-1], '', **atts)) + + def depart_reference(self, node): + self.body.append('' % (self.context.pop(),)) + + # revision is handled in ``visit_docinfo()`` + def visit_revision(self, node): + raise nodes.SkipNode + + def visit_row(self, node): + self.entry_level = 0 + self.body.append(self.starttag(node, 'row')) + + def depart_row(self, node): + self.body.append('\n') + + def visit_section(self, node): + if self.section == 0 and self.doctype == 'book': + self.body.append(self.starttag(node, 'chapter')) + else: + self.body.append(self.starttag(node, 'section')) + self.section += 1 + + def depart_section(self, node): + self.section -= 1 + if self.section == 0 and self.doctype == 'book': + self.body.append('\n') + else: + self.body.append('\n') + + def visit_sidebar(self, node): + self.body.append(self.starttag(node, 'sidebar')) + + def depart_sidebar(self, node): + self.body.append('\n') + + # author is handled in ``visit_docinfo()`` + def visit_status(self, node): + raise nodes.SkipNode + + def visit_strong(self, node): + # self.body.append(self.starttag(node, 'emphasis', role='strong')) # XXX + self.body.append('') + + def depart_strong(self, node): + self.body.append('') + + def visit_substitution_definition(self, node): + raise nodes.SkipNode + + def visit_substitution_reference(self, node): + self.unimplemented_visit(node) + + def visit_subtitle(self, node): + self.body.append(self.starttag(node, 'subtitle')) + + def depart_subtitle(self, node): + self.body.append('\n') + if isinstance(node.parent, nodes.sidebar): + self.body.append('\n') + + # TODO: system_message + visit_system_message = depart_system_message = lambda self, node: None + + def visit_table(self, node): + self.body.append( + self.starttag(node, 'informaltable', frame='all') + ) + + def depart_table(self, node): + self.body.append('\n') + + # TODO: target + visit_target = depart_target = lambda self,node: None + + def visit_tbody(self, node): + self.body.append(self.starttag(node, 'tbody')) + + def depart_tbody(self, node): + self.body.append('\n') + + def visit_term(self, node): + self.body.append(self.starttag(node, 'term')) + self.body.append('') + + def depart_term(self, node): + # Leave the end tag "term" to ``visit_definition()``, + # in case there's a classifier. + self.body.append('') + + def visit_tgroup(self, node): + self.colnames = [] + atts = {'cols': node['cols']} + self.body.append(self.starttag(node, 'tgroup', **atts)) + + def depart_tgroup(self, node): + self.body.append('\n') + + def visit_thead(self, node): + self.body.append(self.starttag(node, 'thead')) + + def depart_thead(self, node): + self.body.append('\n') + + def visit_tip(self, node): + self.body.append(self.starttag(node, 'tip')) + + def depart_tip(self, node): + self.body.append('\n') + + def visit_title(self, node): + # HACK: sidebar subtitle needs to go into sidebarinfo + # so it's easier to put the title in there too + if isinstance(node.parent, nodes.sidebar): + if isinstance(node.parent.children[1], nodes.subtitle): + self.body.append('') + self.body.append(self.starttag(node, 'title', '')) + + def depart_title(self, node): + self.body.append('\n') + + # XXX just a hack for now + def visit_title_reference(self, node): + #self.body.append(self.starttag(node, 'emphasis')) # XXX + self.body.append('') + + # XXX just a hack for now + def depart_title_reference(self, node): + self.body.append('') + + def visit_topic(self, node): + # TODO: map dedication to dedication + + # Table of Contents generation handled by DocBook + if node.get('class') == 'contents': + raise nodes.SkipChildren + elif node.get('class') == 'abstract': + self.body.append(self.starttag(node, 'abstract')) + self.context.append('abstract') + # generic "topic" element + # XXX I don't really know what else to do with it. + elif node.get('class','') == '': + self.body.append(self.starttag(node, 'section')) + self.context.append('section') + else: + # XXX debug code + print 'class:', node.get('class') + print node.__class__.__name__ + print node + print `node` + print dir(node) + self.unimplemented_visit(node) + + def depart_topic(self, node): + if len(self.context): + self.body.append('\n' % (self.context.pop(),)) + + # QUESTION: what to do for "transition"? + def visit_transition(self, node): + pass + + def depart_transition(self, node): + pass + + # author is handled in ``visit_docinfo()`` + def visit_version(self, node): + raise nodes.SkipNode + + def visit_warning(self, node): + self.body.append(self.starttag(node, 'warning')) + + def depart_warning(self, node): + self.body.append('\n') + + def unimplemented_visit(self, node): + raise NotImplementedError('visiting unimplemented node type: %s' + % node.__class__.__name__) + +# :collapseFolds=0:folding=sidekick:indentSize=4: +# :lineSeparator=\n:noTabs=true:tabSize=4: diff -r 000000000000 -r cc367abb080e setup.cfg --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup.cfg Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,4 @@ +[bdist_rpm] +release = 0.1 +packager = Sylvain Thénault +provides = doctools diff -r 000000000000 -r cc367abb080e setup.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/setup.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,185 @@ +#!/usr/bin/env python +# pylint: disable-msg=W0142, W0403,W0404, W0613,W0622,W0622, W0704, R0904 +# +# Copyright (c) 2003 LOGILAB S.A. (Paris, FRANCE). +# http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# 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., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" Generic Setup script, takes package info from __pkginfo__.py file """ + +__revision__ = '$Id: setup.py,v 1.7 2005-03-29 12:17:21 syt Exp $' + +from __future__ import nested_scopes +import os +import sys +import shutil +from distutils.core import setup +from distutils.command import install_lib +from os.path import isdir, exists, join, walk + +# import required features +from __pkginfo__ import modname, version, license, short_desc, long_desc, \ + web, author, author_email +# import optional features +try: + from __pkginfo__ import distname +except ImportError: + distname = modname +try: + from __pkginfo__ import scripts +except ImportError: + scripts = [] +try: + from __pkginfo__ import data_files +except ImportError: + data_files = None +try: + from __pkginfo__ import subpackage_of +except ImportError: + subpackage_of = None +try: + from __pkginfo__ import include_dirs +except ImportError: + include_dirs = [] +try: + from __pkginfo__ import ext_modules +except ImportError: + ext_modules = None + +BASE_BLACKLIST = ('CVS', 'debian', 'dist', 'build', '__buildlog') +IGNORED_EXTENSIONS = ('.pyc', '.pyo', '.elc') + + +def ensure_scripts(linux_scripts): + """ + Creates the proper script names required for each platform + (taken from 4Suite) + """ + from distutils import util + if util.get_platform()[:3] == 'win': + scripts_ = [script + '.bat' for script in linux_scripts] + else: + scripts_ = linux_scripts + return scripts_ + + +def get_packages(directory, prefix): + """return a list of subpackages for the given directory + """ + result = [] + for package in os.listdir(directory): + absfile = join(directory, package) + if isdir(absfile): + if exists(join(absfile, '__init__.py')) or \ + package in ('test', 'tests'): + if prefix: + result.append('%s.%s' % (prefix, package)) + else: + result.append(package) + result += get_packages(absfile, result[-1]) + return result + +def export(from_dir, to_dir, + blacklist=BASE_BLACKLIST, + ignore_ext=IGNORED_EXTENSIONS): + """make a mirror of from_dir in to_dir, omitting directories and files + listed in the black list + """ + def make_mirror(arg, directory, fnames): + """walk handler""" + for norecurs in blacklist: + try: + fnames.remove(norecurs) + except ValueError: + pass + for filename in fnames: + # don't include binary files + if filename[-4:] in ignore_ext: + continue + if filename[-1] == '~': + continue + src = '%s/%s' % (directory, filename) + dest = to_dir + src[len(from_dir):] + print >> sys.stderr, src, '->', dest + if os.path.isdir(src): + if not exists(dest): + os.mkdir(dest) + else: + if exists(dest): + os.remove(dest) + shutil.copy2(src, dest) + try: + os.mkdir(to_dir) + except OSError, ex: + # file exists ? + import errno + if ex.errno != errno.EEXIST: + raise + walk(from_dir, make_mirror, None) + + +EMPTY_FILE = '"""generated file, don\'t modify or your data will be lost"""\n' + +class MyInstallLib(install_lib.install_lib): + """extend install_lib command to handle package __init__.py and + include_dirs variable if necessary + """ + def run(self): + """overriden from install_lib class""" + install_lib.install_lib.run(self) + # create Products.__init__.py if needed + if subpackage_of: + product_init = join(self.install_dir, subpackage_of, '__init__.py') + if not exists(product_init): + self.announce('creating %s' % product_init) + stream = open(product_init, 'w') + stream.write(EMPTY_FILE) + stream.close() + # manually install included directories if any + if include_dirs: + if subpackage_of: + base = join(subpackage_of, modname) + else: + base = modname + for directory in include_dirs: + dest = join(self.install_dir, base, directory) + export(directory, dest) + +def install(**kwargs): + """setup entry point""" + if subpackage_of: + package = subpackage_of + '.' + modname + kwargs['package_dir'] = {package : '.'} + packages = [package] + get_packages(os.getcwd(), package) + else: + kwargs['package_dir'] = {modname : '.'} + packages = [modname] + get_packages(os.getcwd(), modname) + kwargs['packages'] = packages + return setup(name = distname, + version = version, + license =license, + description = short_desc, + long_description = long_desc, + author = author, + author_email = author_email, + url = web, + scripts = ensure_scripts(scripts), + data_files=data_files, + ext_modules=ext_modules, + cmdclass={'install_lib': MyInstallLib}, + **kwargs + ) + +if __name__ == '__main__' : + install() diff -r 000000000000 -r cc367abb080e test/runtests.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/runtests.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,5 @@ +from logilab.common.testlib import main + +if __name__ == '__main__': + import sys, os + main(os.path.dirname(sys.argv[0]) or '.') diff -r 000000000000 -r cc367abb080e test/unittest_transformer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/unittest_transformer.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,119 @@ +# Copyright (c) 2000-2003 LOGILAB S.A. (Paris, FRANCE). +# http://www.logilab.fr/ -- mailto:contact@logilab.fr + +# 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., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +""" +unit tests for the transformer module +""" +__revision__ = "$Id: unittest_transformer.py,v 1.1 2003-09-10 12:38:09 syt Exp $" + +import unittest +import sys + +from logilab.doctools.transformer import PIManager, FormattingException, \ + guess_format, InputGuessException + +class PIManagerClassTest(unittest.TestCase): + """unittest of the processing instruction manager""" + + def setUp(self): + self.manager = PIManager() + + def test_known_values(self): + preprocess, styles = self.manager.fromString(''' + + + + + + +
+Gna gna gna +
''') + self.assertEqual(preprocess, ['thefirstone', 'thesecondone']) + self.assertEqual(styles, {'pdf' : 'theotherone', 'html': 'thisone'}) + + def test_raise_1(self): + self.assertRaises(FormattingException, self.manager.fromString, + ''' + +
+Gna gna gna +
''') + + def test_raise_2(self): + self.assertRaises(FormattingException, self.manager.fromString, + ''' + +
+Gna gna gna +
''') + + def test_raise_3(self): + self.assertRaises(FormattingException, self.manager.fromString, + ''' + +
+Gna gna gna +
''') + + def test_raise_4(self): + self.assertRaises(FormattingException, self.manager.fromString, + ''' + +
+Gna gna gna +
''') + +class GuessformatFunctionTest(unittest.TestCase): + + + def test_known_values_1(self): + self.assertEqual(guess_format('machin.txt'), 'rest') + + def test_known_values_2(self): + self.assertEqual(guess_format('machin.rst'), 'rest') + + def test_known_values_3(self): + self.assertEqual(guess_format('machin.rest'), 'rest') + + def test_known_values_4(self): + self.assertEqual(guess_format('machin.xml'), 'docbook') + + def test_known_values_5(self): + self.assertEqual(guess_format('machin.dbk'), 'docbook') + + def test_known_values_6(self): + self.assertEqual(guess_format('machin.fo'), 'fo') + + def test_raise_1(self): + self.assertRaises(InputGuessException, guess_format, 'machin.unk') + +def suite(): + """return the unitest suite""" + loader = unittest.TestLoader() + testsuite = loader.loadTestsFromModule(sys.modules[__name__]) + return testsuite + +def Run(runner=None): + """run tests""" + testsuite = suite() + if runner is None: + runner = unittest.TextTestRunner() + # uncomment next line to write tests results in a file + #runner.__init__(open('tests.log','w+')) + return runner.run(testsuite) + +if __name__ == '__main__': + Run() diff -r 000000000000 -r cc367abb080e test/validation_tests.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/validation_tests.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,356 @@ +# -*- coding: ISO-8859-1 -*- +"""Validation tests for doctools + +These tests are based on the specification document (see doc/spec_mkdoc.pdf) +""" +MKDOC = '../bin/mkdoc' +DEBUG = 0 + +__revision__ = '$Id: validation_tests.py,v 1.26 2005-11-30 15:40:16 alf Exp $' + + +import unittest +import os, sys, shutil + +SAMPLEDOC = ''' + +%s +
+ +Test +Gros test +AlexandreFAYOLLE +2003Logilab + +
Présentation +Test des utilitaires mkdoc de Logilab. +
+
''' + +SAMPLELETTRE = ''' + +%s + + +Test +Gros test +AlexandreFAYOLLE +2003Logilab + +
Présentation +Test des utilitaires mkdoc de Logilab. +
+
''' + +SAMPLECONTRAT = ''' + +%s + + +Test +Gros test +AlexandreFAYOLLE +2003Logilab + +
Présentation +Test des utilitaires mkdoc de Logilab. +
+
''' + +SAMPLESITE = ''' + +%s + + +Test +Gros test + +''' + +SAMPLEREST = '''Test ReST +========= + +:Author: Sylvain Thénault +:Organization: Logilab +:Version: $Revision: 1.26 $ +:Date: $Date: 2005-11-30 15:40:16 $ +:Abstract: + Test de la conversion avec du ReST + +Test1 +----- + +Description +``````````` +Des tests et du text à convertir. Convertit des fichiers au format ReST_ (Restructured Text) ou Docbook_ dans divers formats tels que html ou pdf. + +.. _ReST: http://docutils.sourceforge.net/rst.html +.. _Docbook: http://www.docbook.org + + +Les subsititutions avec des charactères non latin-1 sont également mises en |oe| uvre. + +.. |oe| unicode:: œ + :rtrim: + +''' + +SAMPLEFO = ''' + + + + + + + + Hello world example + + Hello XSLFO! + + + ''' + +EXTENSIONS = { + 'pdf': 'pdf', + 'html': 'html', + 'docbook': 'xml', + } + +class TestMkdoc(unittest.TestCase): + """Base class. Defines some helper functions and no tests""" + + EXTENSION = 'xml' + TARGET = None + def setUp(self): + """initialize the name of the file to process and the name of the result""" + self.filename = mktemp('.' + self.EXTENSION) + self.targetname = os.path.basename(self.filename).replace(self.EXTENSION, + EXTENSIONS[self.TARGET]) + + def tearDown(self): + """remove generated files""" + os.remove(self.filename) + if os.path.exists(self.targetname): + os.remove(self.targetname) + + + def run_mkdoc(self, doc, style=None, **additional_options): + f = open(self.filename,'w') + f.write(doc) + f.close() + commandline = [MKDOC, '--target', self.TARGET, '--check', 'no'] + if not DEBUG: + commandline.append('--quiet') + if style: + commandline.append('--stylesheet') + commandline.append(style) + for key, val in additional_options.items(): + commandline.append('--%s' % key) + commandline.append(val) + + commandline.append(self.filename) + if DEBUG: + print '*'*80 + print ' '.join(commandline) + print 'target', self.targetname + sys.stdout.flush() + status = os.spawnv(os.P_WAIT,MKDOC, commandline) + return status + + def make_doc(self, target, xslt, sample=SAMPLEDOC): + """default implementation for XML documents""" + PI = ''%(target,xslt) + doc = sample % PI + return doc + + + def default_test(self,target=None,xslt=None, **additional_options): + """The average default test. + Tests that mkdoc runs fine and that a file is generated + with some contents""" + doc = self.make_doc(target, xslt) + status = self.run_mkdoc(doc, xslt, **additional_options) + self.failUnlessEqual(status,0) + self.failUnless(os.path.isfile(self.targetname)) + self.failUnless(os.path.getsize(self.targetname)>0) + +class Xml2Pdf(TestMkdoc): + """Tests the XML to PDF conversions""" + TARGET = 'pdf' + + def test_pdf_standard(self): + self.default_test('pdf','standard') + + def test_pdf_standard(self): + self.default_test('pdf','standard') + + def test_pdf_ao(self): + self.default_test('pdf','reponse-ao') + + def test_pdf_admin(self): + self.default_test('pdf','rapport-admin') + + def test_pdf_pubtech(self): + self.default_test('pdf','publi-technique') + + def test_pdf_pubcom(self): + self.default_test('pdf','publi-commerciale') + + def test_pdf_lettre(self): + doc = self.make_doc(self.TARGET, 'lettre', sample=SAMPLELETTRE) + status = self.run_mkdoc(doc) + self.failUnlessEqual(status,0) + self.failUnless(os.path.isfile(self.targetname)) + + def test_pdf_contrat(self): + doc = self.make_doc(self.TARGET, 'contrat', sample=SAMPLECONTRAT) + status = self.run_mkdoc(doc) + self.failUnlessEqual(status,0) + self.failUnless(os.path.isfile(self.targetname)) + + def test_pdf_formation(self): + self.default_test('pdf','catalogue-formation') + + +class Xml2Html(TestMkdoc): + """Tests the XML to HTML conversions""" + EXTENSION = 'dbk' + TARGET = 'html' + + def tearDown(self): + """remove generated files""" + if os.path.exists(self.filename): + os.remove(self.filename) + if os.path.exists(self.targetname): + os.remove(self.targetname) + if os.path.exists('html'): + shutil.rmtree('html') + + def multi_test(self, target=None, xslt=None, sample=SAMPLEDOC, + **additional_options): + """The average default test. + Tests that mkdoc runs fine and that a file is generated + with some contents""" + doc = self.make_doc(target, xslt, sample) + status = self.run_mkdoc(doc, xslt, **additional_options) + self.failUnlessEqual(status,0) + self.failUnless(os.path.isdir('html')) + self.failUnless(os.path.isfile('html/index.html')) + + def test_html_standard(self): + self.default_test('html','standard') + + def test_html_single(self): + self.default_test('html','single-file') + + def test_html_multi(self): + self.multi_test('html','multi-files') + + def test_html_website(self): + self.multi_test('html','web-site', sample=SAMPLESITE) + +class Rest2Html(Xml2Html): + EXTENSION = 'rst' + + def make_doc(self, target, xslt, sample=None): + return SAMPLEREST + + def test_html_website(self): + pass + #self.multi_test('html','web-site', doctype='site') + +class Rest2Pdf(Xml2Pdf): + EXTENSION = 'txt' + + def test_pdf_admin(self): + self.default_test('pdf','rapport-admin', doctype='article') + + def test_pdf_lettre(self): + self.default_test('pdf','lettre', doctype='lettre') + + def test_pdf_contrat(self): + self.default_test('pdf','contrat', doctype='contrat') + + def test_pdf_pubcom(self): + self.default_test('pdf','publi-commerciale', doctype='article') + + def make_doc(self,target,xslt): + return SAMPLEREST + + +class Rest2Docbook(TestMkdoc): + EXTENSION = 'rest' + TARGET = 'docbook' + def make_doc(self,*args): + return SAMPLEREST + + def test_rest_to_docbook(self): + self.default_test() + +class Fo2Pdf(TestMkdoc): + EXTENSION = 'fo' + TARGET = 'pdf' + def make_doc(self,*args): + return SAMPLEFO + + def test_fo_to_pdf(self): + self.default_test() + + +class Xml2PdfWithPreprocess(TestMkdoc): + EXTENSION = 'xml' + TARGET = 'pdf' + def make_doc(self,target,xslt): + """default implementation for XML documents""" + PI = ''%(target,xslt) + PI2 = '' + doc = SAMPLEDOC % (PI + PI2) + return doc + + def test_pdf_admin(self): + self.default_test('pdf','rapport-admin') + + + +def ensure_mkdoc_executable(): + import stat + mask = stat.S_IMODE(os.stat(MKDOC)[stat.ST_MODE]) + if not mask & 0111: + try: + os.chmod(MKDOC, mask|0111) + except OSError: + sys.exit('%s is not executable') + +def mktemp(extension=''): + import time, md5 + while 1: + filename = '/tmp/temp_%s%s'%(md5.new(str(time.time())).hexdigest(), + extension) + if os.path.exists(filename): + time.sleep(.1) + else: + return filename + + +ensure_mkdoc_executable() + +def suite(): + loader = unittest.TestLoader() + testsuite = loader.loadTestsFromModule(sys.modules[__name__]) + return testsuite + + +if __name__ == '__main__': + if os.environ.get('PYUNIT', 'text') == 'graphic': + try: + from unittestgui import main + except ImportError: + from unittest import main + else: + from unittest import main + main() diff -r 000000000000 -r cc367abb080e transform.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transform.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,58 @@ +#!/usr/bin/env python + +# -*- coding: ISO-8859-1 -*- + +# Copyright (c) 2000-2003 LOGILAB S.A. (Paris, FRANCE). +# http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# 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., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +"""main entry point for the transformer""" + +__revision__ = '$Id: transform.py,v 1.12 2004-10-31 02:18:06 nico Exp $' + +import sys +from logilab.doctools.transformer import Transformer, FormattingException, \ + GuessException + +def run(args): + """ + main + """ + transformer = Transformer() + transformer.load_file_configuration() + args = transformer.load_command_line_configuration(args) + if not args: + print transformer.help() + return 4 + status = 0 + for filename in args: + if len(args) > 1: + print '*' * 80 + try: + output_file = transformer.transform(filename) + except GuessException, exc: + print 'Error:', exc + status = 1 + except FormattingException, exc: + print 'Error:', exc + status = 2 + except: + import traceback + traceback.print_exc() + status = 3 + return status + +if __name__ == '__main__': + sys.exit(run(sys.argv[1:])) diff -r 000000000000 -r cc367abb080e transformer.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/transformer.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,494 @@ +# -*- coding: ISO-8859-1 -*- + +# Copyright (c) 2000-2003 LOGILAB S.A. (Paris, FRANCE). +# http://www.logilab.fr/ -- mailto:contact@logilab.fr +# +# 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., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +""" %prog [options] + + Transform ReST / DOCBOOK XML to differents output formats +""" + +__revision__ = "$Id: transformer.py,v 1.15 2006-02-27 09:03:13 nico Exp $" + +import os +import sys +from os.path import isabs, join, exists, expanduser, splitext, basename#, exists +from cStringIO import StringIO +from commands import getstatusoutput +from xml.sax import ContentHandler, make_parser, SAXNotRecognizedException +from xml.sax import InputSource, ErrorHandler +from xml.sax.handler import feature_external_pes, feature_external_ges +from logilab.common.configuration import OptionsManagerMixIn +from logilab.common.configuration import OptionsProviderMixIn + +from logilab.doctools.__pkginfo__ import version + +#import tempfile +#tempfile.tempdir='.' + +REST_EXTENSIONS = ('.txt', '.rst', '.rest') +DOCBOOK_EXTENSIONS = ('.xml', '.dbk') +FO_EXTENSIONS = ('.fo',) + +if os.environ.has_key('MKDOCRC') and exists(os.environ['MKDOCRC']): + MKDOCRC = os.environ['MKDOCRC'] +else: + USER_HOME = expanduser('~') + if USER_HOME == '~': + MKDOCRC = ".mkdocrc" + else: + MKDOCRC = join(USER_HOME, '.mkdocrc') + if not exists(MKDOCRC): + if exists('/etc/mkdocrc'): + MKDOCRC = '/etc/mkdocrc' + else: + MKDOCRC = None + +ENV_HELP = """ +The following environment variables are used : + * MKDOCRC + path to the configuration file. If not found, it will use the first +existant file in ~/.mkdocrc, /etc/mkdocrc. +""" +if MKDOCRC: + ENV_HELP += 'The current configuration file in use is %s.'% MKDOCRC +else: + ENV_HELP += 'No configuration file has been found for this run.' + +# exceptions ################################################################## + +class FormattingException(Exception): + """raised when a transformation failed""" + +class GuessException(Exception): + """raised when we are not able to guess something""" + +class InputGuessException(GuessException): + """raised when we are not able to guess the input file format""" + +class OutputGuessException(GuessException): + """raised when we are not able to guess the input file format""" + +# utilities ################################################################### + +class PIManager(ContentHandler): + """try to get preprocess and style xslt from processing instruction""" + def __init__(self, quiet=1): + self.quiet = quiet + + def processingInstruction(self, target, data): + """Receive notification of a processing instruction.""" + if target == 'logidoc-style': + target, xslt = None, None + for attr in data.split(' '): + name, value = attr.split('=') + if name == 'target': + target = value[1:-1] + elif name == 'xslt': + xslt = value[1:-1] + else: + msg = 'Bad logidoc-style attribute %s' + raise FormattingException(msg % name) + if not target: + msg = 'Bad logidoc-style, missing target' + raise FormattingException(msg) + if not xslt: + msg = 'Bad logidoc-style, missing xslt' + raise FormattingException(msg) + if not self.xslts.has_key(target): + self.xslts[target] = xslt + else: + print 'Warning: ignoring %s stylesheet for %s' % (xslt, target) + elif target == 'logidoc-preprocess': + name, value = data.split('=') + if name != 'xslt': + msg = 'Bad logidoc-preprocess attribute %s' + raise FormattingException(msg % name) + + assert name == 'xslt' + self.preprocess.append(value[1:-1]) + + def reset(self): + self.preprocess = [] + self.xslts = {} + + def fromFile(self, filename): + inputsource = InputSource('file://'+os.path.abspath(filename)) + return self.fromInputSource(inputsource) + + def fromString(self, string): + inputsource = InputSource() + inputsource.setByteStream(StringIO(string)) + inputsource.setSystemId('file://'+os.path.abspath("hardcoded_string")) + return self.fromInputSource(inputsource) + + + def fromInputSource(self, inputsource): + self.reset() + parser = make_parser() + parser.setContentHandler(self) + parser.setErrorHandler(ErrorHandler()) + # do not include any external entities +## try: +## parser.setFeature(feature_external_ges, 0) +## except SAXNotRecognizedException: +## pass +## try: +## parser.setFeature(feature_external_pes, 0) +## except SAXNotRecognizedException: +## pass + parser.parse(inputsource) + return self.preprocess, self.xslts + + +def exec_cmd(cmd): + """executed a command, check status and return output""" + status, output = getstatusoutput(cmd) + if status != 0: + raise FormattingException('"%s" returned status %s\n%s' % ( + cmd, status, output)) + return output + +def guess_format(filename): + """guess file format according to its extension""" + ext = splitext(filename)[1] + if ext in REST_EXTENSIONS: + return 'rest' + if ext in DOCBOOK_EXTENSIONS: + return 'docbook' + if ext in FO_EXTENSIONS: + return 'fo' + raise InputGuessException("Unable to guess file format from %s" % filename) + + +def xmlproc_output(output, checked): + """parse xmlproc output and check for errors""" + for line in output.strip().split('\n'): + if line[0:2] == 'E:' or line[0:2] == 'W:' : + print line + j = line.find(" error(s)") + assert j != -1 + i = line.rfind(" ", 0, j) + err = line[i+1:j] + if err != "0" : + raise FormattingException('Not a %s xml file' % checked) + + +# the transformer ############################################################# + +# FIXME: on a besoin de rajouter des étapes de transformation pour intégrer +# pybill et trf-session. faudrait remanier ce code pour faire apparaître un +# objet Chainon qui sera une transformation élémentaire et ensuite on +# pourra chaîner les chaînons avec un joli générateur/producteur paresseux + +class Transformer(OptionsManagerMixIn, OptionsProviderMixIn): + name = 'MAIN' + options = ( + # main options + ('target', + {'type': 'choice', + 'choices': ('docbook', 'html', 'fo', 'pdf'), + 'default' : 'pdf', + 'metavar' : "", + 'help': "output format. Available format are docbook (if input is a \ +ReST file), html and pdf." + }), + ('source', + {'type': 'choice', + 'choices': ('rest', 'docbook', 'fo'), + 'metavar' : "", + 'help': "source format. Available format are rest, docbook, fo. If \ +not specified, source format will be guessed from the file's extension." + }), + ('check', + {'type' : 'yn', + 'metavar' : '', + 'default' : 1, + 'help': "tell if we should check that the docbook input file is \ +well formed xml." + }), + ('validate', + {'type' : 'yn', + 'metavar' : '', + 'default' : 0, + 'help': "tell if we should validate the docbook input file." + }), + ('preprocess', + {'type': 'string', + 'action': 'append', + 'default': (), + 'metavar' : '', + 'help': "add a pre-processing style sheet. You can set this option \ +multiple times. If not specified, preprocessing." + }), + ('stylesheet', + {'type': 'string', + 'metavar' : '', + 'help': "set the main style sheet." + }), + ('ignore-pi', + {'action': 'store_true', + 'dest': 'ignore_pi', + 'help': "Do not try to guess main/pre-process stylesheets from \ +processing instruction." + }), + ('keep', + {'action': 'store_true', + 'help': "Keep temporary files." + }), + ('quiet', + {'action': 'store_true', + 'help': "Do not display information about what we're doing..." + }), + + # FOP related options + ('fop', + {'type': 'string', + 'default' : 'fop', + 'metavar' : "", + 'help': "path of the fop executable." + }), + ('fop-options', + {'type': 'string', + 'dest' : 'fop_opts', + 'default' : '', + 'metavar' : "", + 'help': "options given to the fop executable." + }), + + # xsltproc related options + ('xsltproc', + {'type': 'string', + 'default' : 'xsltproc', + 'metavar' : "", + 'help': "path of the xsltproc executable." + }), + ('xsltproc-options', + {'type': 'string', + 'dest' : 'xsltproc_opts', + 'default' : '--xinclude --catalogs', + 'metavar' : "", + 'help': "options given to the xsltproc executable." + }), + ('param', + {'type': 'named', + 'action' : 'append', + 'default' : (), + 'dest': 'parameters', + 'metavar' : "=", + 'help': "sets the stylesheet parameter to . You may \ +set this option multiple times. Parameters are given to the xslt processor." + }), + # ReST related options + ('doctype', + {'type': 'string', + 'default' : 'book', + 'metavar' : "", + 'help': "doctype to use when converting ReST to DOCBOOK." + }), + + ## FIXME Path to xslt directory has not to be specified. + ## TODO : Remove all references to xslt root and use id in catalog + # xslts location + ('xsltroot', + {'type': 'string', + 'metavar' : "", + 'default' : '/usr/share/sgml/logilab-xml/stylesheet/', + 'help': "directory where logilab's stylesheets are located." + }), + ) + + def __init__(self): + OptionsManagerMixIn.__init__(self, usage=__doc__, version=version, + config_file=MKDOCRC, quiet=1) + OptionsProviderMixIn.__init__(self) + self.register_options_provider(self) + self.add_help_section('Environment variables', ENV_HELP) + self.pimanager = PIManager() + + def xslt_transform(self, input_file, output_file, xslt_file): + """xsltproc based transformation + """ + if not self.config.quiet: + print '-' * 80 + print "Transforms %s to %s using %s" % (input_file, output_file, + xslt_file) + cmd = [self.config.xsltproc, self.config.xsltproc_opts, + "--output ", output_file] + params = [] + for name, value in self.config.parameters : + cmd.append('--param') + cmd.append(name) + cmd.append("\"'" + value + "'\"") + cmd.append(xslt_file) + cmd.append(input_file) + # executes transformation command line + output = exec_cmd(' '.join(cmd)) + if not self.config.quiet: + print output + return output_file + + + def fop_transform(self, fo_file, output_file): + """FOP based transformation + """ + if not self.config.quiet: + print '-' * 80 + print "Transforms Formatting Objects to PDF (%s -> %s)" % ( + fo_file, output_file) + # executes transformation command line + output = exec_cmd("%s %s %s %s" %(self.config.fop, self.config.fop_opts, + fo_file, output_file)) + if not self.config.quiet: + print output + return output_file + + + def rest_transform(self, rest_file, output_file): + """transforms Restructured Text to DOCBOOK XML + """ + if not self.config.quiet: + print '-' * 80 + print "Transforms Restructured Text to DOCBOOK XML (%s -> %s)" % ( + rest_file, output_file) + from docutils import core, io + from logilab.doctools.rest_docbook import Writer + writer = Writer() + pub = core.Publisher(writer=writer) + pub.set_reader(reader_name='standalone', + parser_name='restructuredtext', parser=None) + pub.source = io.FileInput(source_path=rest_file, encoding='ISO-8859-1') + pub.destination = io.FileOutput(destination_path=output_file, + encoding='UTF-8') + # FIXME : find the way to specify docutils no parsing args + # hint: use core.publish_programmatically ? + sys.argv = [sys.argv[0]] + try: + pub.publish(settings_overrides={'output_encoding': 'UTF-8', + 'report_level': 2, + 'doctype' : self.config.doctype, + }) + except Exception, ex: + raise FormattingException(str(ex)) + return output_file + + + def check_xml(self, xml_file): + """check the given xml file is well formed XML + """ + if not self.config.quiet: + print '-' * 80 + print 'Checking %s' % xml_file + output = exec_cmd("xmlproc_parse " + xml_file) + xmlproc_output(output, 'well formed') + return xml_file + + + def validate_xml(self, xml_file): + """check the given xml file is valid XML + """ + if not self.config.quiet: + print '-' * 80 + print 'Validating %s' % xml_file + output = exec_cmd("xmlproc_val " + xml_file) + xmlproc_output(output, 'valid') + return xml_file + + + def transform(self, filename): + """run transforms on filename + """ + # get transform parameters + to_remove = [] + source_format = self.config.source + dest_format = self.config.target + preprocess = self.config.preprocess + stylesheet = self.config.stylesheet + base = splitext(basename(filename))[0] + + if not source_format: + source_format = guess_format(filename) + + # check docbook xml for validity or well formness + if source_format == 'docbook': + if not self.config.ignore_pi and (not preprocess or not stylesheet): + self.pimanager.quiet = self.config.quiet + preproc, styles = self.pimanager.fromFile(filename) + preprocess = preprocess or preproc + stylesheet = stylesheet or styles.get(dest_format) + + # check we have a main stylesheet + if not stylesheet and dest_format != 'docbook' and source_format != 'fo': + raise OutputGuessException('Unable to guess the main style sheet') + + # transform ReST to docbook ? + if source_format == 'rest': + filename = self.rest_transform(filename, base + '.xml') + if dest_format != 'docbook': + to_remove.append(filename) + + # are we arrived ? + if dest_format == 'docbook': + return filename + + # preprocessing + for preprocess_xslt in preprocess: + xslt = self.absolute_stylesheet(preprocess_xslt, 'pre-process') + output = '%s.%s.xml' % (base, preprocess_xslt) + filename = self.xslt_transform(filename, output, xslt) + to_remove.append(output) + + # finalization + if dest_format == 'html': + # transform DOCBOOK to HTML + xslt = self.absolute_stylesheet(stylesheet, 'html') + filename = self.xslt_transform(filename, base + '.html', xslt) + else: + if source_format != 'fo': + # transform DOCBOOK to FO + xslt = self.absolute_stylesheet(stylesheet, 'fo') + filename = self.xslt_transform(filename, base + '.fo', xslt) + to_remove.append(filename) + # are we arrived ? + if dest_format == 'fo': + return filename + # transform FO to PDF + filename = self.fop_transform(filename, base + '.pdf') + + + self.clean(to_remove) + return filename + + + def absolute_stylesheet(self, stylesheet, type): + """return the absolute path of the given stylesheet""" + if isabs(stylesheet): + return stylesheet + if stylesheet.endswith('.xsl') and stylesheet.endswith('.xslt'): + return join(self.config.xsltroot, type, stylesheet) + return join(self.config.xsltroot, type, stylesheet, 'root.xsl') + + def clean(self, files): + """remove temporary files, unless configuration tells to keep them""" + if self.config.keep: + return + if not self.config.quiet and files: + print '-' * 80 + print 'Removing temporary files' + for file in files: + os.remove(file) + + diff -r 000000000000 -r cc367abb080e xmlformat.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xmlformat.py Wed Apr 26 10:48:09 2006 +0000 @@ -0,0 +1,319 @@ +#!/usr/bin/python +'''%(PROG)s: format xml source code to xml docbook using roles + +USAGE: %(PROG)s [OPTIONS] ... + +OPTIONS: + -h / --help + display this help message and exit + + -o / --output + write results in file . + -s / --stdout + write results to standard output. + -e / --encoding iso-8859-1 + specify encoding to use in outputs. + + -n / --no-head + do not insert output headers. + + -f / --format + set output format. Default to %(DEFAULT_FORMAT)s. + Available formats are %(FORMATS)s. +''' + +__revision__ = "$Id: xmlformat.py,v 1.7 2004-10-31 02:18:06 nico Exp $" + +import sys +from os.path import basename +from xml.dom.ext import SplitQName +from xml.sax.handler import ContentHandler + +PROG = basename(sys.argv[0]) +FORMATS = ('docbook', 'extended-docbook', 'html') +DEFAULT_FORMAT = 'docbook' + +_ROOT, _STRING, _COMMENT, _NAME, _KEYWORD, _TEXT, _HEAD = 0, 1, 2, 3, 4, 5, 6 + +LOGILAB = { + _HEAD: (''' +
''', '
'), + _ROOT: ('',''), + _STRING: ('', ''), + _COMMENT:('', ''), + _NAME: ('', ''), + _KEYWORD:('', ''), + _TEXT: ('', '') + } +DOCBOOK = { + _HEAD: (''' +
''', '
'), + _ROOT: ('',''), + _STRING: ('', ''), + _COMMENT:('', ''), + _NAME: ('', ''), + _KEYWORD:('', ''), + _TEXT: ('', '') + } +HTML = { + _HEAD: (''' + + + + + +''','\n'), + _ROOT: ('
', '
'), + _STRING: ('', ''), + _COMMENT:('', ''), + _NAME: ('', ''), + _KEYWORD:('', ''), + _TEXT: ('', '') + } + +## full sax handler, print each event to output ############################### + +class XmlFormatSaxHandler(ContentHandler): + """ + Format an xmlfile to docbook or html + """ + + def __init__(self, head=1, output=sys.stdout, encoding='UTF-8'): + self._out = output + self._cod = encoding + self._head = head + self._o_d = LOGILAB + self._ind = 0 + + def set_format(self, format): + if format == 'docbook': + self._o_d = DOCBOOK + elif format == 'extended-docbook': + self._o_d = LOGILAB + if format == 'html': + self._o_d = HTML + + ## content handler ######################################################## + def startDocument(self): + if self._head: + self._out.write(self._o_d[_HEAD][0] % self._cod) + self._out.write(self._o_d[_ROOT][0]) + + def endDocument(self): + self._out.write(self._o_d[_ROOT][1]) + if self._head: + self._out.write(self._o_d[_HEAD][1]) + + def startElement(self, name, attrs): + prefix, local = SplitQName(name) + if prefix: + self._out.write('<%s%s%s:%s%s%s'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], prefix, self._o_d[_KEYWORD][1], + self._o_d[_NAME][0], local, self._o_d[_NAME][1])) + else: + self._out.write('<%s%s%s'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], local, self._o_d[_KEYWORD][1])) + for key, val in attrs.items(): + prefix, local = SplitQName(key) + if prefix: + self._out.write(' %s%s%s:%s%s%s=%s"%s"%s'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], prefix, self._o_d[_KEYWORD][1], + self._o_d[_NAME][0], local, self._o_d[_NAME][1], + self._o_d[_STRING][0], val, self._o_d[_STRING][1])) + else: + self._out.write(' %s%s%s=%s"%s"%s'.encode(self._cod) % ( + self._o_d[_NAME][0], local, self._o_d[_NAME][1], + self._o_d[_STRING][0], val, self._o_d[_STRING][1])) + self._out.write('>') + + def endElement(self, name): + prefix, local = SplitQName(name) + if prefix: + self._out.write('</%s%s%s:%s%s%s>'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], prefix, self._o_d[_KEYWORD][1], + self._o_d[_NAME][0], local, self._o_d[_NAME][1])) + else: + self._out.write('</%s%s%s>'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], local, self._o_d[_KEYWORD][1])) + + def processingInstruction(self, target, data): + self._out.write('<?%s%s%s %s%s%s>'.encode(self._cod) % ( + self._o_d[_NAME][0], target, self._o_d[_NAME][1], + self._o_d[_STRING][0], data, self._o_d[_STRING][1])) + + def characters(self, ch): + self._out.write('%s%s%s' % ( + self._o_d[_TEXT][0], ch.replace('<', '<').encode(self._cod), + self._o_d[_TEXT][1])) + + ## lexical handler ######################################################## + def comment(self, comment): + self._out.write('%s<!--%s-->%s' % ( + self._o_d[_COMMENT][0], + comment.replace('<', '<').encode(self._cod), + self._o_d[_COMMENT][1])) + + def startCDATA(self): + self.cdata = 0 + self._out.write('<%s[CDATA[%s' % ( + self._o_d[_KEYWORD][0], self._o_d[_KEYWORD][1])) + + def endCDATA(self): + self._out.write('%s]]%s>' % ( + self._o_d[_KEYWORD][0], self._o_d[_KEYWORD][1])) + + def startDTD(self, name, public_id, system_id): + self._out.write('<%s!DOCTYPE%s %s'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], self._o_d[_KEYWORD][1], name)) + if public_id: + self._out.write(' PUBLIC %s"%s"%s %s"%s"%s [\n'.encode(self._cod) % ( + self._o_d[_STRING][0], public_id, self._o_d[_STRING][1], + self._o_d[_STRING][0], system_id, self._o_d[_STRING][1])) + else: + self._out.write(' SYSTEM %s"%s"%s [\n'.encode(self._cod) % ( + self._o_d[_STRING][0], system_id, self._o_d[_STRING][1])) + + def endDTD(self): + self._out.write(']>\n') + + def startEntity(self, name): + pass + + def endEntity(self, name): + pass + + ## decl handler ########################################################### + def internalEntityDecl(self, name, value): + self._out.write('<%s!ENTITY%s %s %s>\n'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], self._o_d[_KEYWORD][1], name, value)) + + def externalEntityDecl(self, name, public_id, system_id): + self._out.write('<%s!ENTITY%s %s'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], self._o_d[_KEYWORD][1], name)) + if public_id: + self._out.write(' PUBLIC %s"%s"%s %s"%s"%s>\n'.encode(self._cod) % ( + self._o_d[_STRING][0], public_id, self._o_d[_STRING][1], + self._o_d[_STRING][0], system_id, self._o_d[_STRING][1])) + else: + self._out.write(' SYSTEM %s"%s"%s>\n'.encode(self._cod) % ( + self._o_d[_STRING][0], system_id, self._o_d[_STRING][1])) + + def elementDecl(self, elem_name, content_model): + c_m = _decode_content_model(content_model) + self._out.write('<%s!ELEMENT%s %s %s>\n'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], self._o_d[_KEYWORD][1], elem_name, + c_m)) + + def attributeDecl(self, elem_name, attr_name, type_d, value_def, value): + import types + if type(type_d) is types.ListType: + s = '' + for pos in type_d: + if not s: + s = '(%s' % pos + else: + s = '%s|%s' % (s, pos) + s = '%s)' % s + self._out.write('<%s!ATTLIST%s %s %s %s %s>\n'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], self._o_d[_KEYWORD][1], elem_name, + attr_name, s , value_def)) + else: + self._out.write('<%s!ATTLIST%s %s %s %s>\n'.encode(self._cod) % ( + self._o_d[_KEYWORD][0], self._o_d[_KEYWORD][1], elem_name, + attr_name, type)) + +C_OP, C_VAL, C_NUM = 0, 1, 2 +def _decode_content_model(content_m): + s = '' + if content_m[C_OP] == ',': + for c_m in content_m[C_VAL]: + if not s: + s = '(%s' % _decode_content_model(c_m) + else: + s = '%s, %s' % (s, _decode_content_model(c_m)) + s = '%s)%s' % (s, content_m[C_NUM] ) + elif content_m[C_OP] == '|': + for c_m in content_m[C_VAL]: + if not s: + s = '(%s' % _decode_content_model(c_m) + else: + s = '%s|%s' % (s, _decode_content_model(c_m)) + s = '%s)%s' % (s, content_m[C_NUM] ) + else: + s = '%s%s' % (s, content_m[C_OP]) + s = '%s%s' % (s, content_m[-1]) + return s + + +def run(args): + """ + main + """ + import getopt, os + from xml.sax import make_parser + from xml.sax.handler import property_lexical_handler + from xml.sax.handler import property_declaration_handler + ## get options + (options, args) = getopt.getopt(args, + 'he:o:sf:n', + ['help', 'encoding=', 'output=', 'stdout', + 'format=', 'no-head']) + encod, output, dest, head, format = 'UTF-8', None, None, 1, DEFAULT_FORMAT + for opt in options: + if opt[0] == '-h' or opt[0] == '--help': + print __doc__ % globals() + return + elif opt[0] == '-o' or opt[0] == '--output': + output = opt[1] + dest = open(output, 'w') + elif opt[0] == '-s' or opt[0] == '--stdout': + dest = sys.stdout + elif opt[0] == '-o' or opt[0] == '--format': + val = opt[1].lower() + if not val in FORMATS: + raise 'Unknown format %s' % val + format = val + elif opt[0] == '-e' or opt[0] == '--encoding': + encod = opt[1] + elif opt[0] == '-n' or opt[0] == '--no-head': + head = 0 + if len(args) == 0: + print __doc__ % globals() + return + ## transforms source files (xmlproc support property_lexical_handler while + ## pyexpat doen't) + #p = make_parser(['xml.sax.drivers2.drv_xmlproc']) + p = make_parser() + for filename in args: + source = open(filename, 'r') + ## prepare handler + if not dest: + if filename[-4:] not in ('.xml', '.dtd'): + sys.stderr.write('Unknown extension %s, ignored file %s\n' % \ + (filename[-4:], filename)) + continue + dest = open('%s_dcbk.xml' % os.path.basename(filename)[:-4], 'w+') + h = XmlFormatSaxHandler(head, dest, encod) + h.set_format(format) + p.setContentHandler(h) + try: + p.setProperty(property_lexical_handler, h) + except Exception, exc: + print exc + try: + p.setProperty(property_declaration_handler, h) + except Exception, exc: + print exc + sys.stderr.write("Formatting %s ...\n" % filename) + + ## parse and write colorized version to output file + p.parse(source) + + source.close() + if not output and not dest is sys.stdout: + dest.close() + dest = None + + +if __name__ == "__main__": + run(sys.argv[1:])