python-odf (1.3.1+dfsg-1) unstable; urgency=medium
* New upstream version, which allowed to remove all previous patches. * Set HTML_TIMESTAMP = NO (Closes: #777635). * Added patch which (Closes: #783789). * Remove doc/ in source, because of uglified JS. * Updated watch file. # imported from the archive
This commit is contained in:
commit
e06f58a6c6
|
@ -0,0 +1,2 @@
|
|||
build/
|
||||
.pyc
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,24 @@
|
|||
1.3
|
||||
A new edition of odfpy to support Python3.
|
||||
|
||||
This version has been reworked by Georges Khaznadar <georgesk@debian.org>,
|
||||
to add Python3 support.
|
||||
|
||||
1.2
|
||||
Support ODF 1.2
|
||||
|
||||
past 0.9
|
||||
Made sure userfield.py works with OpenOffice.org 3.x files.
|
||||
0.9
|
||||
Updated to ODF version 1.1
|
||||
0.8
|
||||
Added the ability to load a document.
|
||||
0.7
|
||||
Refactored command-line tool odfuserfied into odf.userfield as a
|
||||
library and adapted odfuserfied to use this library.
|
||||
|
||||
0.6.1
|
||||
TODO: collect changes from svn check-in messages
|
||||
|
||||
0.6
|
||||
Implemented subobjects.
|
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,5 @@
|
|||
include *.txt api-for-odfpy.odt
|
||||
recursive-include * *.1 *.docbook Makefile
|
||||
recursive-include tests *.txt *.py runtests *.odt *.ods *.odp
|
||||
recursive-include examples *.txt *.py
|
||||
recursive-include contrib *.txt *.py
|
|
@ -0,0 +1,93 @@
|
|||
# ODFPY
|
||||
|
||||
This is a collection of utility programs written in Python to manipulate
|
||||
OpenDocument 1.2 files.
|
||||
|
||||
How to proceed: Each application has its own directory. In there, look
|
||||
at the manual pages. The Python-based tools need the odf library. Just
|
||||
make a symbolic link like this: ln -s ../odf odf
|
||||
... or type: make
|
||||
|
||||
For your own use of the odf library, see api-for-odfpy.odt
|
||||
|
||||
## INSTALLATION
|
||||
|
||||
First you get the package.
|
||||
|
||||
$ git clone https://github.com/eea/odfpy.git
|
||||
|
||||
Then you can build and install the library for Python2 and Python3:
|
||||
|
||||
```
|
||||
$ python setup.py build
|
||||
$ python3 setup.py build
|
||||
$ su
|
||||
# python setup.py install
|
||||
# python3 setup.py install
|
||||
```
|
||||
The library is incompatible with PyXML.
|
||||
|
||||
## ISSUES
|
||||
|
||||
If you run the tests with python3, you will probably see one error.
|
||||
It is probably a flaw in the command assertRaises of Python3: the
|
||||
right exception is raised, but it is not correctly identified by
|
||||
Python3's assertRaises.
|
||||
|
||||
## REDISTRIBUTION LICENSE
|
||||
|
||||
This project, with the exception of the OpenDocument schemas, are
|
||||
Copyright (C) 2006-2014, Daniel Carrera, Alex Hudson, Søren Roug,
|
||||
Thomas Zander, Roman Fordinal, Michael Howitz and Georges Khaznadar.
|
||||
|
||||
It is distributed under both GNU General Public License v.2 or (at
|
||||
your option) any later version or APACHE License v.2.
|
||||
See GPL-LICENSE-2.txt and APACHE-LICENSE-2.0.txt.
|
||||
|
||||
The OpenDocument RelaxNG Schemas are Copyright © OASIS Open 2005. See
|
||||
the schema files for their copyright notice.
|
||||
|
||||
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.
|
||||
|
||||
## TODO / IDEAS
|
||||
|
||||
* html2odf
|
||||
Alex Hudson has been contracted to produce a command-line html2odf
|
||||
converter. It should include support for images, tables, CSS, etc.
|
||||
He will provide a C# version first, and later a C version.
|
||||
|
||||
* odf2pdf
|
||||
A valuable tool, but one that is hard to do. PDF is an immensely
|
||||
popular format, but it's tricky to make PDFs. With an odf2pdf tool
|
||||
available, many developers would use ODF purely for the purpose of
|
||||
generating a PDF later. The latest idea is to hire KOffice
|
||||
developers and get them to trim down KOffice into a converter.
|
||||
|
||||
* pdf2odf
|
||||
This conversion is less likely to produce good results, but it
|
||||
might be worth a shot. Poppler is a pdf library that can convert
|
||||
PDF into XML. Maybe we can convert that XML to ODF.
|
||||
http://webcvs.freedesktop.org/poppler/poppler/
|
||||
|
||||
* odfclean
|
||||
A command-line program that removes unused automatic styles,
|
||||
metadata and track-changes. Some companies might like to send all
|
||||
out-going files through odfclean to remove any information they
|
||||
don't want others to see.
|
||||
|
||||
* odf2xliff
|
||||
Create XLIFF extraction and merge application. XLIFF is a OASIS file
|
||||
for translations. You extract the text strings, send them to the translator
|
||||
and then import them. It allows you to work on the document in the
|
||||
meantime and only retranslate the changed parts.
|
||||
|
||||
* odfdiff
|
||||
A program that can generate a diff between two ODF files. Useful for
|
||||
SVN commit messages. This is very difficult to do. But see:
|
||||
http://www.manageability.org/blog/stuff/open-source-xml-diff-in-java/view
|
||||
http://freshmeat.net/projects/xmldiff/
|
||||
|
||||
* odfsign
|
||||
Sign and verify the signature(s) of an ODF document.
|
Binary file not shown.
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,6 @@
|
|||
|
||||
odf:
|
||||
ln -s ../../odf
|
||||
|
||||
clean:
|
||||
rm -f odf
|
|
@ -0,0 +1,213 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007-2008 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
#Python imports
|
||||
import zipfile
|
||||
from odf.odf2xhtml import ODF2XHTML
|
||||
from odf.namespaces import OFFICENS, TEXTNS, XLINKNS
|
||||
from odf.opendocument import odmimetypes
|
||||
|
||||
#Zope imports
|
||||
from OFS.Image import File, cookId
|
||||
from Globals import InitializeClass
|
||||
from Globals import DTMLFile
|
||||
from AccessControl import ClassSecurityInfo
|
||||
from AccessControl.Permissions import view_management_screens, view, change_images_and_files
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
|
||||
class ODF2XHTMLBody(ODF2XHTML):
|
||||
|
||||
def rewritelink(self, imghref):
|
||||
imghref = imghref.replace("Pictures/","index_html?pict=")
|
||||
return imghref
|
||||
|
||||
manage_addODFFileForm=DTMLFile('dtml/odffileAdd', globals())
|
||||
|
||||
def manage_addODFFile(self, id='', file='',title='', precondition='', content_type='', conversion='embedded',
|
||||
REQUEST=None):
|
||||
"""Add a new File object.
|
||||
|
||||
Creates a new File object 'id' with the contents of 'file'"""
|
||||
|
||||
id = str(id)
|
||||
title = str(title)
|
||||
conversion = str(conversion)
|
||||
content_type = str(content_type)
|
||||
precondition = str(precondition)
|
||||
|
||||
suffix = ''
|
||||
newid, title = cookId(id, title, file)
|
||||
if id == '' and newid[-4:-2]== '.o' and newid[-2] in ['d','t']:
|
||||
id = newid[:-4]
|
||||
suffix = id[-3:]
|
||||
else:
|
||||
id = newid
|
||||
self = self.this()
|
||||
|
||||
# First, we create the file without data:
|
||||
self._setObject(id, ODFFile(id, title, '', suffix, content_type, precondition, conversion))
|
||||
|
||||
# Now we "upload" the data. By doing this in two steps, we
|
||||
# can use a database trick to make the upload more efficient.
|
||||
if file:
|
||||
self._getOb(id).manage_upload(file)
|
||||
if content_type:
|
||||
self._getOb(id).content_type = content_type
|
||||
|
||||
if REQUEST is not None:
|
||||
REQUEST['RESPONSE'].redirect(self.absolute_url()+'/manage_main')
|
||||
|
||||
|
||||
class ODFFile(File):
|
||||
""" ODFFile class """
|
||||
|
||||
meta_type = "OpenDocument File"
|
||||
# icon = 'misc_/ODFFile/presentation'
|
||||
|
||||
# manage_options = (
|
||||
# (File.manage_options[5],
|
||||
# File.manage_options[3],
|
||||
# File.manage_options[6],)
|
||||
# )
|
||||
|
||||
security = ClassSecurityInfo()
|
||||
|
||||
def __init__(self, id, title, file, suffix, content_type='', precondition='', conversion='embedded'):
|
||||
""" constructor """
|
||||
self.xhtml = "<h1>Nothing uploaded</h1>"
|
||||
self.conversion = conversion
|
||||
self.suffix = suffix
|
||||
self._pictures = {}
|
||||
File.__dict__['__init__'](self, id, title, file, content_type, precondition)
|
||||
|
||||
|
||||
###########################
|
||||
# ZMI FORMS #
|
||||
###########################
|
||||
|
||||
|
||||
|
||||
security.declareProtected(view, 'index_html')
|
||||
|
||||
def index_html(self, REQUEST=None, RESPONSE=None):
|
||||
""" Show the HTML part """
|
||||
if REQUEST.has_key('pict'):
|
||||
return self.Pictures(REQUEST['pict'], REQUEST, RESPONSE)
|
||||
|
||||
rsp = []
|
||||
if self.conversion == 'embedded':
|
||||
rsp.append(self.standard_html_header(self, REQUEST, RESPONSE))
|
||||
rsp.append(self.xhtml)
|
||||
if self.conversion == 'embedded':
|
||||
rsp.append(self.standard_html_footer(self, REQUEST, RESPONSE))
|
||||
return(''.join(rsp))
|
||||
|
||||
manage_editForm = DTMLFile('dtml/odfEdit',globals())
|
||||
manage_editForm._setName('manage_editForm')
|
||||
manage=manage_main = manage_editForm
|
||||
manage_uploadForm = manage_editForm
|
||||
|
||||
def manage_edit(self, title, content_type, precondition='',
|
||||
filedata=None, conversion='none', REQUEST=None):
|
||||
"""
|
||||
Changes the title and content type attributes of the OpenDocument File.
|
||||
"""
|
||||
ODFFile.inheritedAttribute('manage_edit')(self, title, content_type, precondition, filedata)
|
||||
conversion = str(conversion)
|
||||
if self.conversion != conversion:
|
||||
self.conversion = conversion
|
||||
self.update_xhtml()
|
||||
|
||||
if REQUEST:
|
||||
message="Saved changes."
|
||||
return self.manage_main(self,REQUEST,manage_tabs_message=message)
|
||||
|
||||
security.declareProtected(change_images_and_files, 'uploadFile')
|
||||
def uploadFile(self, file):
|
||||
""" asociates a file to the ODFFile object """
|
||||
data, size = self._read_data(file)
|
||||
content_type = self._get_content_type(file, data, self.__name__, 'undefined')
|
||||
self.update_data(data, content_type, size)
|
||||
self._p_changed = 1
|
||||
|
||||
security.declareProtected(view, 'download')
|
||||
def download(self, REQUEST, RESPONSE):
|
||||
""" set for download asociated file """
|
||||
self.REQUEST.RESPONSE.setHeader('Content-Type', self.content_type)
|
||||
self.REQUEST.RESPONSE.setHeader('Content-Length', self.size)
|
||||
self.REQUEST.RESPONSE.setHeader('Content-Disposition', 'attachment;filename="' + self.id() + self.suffix + '"')
|
||||
return ODFFile.inheritedAttribute('index_html')(self, REQUEST, RESPONSE)
|
||||
|
||||
security.declareProtected(view, 'download')
|
||||
def picture_list(self, REQUEST, RESPONSE):
|
||||
""" Show list of pictures """
|
||||
return "\n".join(self._pictures.keys())
|
||||
|
||||
security.declareProtected(view, 'download')
|
||||
def Pictures(self, pict, REQUEST, RESPONSE):
|
||||
""" set for download asociated file """
|
||||
suffices = {
|
||||
'wmf':'image/x-wmf',
|
||||
'png':'image/png',
|
||||
'gif':'image/gif',
|
||||
'jpg':'image/jpeg',
|
||||
'jpeg':'image/jpeg'
|
||||
}
|
||||
|
||||
suffix = pict[pict.rfind(".")+1:]
|
||||
ct = suffices.get(suffix,'application/octet-stream')
|
||||
self.REQUEST.RESPONSE.setHeader('Content-Type', ct)
|
||||
return self._pictures[pict]
|
||||
|
||||
def _save_pictures(self, fd):
|
||||
self._pictures = {}
|
||||
z = zipfile.ZipFile(fd)
|
||||
for zinfo in z.infolist():
|
||||
if zinfo.filename[0:9] == 'Pictures/':
|
||||
pictname = zinfo.filename[9:]
|
||||
self._pictures[pictname] = z.read(zinfo.filename)
|
||||
z.close()
|
||||
|
||||
# private
|
||||
update_xhtml__roles__=()
|
||||
def update_xhtml(self):
|
||||
if self.size == 0:
|
||||
return
|
||||
if self.conversion == 'embedded':
|
||||
odhandler = ODF2XHTMLBody(embedable=True)
|
||||
else:
|
||||
odhandler = ODF2XHTMLBody(embedable=False)
|
||||
fd = StringIO(str(self.data))
|
||||
self._save_pictures(fd)
|
||||
fd.seek(0)
|
||||
self.xhtml = odhandler.odf2xhtml(fd).encode('us-ascii','xmlcharrefreplace')
|
||||
self.title = odhandler.title
|
||||
|
||||
update_data__roles__=()
|
||||
def update_data(self, data, content_type=None, size=None):
|
||||
File.__dict__['update_data'](self, data, content_type, size)
|
||||
suffix = odmimetypes.get(content_type)
|
||||
if suffix:
|
||||
self.suffix = suffix
|
||||
self.update_xhtml()
|
||||
|
||||
InitializeClass(ODFFile)
|
|
@ -0,0 +1,3 @@
|
|||
ODFFile is a Zope 2.x product that will accept an ODT file, and show it as HTML incl.
|
||||
images. It can optionally put the standard_html_header and standard_html_footer around the
|
||||
content.
|
|
@ -0,0 +1,45 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007-2008 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
|
||||
#Zope imports
|
||||
from ODFFile import ODFFile, manage_addODFFileForm, manage_addODFFile
|
||||
from AccessControl.Permissions import add_documents_images_and_files
|
||||
#from App.ImageFile import ImageFile
|
||||
|
||||
|
||||
def initialize(context):
|
||||
""" initialize the ODFFile component """
|
||||
|
||||
#register classes
|
||||
context.registerClass(
|
||||
ODFFile,
|
||||
permission=add_documents_images_and_files,
|
||||
constructors = (manage_addODFFileForm, manage_addODFFile),
|
||||
icon = 'images/openofficeorg-oasis-text.gif'
|
||||
)
|
||||
|
||||
context.registerHelp()
|
||||
context.registerHelpTitle('ODFFile')
|
||||
|
||||
#misc_ = {
|
||||
# 'text':ImageFile('images/openofficeorg-oasis-text.gif', globals()),
|
||||
# 'presentation':ImageFile('images/openofficeorg-oasis-presentation.gif', globals()),
|
||||
# 'spreadsheet':ImageFile('images/openofficeorg-oasis-spreadsheet.gif', globals())
|
||||
# }
|
|
@ -0,0 +1,149 @@
|
|||
<dtml-var manage_page_header>
|
||||
<dtml-var manage_tabs>
|
||||
|
||||
|
||||
<p class="form-help">
|
||||
You can update the data for this ODF file object using the form below.
|
||||
Select a data file from your local computer by clicking the <em>browse</em>
|
||||
button and click <em>upload</em> to update the contents of the
|
||||
file. You may also edit the file content directly if the content is a
|
||||
text type and small enough to be edited in a text area.
|
||||
</p>
|
||||
|
||||
<form action="&dtml-URL1;" method="post" enctype="multipart/form-data">
|
||||
<table cellpadding="2" cellspacing="0" width="100%" border="0">
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-optional">
|
||||
Title
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="text" name="title" size="40" value="<dtml-if
|
||||
title>&dtml-title;</dtml-if>">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-label">
|
||||
Content Type
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="text" name="content_type:required" size="40" value="<dtml-if
|
||||
content_type>&dtml-content_type;</dtml-if>">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-optional">
|
||||
Precondition
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="text" name="precondition" size="40" value="<dtml-if
|
||||
precondition>&dtml-precondition;</dtml-if>">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-label">
|
||||
Conversion
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="radio" name="conversion" id="noconv" value="none" <dtml-if "conversion == 'none'">checked="checked"</dtml-if>/> <label for="noconv">No conversion</label>
|
||||
<input type="radio" name="conversion" id="rawhtml" value="rawhtml" <dtml-if "conversion == 'rawhtml'">checked="checked"</dtml-if>/> <label for="rawhtml">Raw html</label>
|
||||
<input type="radio" name="conversion" id="embedded" value="embedded" <dtml-if "conversion == 'embedded'">checked="checked"</dtml-if>/> <label for="embedded">With site header/footer</label>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<dtml-let ct=getContentType>
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-label">
|
||||
Last Modified
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-text">
|
||||
<dtml-var bobobase_modification_time fmt="%Y-%m-%d %H:%M">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-label">
|
||||
File Size
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-text">
|
||||
<dtml-var size thousands_commas> bytes
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</dtml-let>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-element">
|
||||
<dtml-if wl_isLocked>
|
||||
<em>Locked by WebDAV</em>
|
||||
<dtml-else>
|
||||
<input class="form-element" type="submit" name="manage_edit:method"
|
||||
value="Save Changes">
|
||||
</dtml-if>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<br />
|
||||
<div class="form-label">
|
||||
File Data
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<br />
|
||||
<input type="file" name="file" size="25" />
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-element">
|
||||
<dtml-if wl_isLocked>
|
||||
<em>Locked by WebDAV</em>
|
||||
<dtml-else>
|
||||
<input class="form-element" type="submit" name="manage_upload:method"
|
||||
value="Upload">
|
||||
</dtml-if>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<br />
|
||||
<div class="form-label">
|
||||
Orig. Data
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<br />
|
||||
<a href="&dtml-absolute_url;/download">Download original</a>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<dtml-var manage_page_footer>
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
<dtml-var manage_page_header>
|
||||
|
||||
<dtml-var expr="manage_form_title(this(), _,form_title='Add ODF File',)">
|
||||
|
||||
<p class="form-help">
|
||||
Select a file to upload from your local computer by clicking the
|
||||
<em>Browse</em> button.
|
||||
</p>
|
||||
|
||||
<form action="manage_addODFFile" method="post"
|
||||
enctype="multipart/form-data">
|
||||
<table cellspacing="0" cellpadding="2" border="0">
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-label">
|
||||
Id
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="text" name="id" size="40" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-optional">
|
||||
Title
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="text" name="title" size="40" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-optional">
|
||||
Conversion
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="radio" name="conversion" id="noconv" value="none"/> <label for="noconv">No conversion</label>
|
||||
<input type="radio" name="conversion" id="rawhtml" value="rawhtml"/> <label for="rawhtml">Raw html</label>
|
||||
<input type="radio" name="conversion" id="embedded" value="embedded" checked="checked"/> <label for="embedded">With site header/footer</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-optional">
|
||||
File
|
||||
</div>
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<input type="file" name="file" size="25" value="" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="left" valign="top">
|
||||
</td>
|
||||
<td align="left" valign="top">
|
||||
<div class="form-element">
|
||||
<input class="form-element" type="submit" name="submit"
|
||||
value=" Add " />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<dtml-var manage_page_footer>
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
OpenDocument File: Use OpenDocument as web content management
|
||||
|
||||
OpenDocument File will accept an ODF file and show it as HTML incl.
|
||||
images. It can optionally put the standard_html_header and
|
||||
standard_html_footer around the content.
|
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.0 KiB |
|
@ -0,0 +1 @@
|
|||
0.1
|
|
@ -0,0 +1,14 @@
|
|||
all: odf gbtext2odt.1
|
||||
|
||||
txt: gbtext2odt.txt
|
||||
|
||||
%.1: %.docbook
|
||||
xmlto man $<
|
||||
|
||||
%.txt: %.docbook
|
||||
xmlto txt $<
|
||||
|
||||
clean:
|
||||
rm -f *.txt odf
|
||||
odf:
|
||||
ln -s ../../odf
|
|
@ -0,0 +1,76 @@
|
|||
.\" Title: gbtext2odt
|
||||
.\" Author:
|
||||
.\" Generator: DocBook XSL Stylesheets v1.72.0 <http://docbook.sf.net/>
|
||||
.\" Date: 09/01/2007
|
||||
.\" Manual:
|
||||
.\" Source:
|
||||
.\"
|
||||
.TH "GBTEXT2ODT" "1" "09/01/2007" "" ""
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.SH "NAME"
|
||||
gbtext2odt \- Create OpenDocument from Project Gutenberg text
|
||||
.SH "SYNOPSIS"
|
||||
.HP 11
|
||||
\fBgbtext2odt\fR [\-e\ \fIencoding\fR] [\-a\ \fIauthor\fR] [\-c\ \fIcreation\ date\fR] [\-l\ \fIlanguage\fR] [\-p\ \fIpublisher\fR] [\-t\ \fItitle\fR] [\-T] [\fIinputfile\fR]
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
Project Gutenberg is the first and largest single collection of free electronic books, or eBooks. The project started in 1971, and the chosen format is "Plain Vanilla ASCII," and this makes the text frustrating to read. Therefore the gbtext2odt program will convert such a text to OpenDocument and add some light markup. The idea behind the program is to test the feasibility of using OpenDocument for archival of documents.
|
||||
.PP
|
||||
"Inputfile" is assumed to be an eBook from Project Gutenberg in text form. Books work pretty well, whereas plays, such as
|
||||
\fIRomeo and Juliet\fR, will probably be messed up.
|
||||
.SH "OPTIONS"
|
||||
.PP
|
||||
\-e \fIencoding\fR
|
||||
.RS 4
|
||||
Enter the encoding of the source eBook. Common encodings are: iso\-8859\-1, cp1252 (default), ascii and utf\-8
|
||||
.RE
|
||||
.PP
|
||||
\-a \fIauthor\fR
|
||||
.RS 4
|
||||
The name of the author. Entered into the metadata.
|
||||
.RE
|
||||
.PP
|
||||
\-c \fIcreation date\fR
|
||||
.RS 4
|
||||
The date of the creation. Entered into the metadata. This can be the date of conversion, or the date the author completed his document. The format must be in ISO 8601 format. I.e. YYYY\-MM\-DD or YYYY\-MM\-DDTHH:MM:SS.
|
||||
.RE
|
||||
.PP
|
||||
\-l \fIlanguage\fR
|
||||
.RS 4
|
||||
Language of the eBook. It consists of a two or three letter language code taken from the ISO 639 standard optionally followed by a hyphen and a two\-letter country code.
|
||||
.RE
|
||||
.PP
|
||||
\-p \fIpublisher\fR
|
||||
.RS 4
|
||||
The name of the publisher. Entered into the metadata. Defaults to Gutenberg Project
|
||||
.RE
|
||||
.PP
|
||||
\-t \fItitle\fR
|
||||
.RS 4
|
||||
The title of the document. Entered into the metadata.
|
||||
.RE
|
||||
.PP
|
||||
\-T
|
||||
.RS 4
|
||||
Use the title as the output filename, rather than based on the input filename.
|
||||
.RE
|
||||
.SH "EXAMPLE"
|
||||
.PP
|
||||
Conversion of Herodotus\(cq Histories from around 430 BC. Known from the movie
|
||||
[The English Patient].
|
||||
.sp
|
||||
.RS 4
|
||||
.nf
|
||||
wget http://www.gutenberg.org/dirs/etext01/1hofh10.txt
|
||||
gbtext2odt \-e cp1252 \-t "The history of Herodotus \(em Volume 1" \-a Herodotus \-l en \-T 1hofh10.txt
|
||||
.fi
|
||||
.RE
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
http://www.gutenberg.org
|
||||
.SH "ISSUES"
|
||||
.PP
|
||||
OpenOffice doesn't handle creation dates before the year 1000.
|
|
@ -0,0 +1,159 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<refentry id="gbtext2odt">
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>gbtext2odt</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>gbtext2odt</refname>
|
||||
<refpurpose>Create OpenDocument from Project Gutenberg text</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>gbtext2odt</command>
|
||||
<arg choice="opt">-e <replaceable>encoding</replaceable></arg>
|
||||
<arg choice="opt">-a <replaceable>author</replaceable></arg>
|
||||
<arg choice="opt">-c <replaceable>creation date</replaceable></arg>
|
||||
<arg choice="opt">-l <replaceable>language</replaceable></arg>
|
||||
<arg choice="opt">-n <replaceable>etext</replaceable></arg>
|
||||
<arg choice="opt">-p <replaceable>publisher</replaceable></arg>
|
||||
<arg choice="opt">-t <replaceable>title</replaceable></arg>
|
||||
<arg choice="opt">-T</arg>
|
||||
<arg choice="opt"><replaceable>inputfile</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para>
|
||||
Project Gutenberg is the first and largest single collection of free
|
||||
electronic books, or eBooks.
|
||||
The project started in 1971, and the chosen format is
|
||||
"Plain Vanilla ASCII," and this makes the text frustrating to read.
|
||||
Therefore the gbtext2odt program will convert such a text to
|
||||
OpenDocument and add some light markup.
|
||||
The idea behind the program is to test the feasibility of using
|
||||
OpenDocument for archival of documents.
|
||||
</para>
|
||||
<para>
|
||||
"Inputfile" is assumed to be an eBook from Project
|
||||
Gutenberg in text form. Books work pretty well, whereas plays,
|
||||
such as <emphasis>Romeo and Juliet</emphasis>, will probably be
|
||||
messed up.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>Options</title>
|
||||
<variablelist>
|
||||
|
||||
<varlistentry>
|
||||
<term>-e <replaceable>encoding</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Enter the encoding of the source eBook. Common encodings are: iso-8859-1,
|
||||
cp1252 (default), ascii and utf-8
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-a <replaceable>author</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of the author. Entered into the metadata.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-c <replaceable>creation date</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The date of the creation. Entered into the metadata.
|
||||
This can be the date of conversion, or the date the author completed his document.
|
||||
The format must be in ISO 8601 format. I.e. YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-l <replaceable>language</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Language of the eBook. It consists of a two or three letter language code
|
||||
taken from the ISO 639 standard optionally
|
||||
followed by a hyphen and a two-letter country code.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-n <replaceable>etext</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Adds the Gutenberg E-text number to the metadata.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-p <replaceable>publisher</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of the publisher. Entered into the metadata.
|
||||
Defaults to Gutenberg Project
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-t <replaceable>title</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The title of the document. Entered into the metadata.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>-T</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Use the title as the output filename, rather than based on the input filename.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>Example</title>
|
||||
<para>
|
||||
Conversion of <citetitle>Herodotus’ Histories</citetitle> from around 430 BCE. Known from the movie
|
||||
<citetitle>The English Patient</citetitle>. The OpenDocument standard doesn't understand creation dates
|
||||
that are before common era, so we won't add the publication date to the meta data.
|
||||
</para>
|
||||
<screen>
|
||||
wget http://www.gutenberg.org/dirs/etext01/1hofh10.txt
|
||||
gbtext2odt -e cp1252 -t "The history of Herodotus — Volume 1" -a Herodotus -l en -T 1hofh10.txt
|
||||
</screen>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>See Also</title>
|
||||
<para>
|
||||
http://www.gutenberg.org
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1><title>Issues</title>
|
||||
<para>
|
||||
OpenOffice doesn't handle creation dates before the year 1000.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
|
@ -0,0 +1,269 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This library is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU Lesser General Public
|
||||
# License as published by the Free Software Foundation; either
|
||||
# version 2.1 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This library is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public
|
||||
# License along with this library; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from odf.opendocument import OpenDocumentText
|
||||
from odf import style, text, dc, meta
|
||||
import sys, getopt, time
|
||||
|
||||
def usage():
|
||||
sys.stderr.write("""Usage: %s [-l language] [-e encoding] [-T] [-a author]
|
||||
\t[-c creation_date] [-d description] [-n etext] [-p publisher] [-t title] inputfile\n""" % sys.argv[0])
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "a:n:c:d:e:l:p:t:T", ["author=",
|
||||
"date=", "created=", "description=", "number=", "title=",
|
||||
"language=", "publisher=", "encoding="])
|
||||
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
language = None
|
||||
description = None
|
||||
encoding = 'cp1252' # Codepage 1252 is a superset of ASCII and ISO-8859-1
|
||||
argencoding = 'utf-8'
|
||||
creator = ""
|
||||
creationdate = None
|
||||
title = ""
|
||||
ebooknum = None
|
||||
publisher = "Project Gutenberg"
|
||||
copyrights = "http://www.gutenberg.org/license"
|
||||
fn_is_title = False
|
||||
|
||||
for o, a in opts:
|
||||
if o in ("-l", "--language"):
|
||||
if len(a) > 3 and a[2] != '-' and a[3] != '-' or len(a) > 6:
|
||||
sys.stderr.write("""Language must be a two or three letter language code optionally
|
||||
\tfollowed by a hyphen and a two-letter country code""")
|
||||
sys.exit(2)
|
||||
language = a
|
||||
elif o in ("-e", "--encoding"):
|
||||
encoding = a
|
||||
elif o in ("-a", "--author"):
|
||||
creator = unicode(a, argencoding)
|
||||
elif o in ("-d", "--description"):
|
||||
description = a
|
||||
elif o in ("-c", "--date", "--created"):
|
||||
if len(a) > 10 and a[10] != "T":
|
||||
sys.stderr.write("""Date must be in ISO8601 format (YYYY-MM-DDTHH:MM:SS)\n""")
|
||||
sys.exit(2)
|
||||
if len(a) < 10 or (len(a) == 10 and a[4] != "-" and a[7] != "-"):
|
||||
sys.stderr.write("""Date must be in ISO8601 format (YYYY-MM-DD)\n""")
|
||||
sys.exit(2)
|
||||
creationdate = a
|
||||
elif o in ("-p", "--publisher"):
|
||||
publisher = a
|
||||
elif o in ("-n", "--number"):
|
||||
ebooknum = unicode(a, argencoding)
|
||||
elif o in ("-t", "--title"):
|
||||
title = unicode(a, argencoding)
|
||||
elif o == "-T":
|
||||
fn_is_title = True
|
||||
|
||||
if len(args) != 1:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
doc=OpenDocumentText()
|
||||
textdoc = doc.text
|
||||
|
||||
if creator != "":
|
||||
doc.meta.addElement(meta.InitialCreator(text=creator))
|
||||
doc.meta.addElement(dc.Creator(text=creator))
|
||||
if creationdate is not None:
|
||||
doc.meta.addElement(meta.CreationDate(text=creationdate))
|
||||
doc.meta.addElement(dc.Date(text=creationdate))
|
||||
if description is not None:
|
||||
doc.meta.addElement(dc.Description(text=description))
|
||||
if title != "":
|
||||
doc.meta.addElement(dc.Title(text=title))
|
||||
if language is not None:
|
||||
doc.meta.addElement(dc.Language(text=language))
|
||||
if publisher is not None:
|
||||
# doc.meta.addElement(dc.Publisher(text=publisher))
|
||||
doc.meta.addElement(meta.UserDefined(name="Publisher", text=publisher))
|
||||
if copyrights is not None:
|
||||
# doc.meta.addElement(dc.Rights(text=copyrights))
|
||||
doc.meta.addElement(meta.UserDefined(name="Rights", text=copyrights))
|
||||
if ebooknum is not None:
|
||||
doc.meta.addElement(meta.UserDefined(name="EText", text=ebooknum))
|
||||
|
||||
arial = style.FontFace(name="Arial", fontfamily="Arial", fontfamilygeneric="swiss", fontpitch="variable")
|
||||
doc.fontfacedecls.addElement(arial)
|
||||
|
||||
# Paragraph styles
|
||||
standardstyle = style.Style(name="Standard", family="paragraph")
|
||||
standardstyle.addElement(style.ParagraphProperties(marginbottom="0cm", margintop="0cm" ))
|
||||
doc.styles.addElement(standardstyle)
|
||||
|
||||
h1style = style.Style(name="Heading 1", family="paragraph", defaultoutlinelevel="1")
|
||||
h1style.addElement(style.TextProperties(attributes={'fontsize':"20pt", 'fontweight':"bold"}))
|
||||
doc.styles.addElement(h1style)
|
||||
|
||||
textbodystyle = style.Style(name="Text body", family="paragraph", parentstylename=standardstyle)
|
||||
textbodystyle.addElement(style.ParagraphProperties(attributes={'marginbottom':"0.212cm", 'margintop':"0cm",
|
||||
'textalign':"justify", 'justifysingleword':"false"}))
|
||||
doc.styles.addElement(textbodystyle)
|
||||
|
||||
subtitlestyle = style.Style(name="Subtitle", family="paragraph", nextstylename=textbodystyle)
|
||||
subtitlestyle.addElement(style.ParagraphProperties(textalign="center") )
|
||||
subtitlestyle.addElement(style.TextProperties(fontsize="14pt", fontstyle="italic", fontname="Arial"))
|
||||
doc.styles.addElement(subtitlestyle)
|
||||
|
||||
titlestyle = style.Style(name="Title", family="paragraph", nextstylename=subtitlestyle)
|
||||
titlestyle.addElement(style.ParagraphProperties(textalign="center") )
|
||||
titlestyle.addElement(style.TextProperties(fontsize="18pt", fontweight="bold", fontname="Arial"))
|
||||
doc.styles.addElement(titlestyle)
|
||||
|
||||
# Text styles
|
||||
emphasisstyle = style.Style(name="Emphasis",family="text")
|
||||
emphasisstyle.addElement(style.TextProperties(fontstyle="italic"))
|
||||
doc.styles.addElement(emphasisstyle)
|
||||
|
||||
# Make the Gutenberg sections grey
|
||||
sectstyle = style.Style(name="Sect1", family="section")
|
||||
sectstyle.addElement(style.SectionProperties(backgroundcolor="#e6e6e6"))
|
||||
doc.automaticstyles.addElement(sectstyle)
|
||||
|
||||
FULLLINE=55
|
||||
|
||||
paragraph=[]
|
||||
|
||||
def addparagraph(section):
|
||||
""" Join the paragraph list and add it to the section
|
||||
"""
|
||||
global paragraph
|
||||
|
||||
p = ' '.join(paragraph)
|
||||
textsegs = p.split('_')
|
||||
para = text.P(stylename=textbodystyle)
|
||||
section.addElement(para)
|
||||
if len(textsegs) > 1 and (len(textsegs) % 2) == 1:
|
||||
# We have found some kursive text segments
|
||||
for i in range(len(textsegs)):
|
||||
if len(textsegs[i]) > 0:
|
||||
if (i % 2) == 1:
|
||||
y = text.Span(stylename=emphasisstyle, text=textsegs[i])
|
||||
para.addElement(y)
|
||||
else:
|
||||
para.addText(textsegs[i])
|
||||
else:
|
||||
para.addText(p)
|
||||
|
||||
def cleantext(s):
|
||||
if s[0] == '"' or s[-1] == '"':
|
||||
ls=list(s)
|
||||
if ls[0] == '"': ls[0] = u'“'
|
||||
if ls[-1] == '"': ls[-1] = u'”'
|
||||
s = ''.join(ls)
|
||||
s = s.replace('" ',u'” ')
|
||||
s = s.replace(' "',u' “')
|
||||
s = s.replace("'m",u"’m") # I'm
|
||||
s = s.replace("'s",u"’s") # genitive case
|
||||
s = s.replace("'t",u"’t") # don't, doesn't, haven't
|
||||
s = s.replace("'S",u"’S") # genitive case
|
||||
s = s.replace("'T",u"’T") # DON'T, etc
|
||||
s = s.replace("l'",u"l’") # French
|
||||
s = s.replace("d'",u"d’") # French
|
||||
if s.find('---') < 0: # Don't replace double dash for lines
|
||||
s = s.replace('--',u'—')
|
||||
return s
|
||||
|
||||
def pretext(section, line, linelen):
|
||||
section.addElement(text.P(stylename=standardstyle, text=line))
|
||||
|
||||
def posttext(section, line, linelen):
|
||||
section.addElement(text.P(stylename=standardstyle, text=line))
|
||||
|
||||
def mainpart(section, line, linelen):
|
||||
global paragraph
|
||||
|
||||
if linelen > 0 and len(paragraph) == 0 and \
|
||||
line.upper() == line and line.upper() != line.lower():
|
||||
# Headlines are always upper case
|
||||
style = h1style
|
||||
l = cleantext(line)
|
||||
section.addElement(text.H(outlinelevel=1, stylename=h1style, text=l))
|
||||
elif linelen >= FULLLINE:
|
||||
# In the middle of a paragraph
|
||||
paragraph.append(cleantext(line))
|
||||
elif linelen == 0:
|
||||
# End of paragraph
|
||||
if len(paragraph) > 0:
|
||||
addparagraph(section)
|
||||
paragraph=[]
|
||||
elif linelen < FULLLINE and len(paragraph) > 0:
|
||||
# Short tail of paragraph
|
||||
paragraph.append(cleantext(line))
|
||||
else:
|
||||
if line == title or line == title + " by " + creator:
|
||||
section.addElement(text.P( stylename=titlestyle, text=cleantext(line)))
|
||||
return
|
||||
if line == "by" or line == creator:
|
||||
section.addElement(text.P( stylename=subtitlestyle, text=cleantext(line)))
|
||||
return
|
||||
if len(paragraph) > 0:
|
||||
addparagraph(section)
|
||||
paragraph=[]
|
||||
section.addElement(text.P(stylename=textbodystyle, text=cleantext(line)))
|
||||
|
||||
|
||||
PRETEXT = 1
|
||||
MAINPART = 2
|
||||
POSTTEXT = 3
|
||||
textpart = PRETEXT
|
||||
|
||||
# Start in the preamble
|
||||
section = text.Section(stylename=sectstyle, name="preamble") #, display="none")
|
||||
textdoc.addElement(section)
|
||||
|
||||
filename = args[0]
|
||||
if fn_is_title and title is not None and title != "":
|
||||
outfn = title
|
||||
else:
|
||||
suffixi = filename.rfind(".")
|
||||
if suffixi > 1:
|
||||
outfn = filename[:suffixi]
|
||||
else:
|
||||
outfn = "interimname"
|
||||
|
||||
f = open(filename)
|
||||
for rawline in f:
|
||||
line = unicode(rawline.strip(), encoding)
|
||||
linelen = len(line)
|
||||
if line.find("*** END OF TH") == 0:
|
||||
textpart = POSTTEXT
|
||||
section = text.Section(stylename=sectstyle, name="license") #, display="none")
|
||||
textdoc.addElement(section)
|
||||
if textpart == PRETEXT:
|
||||
pretext(section, line, linelen)
|
||||
if line.find("*** START OF TH") == 0 or \
|
||||
line.find("*END THE SMALL PRINT!") == 0 or \
|
||||
line.find("*END*THE SMALL PRINT!") == 0:
|
||||
textpart = MAINPART
|
||||
elif textpart == MAINPART:
|
||||
section = textdoc
|
||||
mainpart(section, line, linelen)
|
||||
else:
|
||||
posttext(section, line, linelen)
|
||||
|
||||
# print d.contentxml()
|
||||
doc.save(outfn, True)
|
|
@ -0,0 +1,8 @@
|
|||
all: fellowship.content
|
||||
|
||||
fellowship.content: html2odt.py
|
||||
python html2odt.py http://opendocumentfellowship.org/ >fellowship.content
|
||||
|
||||
clean:
|
||||
rm -f *.content *.meta *.styles
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
chead = ['''<?xml version="1.0" encoding="UTF-8"?>\n''',
|
||||
'''<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.0">''',
|
||||
'''<office:scripts/>''',
|
||||
'''<office:font-face-decls>''',
|
||||
'''<style:font-face style:name="Luxi Sans1" svg:font-family="'Luxi Sans'" style:font-pitch="variable"/>''',
|
||||
'''<style:font-face style:name="Nimbus Roman No9 L" svg:font-family="'Nimbus Roman No9 L'" style:font-family-generic="roman" style:font-pitch="variable"/>''',
|
||||
'''<style:font-face style:name="Luxi Sans" svg:font-family="'Luxi Sans'" style:font-family-generic="swiss" style:font-pitch="variable"/>''',
|
||||
'''</office:font-face-decls>''',
|
||||
'''<office:automatic-styles/>''',
|
||||
'''<office:body>''',
|
||||
'''<office:text>''',
|
||||
'''<office:forms form:automatic-focus="false" form:apply-design-mode="false"/>''',
|
||||
'''<text:sequence-decls>''',
|
||||
'''<text:sequence-decl text:display-outline-level="0" text:name="Illustration"/>''',
|
||||
'''<text:sequence-decl text:display-outline-level="0" text:name="Table"/>''',
|
||||
'''<text:sequence-decl text:display-outline-level="0" text:name="Text"/>''',
|
||||
'''<text:sequence-decl text:display-outline-level="0" text:name="Drawing"/>''',
|
||||
'''</text:sequence-decls>''']
|
||||
|
||||
cmiddle = [
|
||||
'''<text:p text:style-name="Standard"/>''',]
|
||||
|
||||
cfoot = [ '''</office:text>''',
|
||||
'''</office:body>''',
|
||||
'''</office:document-content>''']
|
||||
|
||||
def content():
|
||||
return ''.join(chead + cmiddle + cfoot)
|
||||
|
|
@ -0,0 +1,495 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
#
|
||||
import string, sys, re
|
||||
import urllib2, htmlentitydefs, urlparse
|
||||
from urllib import quote_plus
|
||||
from HTMLParser import HTMLParser
|
||||
from cgi import escape,parse_header
|
||||
from types import StringType
|
||||
import emptycontent
|
||||
|
||||
def checkurl(url, http_proxy=None):
|
||||
""" grab and convert url
|
||||
"""
|
||||
url = string.strip(url)
|
||||
# if url.lower()[:5] != "http:":
|
||||
# raise IOError, "Only http is accepted"
|
||||
|
||||
if http_proxy:
|
||||
_proxies = { 'http': http_proxy }
|
||||
else:
|
||||
_proxies = {}
|
||||
proxy_support = urllib2.ProxyHandler(_proxies)
|
||||
opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
|
||||
|
||||
urllib2.install_opener(opener)
|
||||
|
||||
req = urllib2.Request(url)
|
||||
req.add_header("User-agent", "HTML2ODT: Convert HTML to OpenDocument")
|
||||
conn = urllib2.urlopen(req)
|
||||
|
||||
if not conn:
|
||||
raise IOError, "Failure in open"
|
||||
data = conn.read()
|
||||
headers = conn.info()
|
||||
conn.close()
|
||||
|
||||
encoding = 'iso8859-1' #Standard HTML
|
||||
if headers.has_key('content-type'):
|
||||
(ct, parms) = parse_header(headers['content-type'])
|
||||
if parms.has_key('charset'):
|
||||
encoding = parms['charset']
|
||||
|
||||
mhp = HTML2ODTParser(encoding, url)
|
||||
failure = ""
|
||||
mhp.feed(data)
|
||||
text = mhp.result() # Flush the buffer
|
||||
return text
|
||||
|
||||
entityref = re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]')
|
||||
charref = re.compile('&#(?:[0-9]+|[xX][0-9a-fA-F]+)[^0-9a-fA-F]')
|
||||
incomplete = re.compile('&[a-zA-Z#]')
|
||||
ampersand = re.compile('&')
|
||||
|
||||
def listget(list, key, default=None):
|
||||
for l in list:
|
||||
if l[0] == key:
|
||||
default = l[1]
|
||||
return default
|
||||
|
||||
class TagObject:
|
||||
|
||||
def __init__(self, tag, attrs, output_loc):
|
||||
self.tag = tag
|
||||
self.attrs = attrs
|
||||
self.output_loc = output_loc
|
||||
|
||||
class HTML2ODTParser(HTMLParser):
|
||||
|
||||
def __init__(self, encoding, baseurl):
|
||||
HTMLParser.__init__(self)
|
||||
self.encoding = encoding
|
||||
(scheme, host, path, params, fragment) = urlparse.urlsplit(baseurl)
|
||||
lastslash = path.rfind('/')
|
||||
if lastslash > -1:
|
||||
path = path[:lastslash]
|
||||
self.baseurl = urlparse.urlunsplit((scheme, host, path,'',''))
|
||||
self.basehost = urlparse.urlunsplit((scheme, host, '','',''))
|
||||
self.sectnum = 0
|
||||
self.tagstack = []
|
||||
self.pstack = []
|
||||
self.processelem = True
|
||||
self.processcont = True
|
||||
self.__data = []
|
||||
self.elements = {
|
||||
'a': (self.s_html_a, self.e_html_a),
|
||||
'base': ( self.output_base, None),
|
||||
'br': ( self.output_br, None),
|
||||
'caption': ( self.output_caption, None),
|
||||
'col': ( self.s_html_col, None),
|
||||
'dd': ( self.s_html_dd, None),
|
||||
'dt': ( self.s_html_dt, None),
|
||||
'div': ( self.s_html_section, self.e_html_section),
|
||||
'em': ( self.s_html_emphasis, self.e_html_emphasis),
|
||||
'h1': ( self.s_html_headline, self.e_html_headline),
|
||||
'h2': ( self.s_html_headline, self.e_html_headline),
|
||||
'h3': ( self.s_html_headline, self.e_html_headline),
|
||||
'h4': ( self.s_html_headline, self.e_html_headline),
|
||||
'h5': ( self.s_html_headline, self.e_html_headline),
|
||||
'h6': ( self.s_html_headline, self.e_html_headline),
|
||||
'head': ( self.s_ignorexml, None),
|
||||
'img': ( self.output_img, None),
|
||||
'li': ( self.s_html_li, self.e_html_li),
|
||||
'meta': ( self.meta_encoding, None),
|
||||
'ol': ( self.output_ol, self.e_html_list),
|
||||
'p': ( self.s_html_block, self.e_html_block),
|
||||
'span': ( self.s_html_span, self.e_html_span),
|
||||
'strong':( self.s_html_emphasis, self.e_html_emphasis),
|
||||
'table':( self.s_html_table, self.e_html_table),
|
||||
'td': ( self.s_html_td, self.e_html_td),
|
||||
'th': ( self.s_html_td, self.e_html_td),
|
||||
'title':( self.s_html_title, self.e_html_title),
|
||||
'tr': ( self.s_html_tr, self.e_html_tr),
|
||||
'ul': ( self.output_ul, self.e_html_list),
|
||||
'input':( self.output_input, None),
|
||||
'select':( self.output_select, None),
|
||||
'textarea':( self.output_textarea, None),
|
||||
}
|
||||
|
||||
|
||||
def result(self):
|
||||
""" Return a string
|
||||
String must be in UNICODE
|
||||
"""
|
||||
str = string.join(self.__data,'')
|
||||
self.__data = []
|
||||
return str
|
||||
|
||||
def meta_name(self, attrs):
|
||||
""" Look in meta tag for textual info"""
|
||||
foundit = 0
|
||||
# Is there a name attribute?
|
||||
for attr in attrs:
|
||||
if attr[0] == 'name' and string.lower(attr[1]) in ('description',
|
||||
'keywords','title',
|
||||
'dc.description','dc.keywords','dc.title'
|
||||
):
|
||||
foundit = 1
|
||||
if foundit == 0:
|
||||
return 0
|
||||
|
||||
# Is there a content attribute?
|
||||
content = self.find_attr(attrs,'content')
|
||||
if content:
|
||||
self.handle_data(u' ')
|
||||
self.handle_attr(content)
|
||||
self.handle_data(u' ')
|
||||
return 1
|
||||
|
||||
def meta_encoding(self, tag, attrs):
|
||||
""" Look in meta tag for page encoding (Content-Type)"""
|
||||
foundit = 0
|
||||
# Is there a content-type attribute?
|
||||
for attr in attrs:
|
||||
if attr[0] == 'http-equiv' and string.lower(attr[1]) == 'content-type':
|
||||
foundit = 1
|
||||
if foundit == 0:
|
||||
return 0
|
||||
|
||||
# Is there a content attribute?
|
||||
for attr in attrs:
|
||||
if attr[0] == 'content':
|
||||
(ct, parms) = parse_header(attr[1])
|
||||
if parms.has_key('charset'):
|
||||
self.encoding = parms['charset']
|
||||
return 1
|
||||
|
||||
def s_ignorexml(self, tag, attrs):
|
||||
self.processelem = False
|
||||
|
||||
def output_base(self, tag, attrs):
|
||||
""" Change the document base if there is a base tag """
|
||||
baseurl = listget(attrs, 'href', self.baseurl)
|
||||
(scheme, host, path, params, fragment) = urlparse.urlsplit(baseurl)
|
||||
lastslash = path.rfind('/')
|
||||
if lastslash > -1:
|
||||
path = path[:lastslash]
|
||||
self.baseurl = urlparse.urlunsplit((scheme, host, path,'',''))
|
||||
self.basehost = urlparse.urlunsplit((scheme, host, '','',''))
|
||||
|
||||
def output_br(self, tag, attrs):
|
||||
self.write_odt(u'<text:line-break/>')
|
||||
|
||||
def s_html_emphasis(self, tag, attrs):
|
||||
self.write_odt(u'<%s>' % tag)
|
||||
|
||||
def e_html_emphasis(self, tag):
|
||||
self.write_odt(u'</%s>' % tag)
|
||||
|
||||
def s_html_span(self, tag, attrs):
|
||||
self.write_odt(u'<text:span>')
|
||||
|
||||
def e_html_span(self, tag):
|
||||
self.write_odt(u'</text:span>')
|
||||
|
||||
def s_html_title(self, tag, attrs):
|
||||
# Put in meta.xml
|
||||
self.write_odt(u'<dc:title>')
|
||||
|
||||
def e_html_title(self, tag):
|
||||
# Put in meta.xml
|
||||
self.write_odt(u'</dc:title>')
|
||||
|
||||
def output_img(self, tag, attrs):
|
||||
src = listget(attrs, 'src', "Illegal IMG tag!")
|
||||
alt = listget(attrs, 'alt', src)
|
||||
# Must remember name of image and download it.
|
||||
self.write_odt(u'<draw:image xlink:href="Pictures/%s" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>' % '00000.png')
|
||||
|
||||
def s_html_a(self, tag, attrs):
|
||||
href = None
|
||||
href = listget(attrs, 'href', None)
|
||||
if href:
|
||||
if href in ("", "#"):
|
||||
href == self.baseurl
|
||||
elif href.find("://") >= 0:
|
||||
pass
|
||||
elif href[0] == '/':
|
||||
href = self.basehost + href
|
||||
self.write_odt(u' <text:a xlink:type="simple" xlink:href="%s">' % escape(href))
|
||||
else:
|
||||
self.write_odt(u' <text:a>')
|
||||
|
||||
def e_html_a(self, tag):
|
||||
self.write_odt(u'</text:a>')
|
||||
|
||||
def s_html_dd(self, tag, attrs):
|
||||
self.write_odt(u'<text:p text:style-name="List_20_Contents">')
|
||||
|
||||
def s_html_dt(self, tag, attrs):
|
||||
self.write_odt(u'<text:p text:style-name="List_20_Heading">')
|
||||
|
||||
def output_ul(self, tag, attrs):
|
||||
self.write_odt(u'<text:list text:style-name="List_20_1">')
|
||||
|
||||
def output_ol(self, tag, attrs):
|
||||
self.write_odt(u'<text:list text:style-name="Numbering_20_1">')
|
||||
|
||||
def e_html_list(self, tag):
|
||||
self.write_odt(u'</text:list>')
|
||||
|
||||
def s_html_li(self, tag, attrs):
|
||||
self.write_odt(u'<text:list-item><text:p text:style-name="P1">')
|
||||
|
||||
def e_html_li(self, tag):
|
||||
self.write_odt(u'</text:p></text:list-item>')
|
||||
|
||||
def output_select(self, tag, attrs):
|
||||
return
|
||||
self.write_odt(u'<br/>Combo box:')
|
||||
|
||||
def output_textarea(self, tag, attrs):
|
||||
return
|
||||
self.write_odt(u'<form:textarea>')
|
||||
|
||||
def output_input(self, tag, attrs):
|
||||
return
|
||||
type = listget(attrs, 'type', "text")
|
||||
value = listget(attrs, 'value', "")
|
||||
if type == "text":
|
||||
self.write_odt(u'<br/>Edit:')
|
||||
elif type == "submit":
|
||||
self.write_odt(u' %s' % value)
|
||||
elif type == "checkbox":
|
||||
#FIXME - Only works in XHTML
|
||||
checked = listget(attrs, 'checked', "not checked")
|
||||
self.write_odt(u'<br/>Checkbox:' % checked)
|
||||
elif type == "radio":
|
||||
checked = listget(attrs, 'checked', "not checked")
|
||||
self.write_odt(u'<br/>Radio button:' % checked)
|
||||
elif type == "file":
|
||||
self.write_odt(u'File upload edit %s' % value)
|
||||
self.write_odt(u'<br/>Browse button:')
|
||||
|
||||
def s_html_headline(self, tag, attrs):
|
||||
self.write_odt(u'<text:h text:style-name="Heading_20_%s" text:outline-level="%s">' % (tag[1],tag[1]))
|
||||
|
||||
def e_html_headline(self, tag):
|
||||
self.write_odt(u'</text:h>')
|
||||
|
||||
def s_html_table(self, tag, attrs):
|
||||
self.write_odt(u'<table:table>')
|
||||
|
||||
def e_html_table(self, tag):
|
||||
self.write_odt(u'</table:table>')
|
||||
|
||||
def s_html_td(self, tag, attrs):
|
||||
self.write_odt(u'<table:table-cell>')
|
||||
|
||||
def e_html_td(self, tag):
|
||||
self.write_odt(u'</table:table-cell>')
|
||||
|
||||
def s_html_tr(self, tag, attrs):
|
||||
self.write_odt(u'<table:table-row>')
|
||||
|
||||
def e_html_tr(self, tag):
|
||||
self.write_odt(u'</table:table-row>')
|
||||
|
||||
def s_html_col(self, tag, attrs):
|
||||
self.write_odt(u'<table:table-column/>')
|
||||
|
||||
def output_caption(self, tag, attrs):
|
||||
self.write_odt(u'Caption: ')
|
||||
|
||||
def s_html_section(self, tag, attrs):
|
||||
""" Outputs block tag such as <p> and <div> """
|
||||
name = self.find_attr(attrs,'id')
|
||||
if name is None:
|
||||
self.sectnum = self.sectnum + 1
|
||||
name = "Sect%d" % self.sectnum
|
||||
self.write_odt(u'<text:section text:name="%s">' % name)
|
||||
|
||||
def e_html_section(self, tag):
|
||||
""" Outputs block tag such as <p> and <div> """
|
||||
self.write_odt(u'</text:section>')
|
||||
|
||||
def s_html_block(self, tag, attrs):
|
||||
""" Outputs block tag such as <p> and <div> """
|
||||
self.write_odt(u'<text:p text:style-name="Text_20_body">')
|
||||
|
||||
def e_html_block(self, tag):
|
||||
""" Outputs block tag such as <p> and <div> """
|
||||
self.write_odt(u'</text:p>')
|
||||
#
|
||||
# HANDLE STARTTAG
|
||||
#
|
||||
def handle_starttag(self, tag, attrs):
|
||||
self.pstack.append( (self.processelem, self.processcont) )
|
||||
tagobj = TagObject(tag, attrs, self.last_data_pos())
|
||||
self.tagstack.append(tagobj)
|
||||
|
||||
method = self.elements.get(tag, (None, None))[0]
|
||||
if self.processelem and method:
|
||||
method(tag, attrs)
|
||||
#
|
||||
# HANDLE END
|
||||
#
|
||||
def handle_endtag(self, tag):
|
||||
"""
|
||||
"""
|
||||
tagobj = self.tagstack.pop()
|
||||
method = self.elements.get(tag, (None, None))[1]
|
||||
if self.processelem and method:
|
||||
method(tag)
|
||||
self.processelem, self.processcont = self.pstack.pop()
|
||||
|
||||
|
||||
#
|
||||
# Data operations
|
||||
#
|
||||
def handle_data(self, data):
|
||||
if self.processelem and self.processcont:
|
||||
self.write_odt(escape(data))
|
||||
|
||||
def write_odt(self, data):
|
||||
""" Collect the data to show on the webpage """
|
||||
if type(data) == StringType:
|
||||
data = unicode(data, self.encoding)
|
||||
self.__data.append(data)
|
||||
|
||||
def last_data_pos(self):
|
||||
return len(self.__data)
|
||||
|
||||
def find_attr(self, attrs, key):
|
||||
""" Run through the attibutes to find a specific one
|
||||
return None if not found
|
||||
"""
|
||||
for attr in attrs:
|
||||
if attr[0] == key:
|
||||
return attr[1]
|
||||
return None
|
||||
|
||||
#
|
||||
# Tagstack operations
|
||||
#
|
||||
def find_tag(self, tag):
|
||||
""" Run down the stack to find the last entry with the same tag name
|
||||
Not Tested
|
||||
"""
|
||||
for tagitem in range(len(self.tagstack), 0, -1):
|
||||
if tagitem.tag == tag:
|
||||
return tagitem
|
||||
return None
|
||||
|
||||
def handle_charref(self, name):
|
||||
""" Handle character reference for UNICODE
|
||||
"""
|
||||
if name[0] in ('x', 'X'):
|
||||
try:
|
||||
n = int(name[1:],16)
|
||||
except ValueError:
|
||||
return
|
||||
else:
|
||||
try:
|
||||
n = int(name)
|
||||
except ValueError:
|
||||
return
|
||||
if not 0 <= n <= 65535:
|
||||
return
|
||||
self.handle_data(unichr(n))
|
||||
|
||||
def handle_entityref(self, name):
|
||||
"""Handle entity references.
|
||||
"""
|
||||
table = htmlentitydefs.name2codepoint
|
||||
if name in table:
|
||||
self.handle_data(unichr(table[name]))
|
||||
else:
|
||||
return
|
||||
|
||||
def handle_attr(self, attrval):
|
||||
""" Scan attribute values for entities and resolve them
|
||||
Simply calls handle_data
|
||||
"""
|
||||
i = 0
|
||||
n = len(attrval)
|
||||
while i < n:
|
||||
match = ampersand.search(attrval, i) #
|
||||
if match:
|
||||
j = match.start()
|
||||
else:
|
||||
j = n
|
||||
if i < j: self.handle_data(attrval[i:j])
|
||||
i = j
|
||||
if i == n: break
|
||||
startswith = attrval.startswith
|
||||
if startswith('&#', i):
|
||||
match = charref.match(attrval, i)
|
||||
if match:
|
||||
name = match.group()[2:-1]
|
||||
self.handle_charref(name)
|
||||
k = match.end()
|
||||
if not startswith(';', k-1):
|
||||
k = k - 1
|
||||
i = k
|
||||
continue
|
||||
else:
|
||||
break
|
||||
elif startswith('&', i):
|
||||
match = entityref.match(attrval, i)
|
||||
if match:
|
||||
name = match.group(1)
|
||||
self.handle_entityref(name)
|
||||
k = match.end()
|
||||
if not startswith(';', k-1):
|
||||
k = k - 1
|
||||
i = k
|
||||
continue
|
||||
match = incomplete.match(attrval, i)
|
||||
if match:
|
||||
# match.group() will contain at least 2 chars
|
||||
if match.group() == attrval[i:]:
|
||||
self.error("EOF in middle of entity or char ref")
|
||||
# incomplete
|
||||
break
|
||||
elif (i + 1) < n:
|
||||
# not the end of the buffer, and can't be confused
|
||||
# with some other construct
|
||||
self.handle_data("&")
|
||||
i = i + 1
|
||||
else:
|
||||
break
|
||||
else:
|
||||
assert 0, "interesting.search() lied"
|
||||
# end while
|
||||
if i < n:
|
||||
self.handle_data(attrval[i:n])
|
||||
i = n
|
||||
|
||||
if __name__ == "__main__":
|
||||
import sys
|
||||
result = checkurl(sys.argv[1])
|
||||
sys.stdout.write('\n'.join(emptycontent.chead))
|
||||
sys.stdout.write(result.encode('utf-8'))
|
||||
sys.stdout.write('\n'.join(emptycontent.cfoot))
|
||||
sys.stdout.write('\n')
|
||||
|
||||
|
|
@ -0,0 +1,114 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from odf.style import Style, ParagraphProperties, TextProperties
|
||||
|
||||
def addStandardStyles(doc):
|
||||
style = Style(name="Standard", family="paragraph", attributes={'class':"text"})
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Text_20_body", displayname="Text body", family="paragraph", parentstylename="Standard", attributes={'class':"text"})
|
||||
p = ParagraphProperties(margintop="0cm", marginbottom="0.212cm")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="List_20_Contents", displayname="List Contents", family="paragraph", parentstylename="Standard", attributes={'class':"html"})
|
||||
p = ParagraphProperties(marginleft="1cm", marginright="0cm", textindent="0cm", autotextindent="false")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
|
||||
style = Style(name="List_20_Heading", displayname="List Heading", family="paragraph", parentstylename="Standard",
|
||||
nextstylename="List_20_Contents", attributes={'class':"html"})
|
||||
p = ParagraphProperties(marginleft="0cm", marginright="0cm", textindent="0cm", autotextindent="false")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Text_20_body_20_indent", displayname="Text body indent", family="paragraph", parentstylename="Text_20_body", attributes={'class':"text"})
|
||||
p = ParagraphProperties(marginleft="0.499cm", marginright="0cm", textindent="0cm", autotextindent="false")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Heading", family="paragraph", parentstylename="Standard", nextstylename="Text_20_body", attributes={'class':"text"})
|
||||
p = ParagraphProperties(margintop="0.423cm", marginbottom="0.212cm", keepwithnext="always")
|
||||
style.addElement(p)
|
||||
p = TextProperties(fontname="Nimbus Sans L", fontsize="14pt", fontnameasian="DejaVu LGC Sans", fontsizeasian="14pt", fontnamecomplex="DejaVu LGC Sans", fontsizecomplex="14pt")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Heading_20_1", displayname="Heading 1", family="paragraph", parentstylename="Heading", nextstylename="Text_20_body", attributes={'class':"text"}, defaultoutlinelevel=1)
|
||||
p = TextProperties(fontsize="115%", fontweight="bold", fontsizeasian="115%", fontweightasian="bold", fontsizecomplex="115%", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Heading_20_2", displayname="Heading 2", family="paragraph", parentstylename="Heading", nextstylename="Text_20_body", attributes={'class':"text"}, defaultoutlinelevel=2)
|
||||
p = TextProperties(fontsize="14pt", fontstyle="italic", fontweight="bold", fontsizeasian="14pt", fontstyleasian="italic", fontweightasian="bold", fontsizecomplex="14pt", fontstylecomplex="italic", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Heading_20_3", displayname="Heading 3", family="paragraph", parentstylename="Heading", nextstylename="Text_20_body", attributes={'class':"text"}, defaultoutlinelevel=3)
|
||||
p = TextProperties(fontsize="14pt", fontweight="bold", fontsizeasian="14pt", fontweightasian="bold", fontsizecomplex="14pt", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="List", family="paragraph", parentstylename="Text_20_body", attributes={'class':"list"})
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Caption", family="paragraph", parentstylename="Standard", attributes={'class':"extra"})
|
||||
p = ParagraphProperties(margintop="0.212cm", marginbottom="0.212cm", numberlines="false", linenumber="0")
|
||||
style.addElement(p)
|
||||
p = TextProperties(fontsize="12pt", fontstyle="italic", fontsizeasian="12pt", fontstyleasian="italic", fontsizecomplex="12pt", fontstylecomplex="italic")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Index", family="paragraph", parentstylename="Standard", attributes={'class':"index"})
|
||||
p = ParagraphProperties(numberlines="false", linenumber=0)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Source_20_Text", displayname="Source Text", family="text")
|
||||
p = TextProperties(fontname="Courier", fontnameasian="Courier", fontnamecomplex="Courier")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Variable", family="text")
|
||||
p = TextProperties(fontstyle="italic", fontstyleasian="italic", fontstylecomplex="italic")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Emphasis", family="text")
|
||||
p = TextProperties(fontstyle="italic", fontstyleasian="italic", fontstylecomplex="italic")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
style = Style(name="Strong_20_Emphasis", displayname="Strong Emphasis", family="text")
|
||||
p = TextProperties(fontweight="bold", fontweightasian="bold", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
doc.styles.addElement(style)
|
||||
|
||||
# Automatic styles
|
||||
style = Style(name="Bold", displayname="Bold", family="text")
|
||||
p = TextProperties(fontweight="bold", fontweightasian="bold", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
doc.automaticstyles.addElement(style)
|
||||
|
||||
style = Style(name="Italic", family="text")
|
||||
p = TextProperties(fontstyle="italic", fontstyleasian="italic", fontstylecomplex="italic")
|
||||
style.addElement(p)
|
||||
doc.automaticstyles.addElement(style)
|
||||
|
|
@ -0,0 +1,619 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2008-2009 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
#
|
||||
import string, sys, re, getopt
|
||||
import urllib2, htmlentitydefs, urlparse
|
||||
from urllib import quote_plus
|
||||
from HTMLParser import HTMLParser
|
||||
from cgi import escape,parse_header
|
||||
from types import StringType
|
||||
|
||||
from odf.opendocument import OpenDocumentText, load
|
||||
from odf import dc, text, table
|
||||
import htmlstyles
|
||||
|
||||
|
||||
def converturl(url, document=None):
|
||||
""" grab and convert url
|
||||
"""
|
||||
url = string.strip(url)
|
||||
# if url.lower()[:5] != "http:":
|
||||
# raise IOError, "Only http is accepted"
|
||||
|
||||
_proxies = {}
|
||||
proxy_support = urllib2.ProxyHandler(_proxies)
|
||||
opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
|
||||
|
||||
urllib2.install_opener(opener)
|
||||
|
||||
req = urllib2.Request(url)
|
||||
req.add_header("User-agent", "HTML2ODT: Convert HTML to OpenDocument")
|
||||
conn = urllib2.urlopen(req)
|
||||
|
||||
if not conn:
|
||||
raise IOError, "Failure in open"
|
||||
data = conn.read()
|
||||
headers = conn.info()
|
||||
conn.close()
|
||||
|
||||
encoding = 'iso8859-1' #Standard HTML
|
||||
if headers.has_key('content-type'):
|
||||
(ct, parms) = parse_header(headers['content-type'])
|
||||
if parms.has_key('charset'):
|
||||
encoding = parms['charset']
|
||||
|
||||
mhp = HTML2ODTParser(document, encoding, url)
|
||||
mhp.feed(data)
|
||||
return mhp
|
||||
|
||||
entityref = re.compile('&([a-zA-Z][-.a-zA-Z0-9]*)[^a-zA-Z0-9]')
|
||||
charref = re.compile('&#(?:[0-9]+|[xX][0-9a-fA-F]+)[^0-9a-fA-F]')
|
||||
incomplete = re.compile('&[a-zA-Z#]')
|
||||
ampersand = re.compile('&')
|
||||
|
||||
def listget(list, key, default=None):
|
||||
for l in list:
|
||||
if l[0] == key:
|
||||
default = l[1]
|
||||
return default
|
||||
|
||||
class TagObject:
|
||||
|
||||
def __init__(self, tag, attrs, output_loc):
|
||||
self.tag = tag
|
||||
self.attrs = attrs
|
||||
self.output_loc = output_loc
|
||||
|
||||
class HTML2ODTParser(HTMLParser):
|
||||
|
||||
def __init__(self, document, encoding, baseurl):
|
||||
HTMLParser.__init__(self)
|
||||
self.doc = document
|
||||
self.curr = self.doc.text
|
||||
if self.doc.getStyleByName("Standard") is None:
|
||||
style = Style(name="Standard", family="paragraph", attributes={'class':"text"})
|
||||
self.doc.styles.addElement(style)
|
||||
|
||||
if self.doc.getStyleByName("Text_20_body") is None:
|
||||
style = Style(name="Text_20_body", displayname="Text body", family="paragraph",
|
||||
parentstylename="Standard", attributes={'class':"text"})
|
||||
p = ParagraphProperties(margintop="0cm", marginbottom="0.212cm")
|
||||
style.addElement(p)
|
||||
self.doc.styles.addElement(style)
|
||||
|
||||
if self.doc.getStyleByName("Heading") is None:
|
||||
style = Style(name="Heading", family="paragraph", parentstylename="Standard",
|
||||
nextstylename="Text_20_body", attributes={'class':"text"})
|
||||
p = ParagraphProperties(margintop="0.423cm", marginbottom="0.212cm", keepwithnext="always")
|
||||
style.addElement(p)
|
||||
p = TextProperties(fontname="Nimbus Sans L", fontsize="14pt",
|
||||
fontnameasian="DejaVu LGC Sans", fontsizeasian="14pt",
|
||||
fontnamecomplex="DejaVu LGC Sans", fontsizecomplex="14pt")
|
||||
style.addElement(p)
|
||||
self.doc.styles.addElement(style)
|
||||
|
||||
self.encoding = encoding
|
||||
(scheme, host, path, params, fragment) = urlparse.urlsplit(baseurl)
|
||||
lastslash = path.rfind('/')
|
||||
if lastslash > -1:
|
||||
path = path[:lastslash]
|
||||
self.baseurl = urlparse.urlunsplit((scheme, host, path,'',''))
|
||||
self.basehost = urlparse.urlunsplit((scheme, host, '','',''))
|
||||
self.sectnum = 0
|
||||
self.tagstack = []
|
||||
self.pstack = []
|
||||
self.processelem = True
|
||||
self.processcont = True
|
||||
self.__data = []
|
||||
self.elements = {
|
||||
'a': (self.s_html_a, self.close_tag),
|
||||
'base': ( self.output_base, None),
|
||||
'b': ( self.s_html_fontstyle, self.close_tag),
|
||||
'big': ( self.s_html_fontstyle, self.close_tag),
|
||||
'br': ( self.output_br, None),
|
||||
'col': ( self.s_html_col, None),
|
||||
'dd': ( self.s_html_dd, self.close_tag),
|
||||
'dt': ( self.s_html_dt, None),
|
||||
'div': ( self.s_html_section, self.e_html_section),
|
||||
'em': ( self.s_html_emphasis, self.close_tag),
|
||||
'h1': ( self.s_html_headline, self.close_tag),
|
||||
'h2': ( self.s_html_headline, self.close_tag),
|
||||
'h3': ( self.s_html_headline, self.close_tag),
|
||||
'h4': ( self.s_html_headline, self.close_tag),
|
||||
'h5': ( self.s_html_headline, self.close_tag),
|
||||
'h6': ( self.s_html_headline, self.close_tag),
|
||||
'head': ( self.s_ignorexml, None),
|
||||
'i': ( self.s_html_fontstyle, self.close_tag),
|
||||
'img': ( self.output_img, None),
|
||||
'li': ( self.s_html_li, self.e_html_li),
|
||||
'meta': ( self.meta_encoding, None),
|
||||
'ol': ( self.output_ol, self.e_html_list),
|
||||
'p': ( self.s_html_block, self.e_html_block),
|
||||
's': ( self.s_html_fontstyle, self.close_tag),
|
||||
'small':( self.s_html_fontstyle, self.close_tag),
|
||||
'span': ( self.s_html_span, self.close_tag),
|
||||
'strike':( self.s_html_fontstyle, self.close_tag),
|
||||
'strong':( self.s_html_emphasis, self.close_tag),
|
||||
'table':( self.s_html_table, self.e_html_table),
|
||||
'td': ( self.s_html_td, self.close_tag),
|
||||
'th': ( self.s_html_td, self.close_tag),
|
||||
'title':( self.s_html_title, self.e_html_title),
|
||||
'tr': ( self.s_html_tr, self.close_tag),
|
||||
'tt': ( self.s_html_fontstyle, self.close_tag),
|
||||
'u': ( self.s_html_fontstyle, self.close_tag),
|
||||
'ul': ( self.output_ul, self.e_html_list),
|
||||
'var': ( self.s_html_emphasis, self.close_tag),
|
||||
}
|
||||
|
||||
def result(self):
|
||||
""" Return a string
|
||||
String must be in UNICODE
|
||||
"""
|
||||
str = string.join(self.__data,'')
|
||||
self.__data = []
|
||||
return str
|
||||
|
||||
def meta_name(self, attrs):
|
||||
""" Look in meta tag for textual info"""
|
||||
foundit = 0
|
||||
# Is there a name attribute?
|
||||
for attr in attrs:
|
||||
if attr[0] == 'name' and string.lower(attr[1]) in ('description',
|
||||
'keywords','title',
|
||||
'dc.description','dc.keywords','dc.title'
|
||||
):
|
||||
foundit = 1
|
||||
if foundit == 0:
|
||||
return 0
|
||||
|
||||
# Is there a content attribute?
|
||||
content = self.find_attr(attrs,'content')
|
||||
if content:
|
||||
self.handle_data(u' ')
|
||||
self.handle_attr(content)
|
||||
self.handle_data(u' ')
|
||||
return 1
|
||||
|
||||
def meta_encoding(self, tag, attrs):
|
||||
""" Look in meta tag for page encoding (Content-Type)"""
|
||||
foundit = 0
|
||||
# Is there a content-type attribute?
|
||||
for attr in attrs:
|
||||
if attr[0] == 'http-equiv' and string.lower(attr[1]) == 'content-type':
|
||||
foundit = 1
|
||||
if foundit == 0:
|
||||
return 0
|
||||
|
||||
# Is there a content attribute?
|
||||
for attr in attrs:
|
||||
if attr[0] == 'content':
|
||||
(ct, parms) = parse_header(attr[1])
|
||||
if parms.has_key('charset'):
|
||||
self.encoding = parms['charset']
|
||||
return 1
|
||||
|
||||
def s_ignorexml(self, tag, attrs):
|
||||
self.processelem = False
|
||||
|
||||
def output_base(self, tag, attrs):
|
||||
""" Change the document base if there is a base tag """
|
||||
baseurl = listget(attrs, 'href', self.baseurl)
|
||||
(scheme, host, path, params, fragment) = urlparse.urlsplit(baseurl)
|
||||
lastslash = path.rfind('/')
|
||||
if lastslash > -1:
|
||||
path = path[:lastslash]
|
||||
self.baseurl = urlparse.urlunsplit((scheme, host, path,'',''))
|
||||
self.basehost = urlparse.urlunsplit((scheme, host, '','',''))
|
||||
|
||||
def output_br(self, tag, attrs):
|
||||
self.curr.addElement(text.LineBreak())
|
||||
|
||||
def s_html_font(self, tag, attrs):
|
||||
""" 15.2.1 Font style elements: the TT, I, B, BIG, SMALL,
|
||||
STRIKE, S, and U elements
|
||||
"""
|
||||
tagdict = {
|
||||
}
|
||||
|
||||
def s_html_emphasis(self, tag, attrs):
|
||||
""" 9.2.1 Phrase elements: EM, STRONG, DFN, CODE, SAMP, KBD,
|
||||
VAR, CITE, ABBR, and ACRONYM
|
||||
"""
|
||||
tagdict = {
|
||||
'cite': ['Citation', {'fontstyle':"italic", 'fontstyleasian':"italic", 'fontstylecomplex':"italic" }],
|
||||
'code': ['Source_20_Text', {'fontname':"Courier", 'fontnameasian':"Courier",'fontnamecomplex':"Courier" }],
|
||||
'dfn': ['Definition',{ }],
|
||||
'em': ['Emphasis', {'fontstyle':"italic", 'fontstyleasian':"italic", 'fontstylecomplex':"italic" }],
|
||||
'strong': ['Strong_20_Emphasis': {'fontweight':"bold",'fontweightasian':"bold",'fontweightcomplex':"bold"}],
|
||||
'var': ['Variable', {'fontstyle':"italic", 'fontstyleasian':"italic", 'fontstylecomplex':"italic" }],
|
||||
}
|
||||
stylename = tagdict.get(tag,'Emphasis')
|
||||
# Add the styles we need to the stylesheet
|
||||
if stylename == "Source_20_Text" and self.doc.getStyleByName(stylename) is None:
|
||||
style = Style(name="Source_20_Text", displayname="Source Text", family="text")
|
||||
p = TextProperties(fontname="Courier", fontnameasian="Courier", fontnamecomplex="Courier")
|
||||
style.addElement(p)
|
||||
self.doc.styles.addElement(style)
|
||||
|
||||
e = text.Span(stylename=stylename)
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def s_html_fontstyle(self, tag, attrs):
|
||||
""" 15.2.1 Font style elements: the TT, I, B, BIG, SMALL,
|
||||
STRIKE, S, and U elements
|
||||
('tt' is not considered an automatic style by OOo)
|
||||
"""
|
||||
tagdict = {
|
||||
'b': ['BoldX',{'fontweight':"bold",
|
||||
'fontweightasian':"bold",'fontweightcomplex':"bold" }],
|
||||
'big': ['BigX', {'fontsize':"120%"}],
|
||||
'i': ['ItalicX', {'fontstyle':"italic", 'fontstyleasian':"italic", 'fontstylecomplex':"italic" }],
|
||||
'tt': ['TeletypeX', {'fontname':"Courier", 'fontnameasian':"Courier", 'fontnamecomplex':"Courier" }],
|
||||
's': ['StrikeX', {'textlinethroughstyle':"solid"}],
|
||||
'small': ['SmallX', {'fontsize':"80%"}],
|
||||
'strike': ['StrikeX', {'textlinethroughstyle':"solid"}],
|
||||
'u': ['UnderlineX', {'textunderlinestyle':"solid", 'textunderlinewidth':"auto",
|
||||
'textunderlinecolor':"fontcolor"}],
|
||||
}
|
||||
stylename,styledecl = tagdict.get(tag,[None,None])
|
||||
if stylename and self.doc.getStyleByName(stylename) is None:
|
||||
style = Style(name=stylename, family="text")
|
||||
style.addElement(TextProperties(attributes=styledecl))
|
||||
self.doc.automaticstyles.addElement(style)
|
||||
if stylename:
|
||||
e = text.Span(stylename=stylename)
|
||||
else:
|
||||
e = text.Span()
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
|
||||
def s_html_span(self, tag, attrs):
|
||||
e = text.Span()
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def s_html_title(self, tag, attrs):
|
||||
e = dc.Title()
|
||||
self.doc.meta.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def e_html_title(self, tag):
|
||||
self.curr = self.curr.parentNode
|
||||
|
||||
def output_img(self, tag, attrs):
|
||||
src = listget(attrs, 'src', "Illegal IMG tag!")
|
||||
alt = listget(attrs, 'alt', src)
|
||||
# Must remember name of image and download it.
|
||||
self.write_odt(u'<draw:image xlink:href="Pictures/%s" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/>' % '00000.png')
|
||||
|
||||
def s_html_a(self, tag, attrs):
|
||||
href = None
|
||||
href = listget(attrs, 'href', None)
|
||||
if href:
|
||||
if href in ("", "#"):
|
||||
href == self.baseurl
|
||||
elif href.find("://") >= 0:
|
||||
pass
|
||||
elif href[0] == '/':
|
||||
href = self.basehost + href
|
||||
e = text.A(type="simple", href=href)
|
||||
else:
|
||||
e = text.A()
|
||||
# if self.curr.parentNode.qname != text.P().qname:
|
||||
# p = text.P()
|
||||
# self.curr.addElement(p)
|
||||
# self.curr = p
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def close_tag(self, tag):
|
||||
self.curr = self.curr.parentNode
|
||||
|
||||
def s_html_dd(self, tag, attrs):
|
||||
if self.doc.getStyleByName("List_20_Contents") is None:
|
||||
style = Style(name="List_20_Contents", displayname="List Contents", family="paragraph",
|
||||
parentstylename="Standard", attributes={'class':"html"})
|
||||
p = ParagraphProperties(marginleft="1cm", marginright="0cm", textindent="0cm", autotextindent="false")
|
||||
style.addElement(p)
|
||||
self.doc.styles.addElement(style)
|
||||
e = text.P(stylename="List_20_Contents")
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def s_html_dt(self, tag, attrs):
|
||||
if self.doc.getStyleByName("List_20_Heading") is None:
|
||||
style = Style(name="List_20_Heading", displayname="List Heading", family="paragraph", parentstylename="Standard",
|
||||
nextstylename="List_20_Contents", attributes={'class':"html"})
|
||||
p = ParagraphProperties(marginleft="0cm", marginright="0cm", textindent="0cm", autotextindent="false")
|
||||
style.addElement(p)
|
||||
self.doc.styles.addElement(style)
|
||||
e = text.P(stylename="List_20_Heading")
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def output_ul(self, tag, attrs):
|
||||
self.write_odt(u'<text:list text:style-name="List_20_1">')
|
||||
|
||||
def output_ol(self, tag, attrs):
|
||||
self.write_odt(u'<text:list text:style-name="Numbering_20_1">')
|
||||
|
||||
def e_html_list(self, tag):
|
||||
self.write_odt(u'</text:list>')
|
||||
|
||||
def s_html_li(self, tag, attrs):
|
||||
self.write_odt(u'<text:list-item><text:p text:style-name="P1">')
|
||||
|
||||
def e_html_li(self, tag):
|
||||
self.write_odt(u'</text:p></text:list-item>')
|
||||
|
||||
def s_html_headline(self, tag, attrs):
|
||||
stylename = "Heading_20_%s" % tag[1]
|
||||
if stylename == "Heading_20_1" and self.doc.getStyleByName("Heading_20_1") is None:
|
||||
style = Style(name="Heading_20_1", displayname="Heading 1",
|
||||
family="paragraph", parentstylename="Heading", nextstylename="Text_20_body",
|
||||
attributes={'class':"text"}, defaultoutlinelevel=1)
|
||||
p = TextProperties(fontsize="115%", fontweight="bold", fontsizeasian="115%",
|
||||
fontweightasian="bold", fontsizecomplex="115%", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
self.doc.styles.addElement(style)
|
||||
|
||||
if stylename == "Heading_20_2" and self.doc.getStyleByName("Heading_20_2") is None:
|
||||
style = Style(name="Heading_20_2", displayname="Heading 2",
|
||||
family="paragraph", parentstylename="Heading", nextstylename="Text_20_body",
|
||||
attributes={'class':"text"}, defaultoutlinelevel=2)
|
||||
p = TextProperties(fontsize="14pt", fontstyle="italic", fontweight="bold",
|
||||
fontsizeasian="14pt", fontstyleasian="italic", fontweightasian="bold",
|
||||
fontsizecomplex="14pt", fontstylecomplex="italic", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
self.doc.styles.addElement(style)
|
||||
|
||||
if stylename == "Heading_20_3" and self.doc.getStyleByName("Heading_20_3") is None:
|
||||
style = Style(name="Heading_20_3", displayname="Heading 3",
|
||||
family="paragraph", parentstylename="Heading", nextstylename="Text_20_body",
|
||||
attributes={'class':"text"}, defaultoutlinelevel=3)
|
||||
p = TextProperties(fontsize="14pt", fontweight="bold", fontsizeasian="14pt",
|
||||
fontweightasian="bold", fontsizecomplex="14pt", fontweightcomplex="bold")
|
||||
style.addElement(p)
|
||||
self.doc.styles.addElement(style)
|
||||
|
||||
e = text.H(stylename="Heading_20_%s" % tag[1], outlinelevel=tag[1])
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def s_html_table(self, tag, attrs):
|
||||
e = table.Table()
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def e_html_table(self, tag):
|
||||
self.curr = self.curr.parentNode
|
||||
|
||||
def s_html_td(self, tag, attrs):
|
||||
e = table.TableCell()
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def s_html_tr(self, tag, attrs):
|
||||
e = table.TableRow()
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def s_html_col(self, tag, attrs):
|
||||
e = table.TableColumn()
|
||||
self.curr.addElement(e)
|
||||
|
||||
def s_html_section(self, tag, attrs):
|
||||
""" Outputs block tag such as <p> and <div> """
|
||||
name = self.find_attr(attrs,'id')
|
||||
if name is None:
|
||||
self.sectnum = self.sectnum + 1
|
||||
name = "Sect%d" % self.sectnum
|
||||
e = text.Section(name=name)
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def e_html_section(self, tag):
|
||||
""" Outputs block tag such as <p> and <div> """
|
||||
self.curr = self.curr.parentNode
|
||||
|
||||
def s_html_block(self, tag, attrs):
|
||||
""" Outputs block tag such as <p> and <div> """
|
||||
e = text.P(stylename="Text_20_body")
|
||||
self.curr.addElement(e)
|
||||
self.curr = e
|
||||
|
||||
def e_html_block(self, tag):
|
||||
""" Outputs block tag such as <p> and <div> """
|
||||
self.curr = self.curr.parentNode
|
||||
#
|
||||
# HANDLE STARTTAG
|
||||
#
|
||||
def handle_starttag(self, tag, attrs):
|
||||
self.pstack.append( (self.processelem, self.processcont) )
|
||||
tagobj = TagObject(tag, attrs, self.last_data_pos())
|
||||
self.tagstack.append(tagobj)
|
||||
|
||||
method = self.elements.get(tag, (None, None))[0]
|
||||
if self.processelem and method:
|
||||
method(tag, attrs)
|
||||
#
|
||||
# HANDLE END
|
||||
#
|
||||
def handle_endtag(self, tag):
|
||||
"""
|
||||
"""
|
||||
tagobj = self.tagstack.pop()
|
||||
method = self.elements.get(tag, (None, None))[1]
|
||||
if self.processelem and method:
|
||||
method(tag)
|
||||
self.processelem, self.processcont = self.pstack.pop()
|
||||
|
||||
|
||||
#
|
||||
# Data operations
|
||||
#
|
||||
def handle_data(self, data):
|
||||
if data.strip() == '': return
|
||||
if self.processelem and self.processcont:
|
||||
self.curr.addText(data)
|
||||
|
||||
def write_odt(self, data):
|
||||
""" Collect the data to show on the webpage """
|
||||
if type(data) == StringType:
|
||||
data = unicode(data, self.encoding)
|
||||
self.__data.append(data)
|
||||
|
||||
def last_data_pos(self):
|
||||
return len(self.__data)
|
||||
|
||||
def find_attr(self, attrs, key):
|
||||
""" Run through the attibutes to find a specific one
|
||||
return None if not found
|
||||
"""
|
||||
for attr in attrs:
|
||||
if attr[0] == key:
|
||||
return attr[1]
|
||||
return None
|
||||
|
||||
#
|
||||
# Tagstack operations
|
||||
#
|
||||
def find_tag(self, tag):
|
||||
""" Run down the stack to find the last entry with the same tag name
|
||||
Not Tested
|
||||
"""
|
||||
for tagitem in range(len(self.tagstack), 0, -1):
|
||||
if tagitem.tag == tag:
|
||||
return tagitem
|
||||
return None
|
||||
|
||||
def handle_charref(self, name):
|
||||
""" Handle character reference for UNICODE
|
||||
"""
|
||||
if name[0] in ('x', 'X'):
|
||||
try:
|
||||
n = int(name[1:],16)
|
||||
except ValueError:
|
||||
return
|
||||
else:
|
||||
try:
|
||||
n = int(name)
|
||||
except ValueError:
|
||||
return
|
||||
if not 0 <= n <= 65535:
|
||||
return
|
||||
self.handle_data(unichr(n))
|
||||
|
||||
def handle_entityref(self, name):
|
||||
"""Handle entity references.
|
||||
"""
|
||||
table = htmlentitydefs.name2codepoint
|
||||
if name in table:
|
||||
self.handle_data(unichr(table[name]))
|
||||
else:
|
||||
return
|
||||
|
||||
def handle_attr(self, attrval):
|
||||
""" Scan attribute values for entities and resolve them
|
||||
Simply calls handle_data
|
||||
"""
|
||||
i = 0
|
||||
n = len(attrval)
|
||||
while i < n:
|
||||
match = ampersand.search(attrval, i) #
|
||||
if match:
|
||||
j = match.start()
|
||||
else:
|
||||
j = n
|
||||
if i < j: self.handle_data(attrval[i:j])
|
||||
i = j
|
||||
if i == n: break
|
||||
startswith = attrval.startswith
|
||||
if startswith('&#', i):
|
||||
match = charref.match(attrval, i)
|
||||
if match:
|
||||
name = match.group()[2:-1]
|
||||
self.handle_charref(name)
|
||||
k = match.end()
|
||||
if not startswith(';', k-1):
|
||||
k = k - 1
|
||||
i = k
|
||||
continue
|
||||
else:
|
||||
break
|
||||
elif startswith('&', i):
|
||||
match = entityref.match(attrval, i)
|
||||
if match:
|
||||
name = match.group(1)
|
||||
self.handle_entityref(name)
|
||||
k = match.end()
|
||||
if not startswith(';', k-1):
|
||||
k = k - 1
|
||||
i = k
|
||||
continue
|
||||
match = incomplete.match(attrval, i)
|
||||
if match:
|
||||
# match.group() will contain at least 2 chars
|
||||
if match.group() == attrval[i:]:
|
||||
self.error("EOF in middle of entity or char ref")
|
||||
# incomplete
|
||||
break
|
||||
elif (i + 1) < n:
|
||||
# not the end of the buffer, and can't be confused
|
||||
# with some other construct
|
||||
self.handle_data("&")
|
||||
i = i + 1
|
||||
else:
|
||||
break
|
||||
else:
|
||||
assert 0, "interesting.search() lied"
|
||||
# end while
|
||||
if i < n:
|
||||
self.handle_data(attrval[i:n])
|
||||
i = n
|
||||
|
||||
def usage():
|
||||
sys.stderr.write("Usage: %s [-a] inputurl outputfile\n" % sys.argv[0])
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "a", ["append"])
|
||||
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
appendto = False
|
||||
for o, a in opts:
|
||||
if o in ("-a", "--append"):
|
||||
appendto = True
|
||||
|
||||
if appendto:
|
||||
doc = load(args[1])
|
||||
else:
|
||||
doc = OpenDocumentText()
|
||||
|
||||
result = converturl(args[0], doc)
|
||||
print result.doc.xml()
|
||||
result.doc.save(args[1])
|
||||
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
all: odf odf2epub.1
|
||||
|
||||
txt: odf2epub.txt
|
||||
|
||||
%.1: %.docbook
|
||||
xmlto man $<
|
||||
|
||||
%.txt: %.docbook
|
||||
xmlto txt $<
|
||||
|
||||
clean:
|
||||
rm -f *.txt odf
|
||||
|
||||
odf:
|
||||
ln -s ../../odf
|
|
@ -0,0 +1,350 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2010 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
from odf.odf2xhtml import ODF2XHTML
|
||||
from odf.namespaces import TEXTNS, XLINKNS
|
||||
from odf.opendocument import load
|
||||
import sys, getopt, time, zipfile
|
||||
from StringIO import StringIO
|
||||
from cgi import escape
|
||||
|
||||
UNIXPERMS = 0100644 << 16L # -rw-r--r--
|
||||
|
||||
def escaped(string):
|
||||
return escape(string).encode('us-ascii','xmlcharrefreplace')
|
||||
|
||||
def usage():
|
||||
sys.stderr.write("Usage: %s [-c cover-image] [-o output-file] [-p] inputfile\n" % sys.argv[0])
|
||||
|
||||
class NavpointEntry:
|
||||
def __init__(self, anchor, title, chapter, level):
|
||||
self.anchor = anchor
|
||||
self.title = title
|
||||
self.chapter = chapter
|
||||
self.level = level
|
||||
|
||||
class ODF2EPUB(ODF2XHTML):
|
||||
|
||||
in_toc = False
|
||||
navpoint_list = []
|
||||
chapters = []
|
||||
headerpart = []
|
||||
cur_html_name = 'chapter0.xhtml'
|
||||
|
||||
def __init__(self, generate_css=True, embedable=False):
|
||||
ODF2XHTML.__init__(self, generate_css, embedable)
|
||||
self.elements[(TEXTNS, "table-of-content")] = (self.s_text_table_of_content, self.e_text_table_of_content)
|
||||
|
||||
def s_text_table_of_content(self, tag, attrs):
|
||||
self.in_toc = True
|
||||
|
||||
def e_text_table_of_content(self, tag, attrs):
|
||||
self.in_toc = False
|
||||
|
||||
# def s_text_a(self, tag, attrs):
|
||||
# if self.in_toc:
|
||||
# href = attrs[(XLINKNS,"href")].split("|")[0]
|
||||
# if href[0] == "#":
|
||||
# n = NavpointEntry(self.get_anchor(href[1:]), href[1:])
|
||||
# self.navpoint_list.append(n)
|
||||
# return ODF2XHTML.s_text_a(self, tag, attrs)
|
||||
|
||||
# def e_text_a(self, tag, attrs):
|
||||
# pass
|
||||
|
||||
def s_text_h(self, tag, attrs):
|
||||
""" Handle a heading
|
||||
If the heading is a level 1 heading, then split the HTML file.
|
||||
We have to be careful, because the heading can be inside a frame or a table.
|
||||
"""
|
||||
level = int(attrs[(TEXTNS,'outline-level')])
|
||||
if level == 1:
|
||||
tags_to_keep = self.htmlstack[:]
|
||||
tags_to_close = self.htmlstack[:]
|
||||
tags_to_close.reverse()
|
||||
for htag,hattrs,hblock in tags_to_close:
|
||||
if htag == 'body':
|
||||
self.generate_footnotes()
|
||||
self._resetfootnotes()
|
||||
self.closetag(htag)
|
||||
# I have to do this rather ugly, as the saved header part doesn't
|
||||
# go through the self.opentag() method
|
||||
self.chapters.append(''.join(self.headerpart + self.lines))
|
||||
self.lines = []
|
||||
self.htmlstack = tags_to_keep[:2] # Only <html> and <body>
|
||||
for htag,hattrs,hblock in tags_to_keep[2:]:
|
||||
self.opentag(htag,hattrs,hblock)
|
||||
return ODF2XHTML.s_text_h(self, tag, attrs)
|
||||
|
||||
def e_text_h(self, tag, attrs):
|
||||
""" Headings end """
|
||||
level = int(attrs[(TEXTNS,'outline-level')])
|
||||
if level > 6: level = 6 # Heading levels go only to 6 in XHTML
|
||||
if level < 1: level = 1
|
||||
lev = self.headinglevels[1:level+1]
|
||||
outline = '.'.join(map(str,lev) )
|
||||
heading = ''.join(self.data)
|
||||
anchor = self.get_anchor("%s.%s" % ( outline, heading))
|
||||
n = NavpointEntry(anchor, heading, len(self.chapters), level)
|
||||
self.navpoint_list.append(n)
|
||||
return ODF2XHTML.e_text_h(self, tag, attrs)
|
||||
|
||||
def s_office_text(self, tag, attrs):
|
||||
""" Save all the lines up to and including the <body> tag
|
||||
so I can split the file into more files
|
||||
"""
|
||||
ODF2XHTML.s_office_text(self, tag, attrs)
|
||||
self.headerpart = self.lines
|
||||
self.lines = []
|
||||
|
||||
def e_office_document_content(self, tag, attrs):
|
||||
ODF2XHTML.e_office_document_content(self, tag, attrs)
|
||||
self.chapters.append(''.join(self.headerpart + self.lines))
|
||||
self.lines = []
|
||||
|
||||
class EPublication:
|
||||
|
||||
mimetype = "application/epub+zip"
|
||||
coverimage = None
|
||||
|
||||
coverhtml = """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Cover</title>
|
||||
<style type="text/css"> img { max-width: 100%; } </style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="cover-image">
|
||||
<img src="Pictures/cover.jpg" alt="Cover image"/>
|
||||
</div>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
container = """<?xml version="1.0"?>
|
||||
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
|
||||
<rootfiles>
|
||||
<rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml"/>
|
||||
</rootfiles>
|
||||
</container>"""
|
||||
|
||||
content_opf_head = """<?xml version="1.0"?>
|
||||
<package xmlns="http://www.idpf.org/2007/opf" unique-identifier="BookID" version="2.0">
|
||||
<metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf">
|
||||
<dc:title>%s</dc:title>
|
||||
<dc:language>%s</dc:language>
|
||||
<dc:identifier id="BookID" opf:scheme="URI">%s</dc:identifier>
|
||||
<dc:creator>%s</dc:creator>
|
||||
%s
|
||||
</metadata>
|
||||
<manifest>
|
||||
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/>
|
||||
<item id="styles-css" href="styles.css" media-type="text/css"/>"""
|
||||
|
||||
toc_ncx_head = """<?xml version="1.0"?>
|
||||
<!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN"
|
||||
"http://www.daisy.org/z3986/2005/ncx-2005-1.dtd">
|
||||
|
||||
<ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1">
|
||||
<head>
|
||||
<meta name="dtb:uid" content="%s"/>
|
||||
<meta name="dtb:depth" content="2"/>
|
||||
<meta name="dtb:totalPageCount" content="0"/>
|
||||
<meta name="dtb:maxPageNumber" content="0"/>
|
||||
</head>
|
||||
<docTitle>
|
||||
<text>%s</text>
|
||||
</docTitle>
|
||||
<navMap>
|
||||
<navPoint id="navPoint-1" playOrder="1">
|
||||
<navLabel>
|
||||
<text>Start</text>
|
||||
</navLabel>
|
||||
<content src="chapter0.xhtml"/>
|
||||
</navPoint>"""
|
||||
toc_ncx_foot = """ </navMap>
|
||||
</ncx>"""
|
||||
|
||||
def __init__(self, filename, coverimage):
|
||||
self.doc = load(filename)
|
||||
self.coverimage = coverimage
|
||||
self.odhandler = ODF2EPUB(True, False)
|
||||
self.odhandler.add_style_file("styles.css")
|
||||
self.odhandler.load(self.doc)
|
||||
|
||||
def save(self, outputfile):
|
||||
""" Save the document under the filename """
|
||||
if outputfile == '-':
|
||||
outputfp = zipfile.ZipFile(sys.stdout,"w")
|
||||
else:
|
||||
outputfp = zipfile.ZipFile(outputfile, "w")
|
||||
self._zipwrite(outputfp)
|
||||
outputfp.close()
|
||||
|
||||
def _zipwrite(self, outputfp):
|
||||
""" Write the document to an open file pointer """
|
||||
now = time.localtime()[:6]
|
||||
xhtml = self.odhandler.xhtml()
|
||||
|
||||
# Write mimetype - uncompressed
|
||||
zout = zipfile.ZipInfo('mimetype', now)
|
||||
zout.compress_type = zipfile.ZIP_STORED
|
||||
zout.external_attr = UNIXPERMS
|
||||
outputfp.writestr(zout, self.mimetype)
|
||||
|
||||
# Write META-INF/container.xml
|
||||
zout = zipfile.ZipInfo('META-INF/container.xml', now)
|
||||
zout.compress_type = zipfile.ZIP_DEFLATED
|
||||
zout.external_attr = UNIXPERMS
|
||||
outputfp.writestr(zout, self.container)
|
||||
|
||||
# Write CSS part
|
||||
zout = zipfile.ZipInfo('OEBPS/styles.css', now)
|
||||
zout.compress_type = zipfile.ZIP_DEFLATED
|
||||
zout.external_attr = UNIXPERMS
|
||||
outputfp.writestr(zout, self.odhandler.css())
|
||||
|
||||
# Write HTML parts
|
||||
for chapter in range(len(self.odhandler.chapters)):
|
||||
zout = zipfile.ZipInfo('OEBPS/chapter%d.xhtml' % chapter, now)
|
||||
zout.compress_type = zipfile.ZIP_DEFLATED
|
||||
zout.external_attr = UNIXPERMS
|
||||
xhtml = self.odhandler.chapters[chapter].encode('us-ascii','xmlcharrefreplace')
|
||||
outputfp.writestr(zout, xhtml)
|
||||
|
||||
# Copy images over to output
|
||||
for arcname, picturerec in self.doc.Pictures.items():
|
||||
what_it_is, fileobj, mediatype = picturerec
|
||||
zi = zipfile.ZipInfo("OEBPS/" + str(arcname), now)
|
||||
zi.compress_type = zipfile.ZIP_STORED
|
||||
zi.external_attr = UNIXPERMS
|
||||
outputfp.writestr(zi, fileobj)
|
||||
|
||||
# Write content.opf
|
||||
zout = zipfile.ZipInfo('OEBPS/content.opf', now)
|
||||
zout.compress_type = zipfile.ZIP_DEFLATED
|
||||
zout.external_attr = UNIXPERMS
|
||||
opf = []
|
||||
if self.coverimage:
|
||||
covermeta = """<meta name="cover" content="cover-image"/>"""
|
||||
else:
|
||||
covermeta = ""
|
||||
opf.append(self.content_opf_head % (escaped(self.odhandler.title), escaped(self.odhandler.language),
|
||||
escaped(args[0]), escaped(self.odhandler.creator), covermeta))
|
||||
if self.coverimage:
|
||||
opf.append(""" <item id="cover-page" href="cover.xhtml" media-type="application/xhtml+xml"/>""")
|
||||
opf.append(""" <item id="cover-image" href="Pictures/cover.jpg" media-type="image/jpeg"/>""")
|
||||
for chapter in range(len(self.odhandler.chapters)):
|
||||
opf.append(""" <item id="chapter%d.xhtml" href="chapter%d.xhtml" media-type="application/xhtml+xml"/>""" % (chapter, chapter))
|
||||
# Write manifest of images.
|
||||
for arcname, picturerec in self.doc.Pictures.items():
|
||||
what_it_is, fileobj, mediatype = picturerec
|
||||
opf.append(""" <item id="%s" href="%s" media-type="%s"/>""" % (arcname.replace('/','_'), arcname, mediatype))
|
||||
opf.append("""</manifest>""")
|
||||
opf.append("""<spine toc="ncx">""")
|
||||
if self.coverimage:
|
||||
opf.append(""" <itemref idref="cover-page" linear="no"/>""")
|
||||
for chapter in range(len(self.odhandler.chapters)):
|
||||
opf.append(""" <itemref idref="chapter%d.xhtml"/>""" % chapter)
|
||||
opf.append("""</spine>""")
|
||||
|
||||
if self.coverimage:
|
||||
opf.append("""<guide>""")
|
||||
opf.append(""" <reference type="cover" title="Cover" href="cover.xhtml"/>""")
|
||||
opf.append("""</guide>""")
|
||||
|
||||
opf.append('</package>')
|
||||
outputfp.writestr(zout, '\n'.join(opf))
|
||||
|
||||
# Write toc.ncx
|
||||
zout = zipfile.ZipInfo('OEBPS/toc.ncx', now)
|
||||
zout.compress_type = zipfile.ZIP_DEFLATED
|
||||
zout.external_attr = UNIXPERMS
|
||||
opf = []
|
||||
opf.append(self.toc_ncx_head % (escaped(args[0]), escaped(self.odhandler.title)))
|
||||
# We basically force the first navpoint to be a level 1 heading, no
|
||||
# matter what it was in reality. Then all other headings are either level 1 or 2.
|
||||
np_inx = 2
|
||||
np_level = 1
|
||||
for np in self.odhandler.navpoint_list:
|
||||
if np_inx == 2:
|
||||
np.level = 1
|
||||
if np.level > 2: np.level = 2
|
||||
if np_inx != 2 and np.level <= np_level:
|
||||
opf.append(""" </navPoint>""");
|
||||
if np_inx != 2 and np.level < np_level:
|
||||
opf.append(""" </navPoint>""");
|
||||
opf.append(""" <navPoint id="navPoint-%d" playOrder="%d"> <!-- L%d -->
|
||||
<navLabel>
|
||||
<text>%s</text>
|
||||
</navLabel>
|
||||
<content src="chapter%d.xhtml#%s"/>
|
||||
""" % (np_inx, np_inx, np.level, escaped(np.title), np.chapter, np.anchor))
|
||||
np_inx += 1
|
||||
np_level = np.level
|
||||
opf.append(""" </navPoint>""");
|
||||
if np_level > 1:
|
||||
opf.append(""" </navPoint>""");
|
||||
opf.append(self.toc_ncx_foot)
|
||||
outputfp.writestr(zout, '\n'.join(opf))
|
||||
|
||||
# Write cover image
|
||||
if self.coverimage:
|
||||
outputfp.write(coverimage,'OEBPS/Pictures/cover.jpg', zipfile.ZIP_STORED)
|
||||
zout = zipfile.ZipInfo('OEBPS/cover.xhtml', now)
|
||||
zout.compress_type = zipfile.ZIP_DEFLATED
|
||||
zout.external_attr = UNIXPERMS
|
||||
outputfp.writestr(zout, self.coverhtml)
|
||||
|
||||
# zout = zipfile.ZipInfo('OEBPS/styles.css', now)
|
||||
# zout.compress_type = zipfile.ZIP_DEFLATED
|
||||
# zout.external_attr = UNIXPERMS
|
||||
# css = self.odhandler.css().encode('us-ascii','xmlcharrefreplace')
|
||||
# outputfp.writestr(zout, css)
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "c:po:", ["cover", "plain","output"])
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
generatecss = True
|
||||
embedable = False
|
||||
outputfilename = "-"
|
||||
coverimage = None
|
||||
|
||||
for o, a in opts:
|
||||
if o in ("-c", "--cover"):
|
||||
coverimage = a
|
||||
if o in ("-p", "--plain"):
|
||||
generatecss = False
|
||||
if o in ("-o", "--output"):
|
||||
outputfilename = a
|
||||
|
||||
if len(args) != 1:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
try:
|
||||
epub = EPublication(args[0], coverimage)
|
||||
epub.save(outputfilename)
|
||||
except:
|
||||
sys.stderr.write("Unable to open file %s or file is not OpenDocument\n" % sys.argv[1])
|
||||
sys.exit(1)
|
||||
sys.exit(0)
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
'\" t
|
||||
.\" Title: odf2epub
|
||||
.\" Author: S\(/oren Roug
|
||||
.\" Generator: DocBook XSL Stylesheets v1.75.2 <http://docbook.sf.net/>
|
||||
.\" Date: 05/16/2010
|
||||
.\" Manual: User commands
|
||||
.\" Source: odfpy
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "ODF2EPUB" "1" "05/16/2010" "odfpy" "User commands"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "NAME"
|
||||
odf2epub \- Convert ODF to an ePub ebook
|
||||
.SH "SYNOPSIS"
|
||||
.HP \w'\fBodf2epub\fR\ 'u
|
||||
\fBodf2epub\fR [\-p] [\-o\ \fIoutputfile\fR] [\-c\ \fIcover_image\fR] \fIpath\fR
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
\fBodf2epub\fR
|
||||
is a program that will create an ebook (\&.epub) from the input file and will write the ebook to stdout or a file specified by \-o\&. "Path" is assumed to be an OpenDocument file of text, spreadsheet or presentation type\&.
|
||||
.PP
|
||||
If the document doesn\'t have a title in the properties, then the first heading of any level is used\&.
|
||||
.SH "OPTIONS"
|
||||
.PP
|
||||
\-c, \-\-cover
|
||||
.RS 4
|
||||
The \-c argument add a cover image to the EPUB file\&. Make sure the cover image itself is scaled to less than 1000px in width and height\&. Best practice is to use an image in JPG or PNG format at 600 pixels wide by 800 pixels in height\&.
|
||||
.RE
|
||||
.PP
|
||||
\-p, \-\-plain
|
||||
.RS 4
|
||||
The \-p flag will generate HTML without CSS\&.
|
||||
.RE
|
||||
.PP
|
||||
\-o, \-\-output
|
||||
.RS 4
|
||||
Specify the output file with this flag\&. "\-" implies standard out\&.
|
||||
.RE
|
||||
.SH "EXAMPLE"
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.nf
|
||||
odf2epub \-o example\&.epub odf\-file\&.odt
|
||||
.fi
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.SH "BUGS"
|
||||
.PP
|
||||
The EPUB format has the following limitations when running on a mobile device\&. If these limits are not adhered to, EPUB files
|
||||
\fImight\fR
|
||||
not work on mobile devices\&. Image Size: 10MB uncompressed\&. Individual XHTML file sizes: 300k uncompressed/100k compressed\&. Odf2epub does not ensure that these limits are adhered to\&.
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
\fBodf2xhtml\fR(1)
|
||||
.SH "AUTHOR"
|
||||
.PP
|
||||
\fBS\(/oren Roug\fR
|
||||
.RS 4
|
||||
Original author
|
||||
.RE
|
|
@ -0,0 +1,92 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<refentry id="odf2epub">
|
||||
<refentryinfo>
|
||||
<productname>odfpy</productname>
|
||||
<author><firstname>Søren</firstname><surname>Roug</surname>
|
||||
<contrib>Original author</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>odf2epub</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">User commands</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname>odf2epub</refname>
|
||||
<refpurpose>Convert ODF to an ePub ebook</refpurpose>
|
||||
</refnamediv>
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>odf2epub</command>
|
||||
<arg choice="opt">-p </arg>
|
||||
<arg choice="opt">-o <replaceable>outputfile</replaceable></arg>
|
||||
<arg choice="opt">-c <replaceable>cover_image</replaceable></arg>
|
||||
<arg choice="plain">
|
||||
<replaceable>path</replaceable>
|
||||
</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para><command>odf2epub</command> is a program that will create
|
||||
an ebook (.epub) from the input file and will write the ebook to stdout or a file specified by -o.
|
||||
"Path" is assumed to be an
|
||||
OpenDocument file of text, spreadsheet or presentation type.
|
||||
</para>
|
||||
<para>
|
||||
If the document doesn't have a title in the properties, then the first heading of any level is used.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>-c, --cover</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The -c argument add a cover image to the EPUB file.
|
||||
Make sure the cover image itself is scaled to less than 1000px in width and height. Best practice
|
||||
is to use an image in JPG or PNG format at 600 pixels wide by 800 pixels in height.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-p, --plain</term>
|
||||
<listitem>
|
||||
<para>
|
||||
The -p flag will generate HTML without CSS.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-o, --output</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify the output file with this flag. "-" implies standard out.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Example</title>
|
||||
<screen>
|
||||
odf2epub -o example.epub odf-file.odt
|
||||
</screen>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Bugs</title>
|
||||
<para>The EPUB format has the following limitations when running on a mobile device.
|
||||
If these limits are not adhered to, EPUB files <emphasis>might</emphasis> not work on mobile devices. Image Size: 10MB uncompressed.
|
||||
Individual XHTML file sizes: 300k uncompressed/100k compressed. Odf2epub does not ensure
|
||||
that these limits are adhered to.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para><command>odf2xhtml</command>(1)</para>
|
||||
</refsect1>
|
||||
</refentry>
|
|
@ -0,0 +1,15 @@
|
|||
all: odf odf2gbzip.1
|
||||
|
||||
txt: odf2gbzip.txt
|
||||
|
||||
%.1: %.docbook
|
||||
xmlto man $<
|
||||
|
||||
%.txt: %.docbook
|
||||
xmlto txt $<
|
||||
|
||||
clean:
|
||||
rm -f *.txt odf
|
||||
|
||||
odf:
|
||||
ln -s ../../odf
|
|
@ -0,0 +1,64 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
from odf.odf2xhtml import ODF2XHTML
|
||||
import zipfile
|
||||
import sys
|
||||
from time import localtime
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
sys.stderr.write("Usage: %s inputfile outputfile\n" % sys.argv[0])
|
||||
sys.exit(1)
|
||||
|
||||
inpath = sys.argv[1]
|
||||
basename = inpath[max(inpath.rfind('/'), inpath.rfind('\\'), inpath.rfind(':'))+1:]
|
||||
dot = basename.rfind('.')
|
||||
if dot > 0: basename = basename[:dot]
|
||||
|
||||
now = localtime()[:6]
|
||||
|
||||
odhandler = ODF2XHTML()
|
||||
result = odhandler.odf2xhtml(inpath).encode('us-ascii','xmlcharrefreplace')
|
||||
|
||||
try:
|
||||
zout = zipfile.ZipFile(sys.argv[2], "w", zipfile.ZIP_DEFLATED)
|
||||
except:
|
||||
sys.stderr.write("Unable to open %s for writing\n" % sys.argv[2])
|
||||
|
||||
zipinfo = zipfile.ZipInfo('%s/%s.htm' % (basename, basename), now)
|
||||
zipinfo.external_attr = 0100644 << 16L # Unix permissions
|
||||
zout.writestr(zipinfo, result)
|
||||
|
||||
try:
|
||||
z = zipfile.ZipFile(inpath)
|
||||
except:
|
||||
sys.stderr.write("Unable to open %s or file is not OpenDocument\n" % sys.argv[2])
|
||||
|
||||
for zinfo in z.infolist():
|
||||
if zinfo.filename[0:9] == 'Pictures/':
|
||||
zipinfo = zipfile.ZipInfo(basename + "/" + zinfo.filename, now)
|
||||
zipinfo.external_attr = 0100644 << 16L # Unix permissions
|
||||
zout.writestr(zipinfo, z.read(zinfo.filename))
|
||||
z.close()
|
||||
zout.close()
|
|
@ -0,0 +1,35 @@
|
|||
.\" Title: odf2gbzip
|
||||
.\" Author:
|
||||
.\" Generator: DocBook XSL Stylesheets v1.72.0 <http://docbook.sf.net/>
|
||||
.\" Date: 09/29/2007
|
||||
.\" Manual:
|
||||
.\" Source:
|
||||
.\"
|
||||
.TH "ODF2GBZIP" "1" "09/29/2007" "" ""
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.SH "NAME"
|
||||
odf2gbzip \- Convert ODF to zipped web archive
|
||||
.SH "SYNOPSIS"
|
||||
.HP 10
|
||||
\fBodf2gbzip\fR \fIpath\fR
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
\fBodf2gbzip\fR
|
||||
is a program that will create a zipped web archive according to the convention followed by Project Gutenberg.
|
||||
.PP
|
||||
"Path" is assumed to be an OpenDocument file of text, spreadsheet or presentation type.
|
||||
.SH "EXAMPLE"
|
||||
.sp
|
||||
.RS 4
|
||||
.nf
|
||||
odf2gbzip odf\-file
|
||||
.fi
|
||||
.RE
|
||||
.SH "SEE ALSO"
|
||||
.PP
|
||||
|
||||
\fBodf2mht\fR(1)
|
||||
\fBodf2war\fR(1)
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<refentry id="odf2gbzip">
|
||||
<refnamediv>
|
||||
<refname>odf2gbzip</refname>
|
||||
<refpurpose>Convert ODF to zipped web archive</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>odf2gbzip</command>
|
||||
<arg choice="plain"><replaceable>path</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para><command>odf2gbzip</command> is a program that will create
|
||||
a zipped web archive according to the convention followed by Project Gutenberg.
|
||||
</para>
|
||||
<para>
|
||||
"Path" is assumed to be an
|
||||
OpenDocument file of text, spreadsheet or presentation type.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1><title>Example</title>
|
||||
<screen>
|
||||
odf2gbzip odf-file
|
||||
</screen>
|
||||
</refsect1>
|
||||
<refsect1><title>See Also</title>
|
||||
<para>
|
||||
<command>odf2mht</command>(1)
|
||||
<command>odf2war</command>(1)
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
all: odf odf2war.1
|
||||
|
||||
txt: odf2war.txt
|
||||
|
||||
%.1: %.docbook
|
||||
xmlto man $<
|
||||
|
||||
%.txt: %.docbook
|
||||
xmlto txt $<
|
||||
|
||||
clean:
|
||||
rm -f *.txt odf
|
||||
|
||||
odf:
|
||||
ln -s ../odf
|
|
@ -0,0 +1,61 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
from odf.odf2xhtml import ODF2XHTML
|
||||
import tarfile
|
||||
import zipfile
|
||||
import sys
|
||||
from time import time
|
||||
|
||||
try:
|
||||
from cStringIO import StringIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
sys.stderr.write("Usage: %s inputfile outputfile\n" % sys.argv[0])
|
||||
sys.exit(1)
|
||||
|
||||
now = long(time())
|
||||
odhandler = ODF2XHTML()
|
||||
result = odhandler.odf2xhtml(sys.argv[1]).encode('us-ascii','xmlcharrefreplace')
|
||||
tar = tarfile.open(sys.argv[2], "w:gz")
|
||||
tarinfo = tarfile.TarInfo()
|
||||
tarinfo.name = 'index.html'
|
||||
tarinfo.uid = 501
|
||||
tarinfo.gid = 100
|
||||
tarinfo.size = len(result)
|
||||
tarinfo.mtime = now
|
||||
#tarinfo.uname = "johndoe"
|
||||
#tarinfo.gname = "fake"
|
||||
tar.addfile(tarinfo, StringIO(result))
|
||||
z = zipfile.ZipFile(sys.argv[1])
|
||||
for zinfo in z.infolist():
|
||||
if zinfo.filename[0:9] == 'Pictures/':
|
||||
tarinfo = tarfile.TarInfo()
|
||||
tarinfo.name = zinfo.filename
|
||||
tarinfo.uid = 501
|
||||
tarinfo.gid = 456
|
||||
tarinfo.size = zinfo.file_size
|
||||
tarinfo.mtime = now
|
||||
#tarinfo.uname = "johndoe"
|
||||
#tarinfo.gname = "fake"
|
||||
tar.addfile(tarinfo, StringIO(z.read(zinfo.filename)))
|
||||
z.close()
|
||||
tar.close()
|
|
@ -0,0 +1,217 @@
|
|||
.\" Title: odf2war
|
||||
.\" Author: S\(/oren Roug
|
||||
.\" Generator: DocBook XSL Stylesheets v1.74.0 <http://docbook.sf.net/>
|
||||
.\" Date: 01/04/2009
|
||||
.\" Manual: User commands
|
||||
.\" Source: odfpy
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "ODF2WAR" "1" "01/04/2009" "odfpy" "User commands"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * (re)Define some macros
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" toupper - uppercase a string (locale-aware)
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de toupper
|
||||
.tr aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
|
||||
\\$*
|
||||
.tr aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SH-xref - format a cross-reference to an SH section
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de SH-xref
|
||||
.ie n \{\
|
||||
.\}
|
||||
.toupper \\$*
|
||||
.el \{\
|
||||
\\$*
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SH - level-one heading that works better for non-TTY output
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de1 SH
|
||||
.\" put an extra blank line of space above the head in non-TTY output
|
||||
.if t \{\
|
||||
.sp 1
|
||||
.\}
|
||||
.sp \\n[PD]u
|
||||
.nr an-level 1
|
||||
.set-an-margin
|
||||
.nr an-prevailing-indent \\n[IN]
|
||||
.fi
|
||||
.in \\n[an-margin]u
|
||||
.ti 0
|
||||
.HTML-TAG ".NH \\n[an-level]"
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
.nr an-break-flag 1
|
||||
\." make the size of the head bigger
|
||||
.ps +3
|
||||
.ft B
|
||||
.ne (2v + 1u)
|
||||
.ie n \{\
|
||||
.\" if n (TTY output), use uppercase
|
||||
.toupper \\$*
|
||||
.\}
|
||||
.el \{\
|
||||
.nr an-break-flag 0
|
||||
.\" if not n (not TTY), use normal case (not uppercase)
|
||||
\\$1
|
||||
.in \\n[an-margin]u
|
||||
.ti 0
|
||||
.\" if not n (not TTY), put a border/line under subheading
|
||||
.sp -.6
|
||||
\l'\n(.lu'
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SS - level-two heading that works better for non-TTY output
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de1 SS
|
||||
.sp \\n[PD]u
|
||||
.nr an-level 1
|
||||
.set-an-margin
|
||||
.nr an-prevailing-indent \\n[IN]
|
||||
.fi
|
||||
.in \\n[IN]u
|
||||
.ti \\n[SN]u
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
.nr an-break-flag 1
|
||||
.ps \\n[PS-SS]u
|
||||
\." make the size of the head bigger
|
||||
.ps +2
|
||||
.ft B
|
||||
.ne (2v + 1u)
|
||||
.if \\n[.$] \&\\$*
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" BB/BE - put background/screen (filled box) around block of text
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de BB
|
||||
.if t \{\
|
||||
.sp -.5
|
||||
.br
|
||||
.in +2n
|
||||
.ll -2n
|
||||
.gcolor red
|
||||
.di BX
|
||||
.\}
|
||||
..
|
||||
.de EB
|
||||
.if t \{\
|
||||
.if "\\$2"adjust-for-leading-newline" \{\
|
||||
.sp -1
|
||||
.\}
|
||||
.br
|
||||
.di
|
||||
.in
|
||||
.ll
|
||||
.gcolor
|
||||
.nr BW \\n(.lu-\\n(.i
|
||||
.nr BH \\n(dn+.5v
|
||||
.ne \\n(BHu+.5v
|
||||
.ie "\\$2"adjust-for-leading-newline" \{\
|
||||
\M[\\$1]\h'1n'\v'+.5v'\D'P \\n(BWu 0 0 \\n(BHu -\\n(BWu 0 0 -\\n(BHu'\M[]
|
||||
.\}
|
||||
.el \{\
|
||||
\M[\\$1]\h'1n'\v'-.5v'\D'P \\n(BWu 0 0 \\n(BHu -\\n(BWu 0 0 -\\n(BHu'\M[]
|
||||
.\}
|
||||
.in 0
|
||||
.sp -.5v
|
||||
.nf
|
||||
.BX
|
||||
.in
|
||||
.sp .5v
|
||||
.fi
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" BM/EM - put colored marker in margin next to block of text
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de BM
|
||||
.if t \{\
|
||||
.br
|
||||
.ll -2n
|
||||
.gcolor red
|
||||
.di BX
|
||||
.\}
|
||||
..
|
||||
.de EM
|
||||
.if t \{\
|
||||
.br
|
||||
.di
|
||||
.ll
|
||||
.gcolor
|
||||
.nr BH \\n(dn
|
||||
.ne \\n(BHu
|
||||
\M[\\$1]\D'P -.75n 0 0 \\n(BHu -(\\n[.i]u - \\n(INu - .75n) 0 0 -\\n(BHu'\M[]
|
||||
.in 0
|
||||
.nf
|
||||
.BX
|
||||
.in
|
||||
.fi
|
||||
.\}
|
||||
..
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "Name"
|
||||
odf2war \- Convert ODF to KDE web archive
|
||||
.SH "Synopsis"
|
||||
.fam C
|
||||
.HP \w'\fBodf2war\fR\ 'u
|
||||
\fBodf2war\fR \fIpath\fR
|
||||
.fam
|
||||
.SH "Description"
|
||||
.PP
|
||||
\fBodf2war\fR
|
||||
is a program that will create a KDE Web Archive (\&.war) that can be read by Konqueror filemanager\&. It will write the web archive to stdout\&. The WAR plugin is part of the kdeaddons package\&.
|
||||
.PP
|
||||
"Path" is assumed to be an OpenDocument file of text, spreadsheet or presentation type\&.
|
||||
.SH "Example"
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.fam C
|
||||
.ps -1
|
||||
.nf
|
||||
.if t \{\
|
||||
.sp -1
|
||||
.\}
|
||||
.BB lightgray adjust-for-leading-newline
|
||||
.sp -1
|
||||
|
||||
odf2war odf\-file
|
||||
.EB lightgray adjust-for-leading-newline
|
||||
.if t \{\
|
||||
.sp 1
|
||||
.\}
|
||||
.fi
|
||||
.fam
|
||||
.ps +1
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.SH "See Also"
|
||||
.PP
|
||||
|
||||
\fBodftools\fR(1),
|
||||
\fBodf2mht\fR(1)
|
||||
.SH "Author"
|
||||
.PP
|
||||
\fBS\(/oren Roug\fR
|
||||
.RS 4
|
||||
Original author
|
||||
.RE
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<refentry id="odf2war">
|
||||
<refentryinfo>
|
||||
<productname>odfpy</productname>
|
||||
<author><firstname>Søren</firstname><surname>Roug</surname>
|
||||
<contrib>Original author</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>odf2war</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">User commands</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname>odf2war</refname>
|
||||
<refpurpose>Convert ODF to KDE web archive</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>odf2war</command>
|
||||
<arg choice="plain"><replaceable>path</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para><command>odf2war</command> is a program that will create
|
||||
a KDE Web Archive (.war) that can be read by Konqueror filemanager. It
|
||||
will write the web archive to stdout. The WAR plugin is part of the
|
||||
kdeaddons package.
|
||||
</para>
|
||||
<para>
|
||||
"Path" is assumed to be an
|
||||
OpenDocument file of text, spreadsheet or presentation type.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1><title>Example</title>
|
||||
<screen>
|
||||
odf2war odf-file
|
||||
</screen>
|
||||
</refsect1>
|
||||
<refsect1><title>See Also</title>
|
||||
<para>
|
||||
<command>odftools</command>(1),
|
||||
<command>odf2mht</command>(1)
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
all: odf odfsign.1
|
||||
|
||||
txt: odfsign.txt
|
||||
|
||||
%.1: %.docbook
|
||||
xmlto man $<
|
||||
|
||||
%.txt: %.docbook
|
||||
xmlto txt $<
|
||||
|
||||
clean:
|
||||
rm -f *.txt odf
|
||||
odf:
|
||||
ln -s ../../odf
|
|
@ -0,0 +1,92 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2006 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Requires PyXML
|
||||
import sha,base64,zipfile,sys
|
||||
from xml.dom.ext.reader import PyExpat
|
||||
from xml.dom.ext.c14n import Canonicalize
|
||||
import StringIO
|
||||
|
||||
|
||||
def data_digest(data):
|
||||
return base64.b64encode(sha.new(data).digest())
|
||||
|
||||
def xml_digest(dom):
|
||||
s = StringIO.StringIO()
|
||||
Canonicalize(dom,s)
|
||||
canon = s.getvalue().encode('utf-8')
|
||||
return data_digest(canon)
|
||||
|
||||
def get_signatureproperty(dom, ref):
|
||||
property_list = dom.getElementsByTagNameNS('http://www.w3.org/2000/09/xmldsig#','SignatureProperty')
|
||||
for p in property_list:
|
||||
id = p.getAttributeNS(None,'Id')
|
||||
if ref == id: return p
|
||||
return None
|
||||
|
||||
def exitwithusage(exitcode=2):
|
||||
sys.stderr.write("Usage: %s inputfile\n" % sys.argv[0])
|
||||
sys.exit(exitcode)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) != 2:
|
||||
exitwithusage()
|
||||
z = zipfile.ZipFile(sys.argv[1])
|
||||
namelist = z.namelist()
|
||||
if "META-INF/documentsignatures.xml" not in namelist:
|
||||
print "This document is not signed"
|
||||
sys.exit()
|
||||
documentsignatures_xml = z.read('META-INF/documentsignatures.xml')
|
||||
reader = PyExpat.Reader()
|
||||
doc = reader.fromString(documentsignatures_xml)
|
||||
|
||||
signature_list = doc.getElementsByTagNameNS('http://www.w3.org/2000/09/xmldsig#','Signature')
|
||||
print "Document has %s signature(s)" % len(signature_list)
|
||||
signnum = 1
|
||||
for signature in signature_list:
|
||||
date = signature.getElementsByTagNameNS("http://purl.org/dc/elements/1.1/","date")[0].firstChild.nodeValue
|
||||
# print date.__dict__
|
||||
|
||||
print "Checking signature #%d - signed on %s" % (signnum, date),
|
||||
refs = signature.getElementsByTagNameNS('http://www.w3.org/2000/09/xmldsig#','Reference')
|
||||
for ref in refs:
|
||||
status = "OK"
|
||||
uri = ref.getAttributeNS(None,'URI')
|
||||
digest_value = ref.getElementsByTagNameNS('http://www.w3.org/2000/09/xmldsig#','DigestValue')[0].firstChild.nodeValue
|
||||
if uri[0] != '#':
|
||||
document = z.read(uri)
|
||||
if uri[-4:] == ".xml" and len(document) != 0:
|
||||
dom = PyExpat.Reader().fromString(document)
|
||||
digest_actual = xml_digest(dom)
|
||||
else:
|
||||
digest_actual = data_digest(document)
|
||||
else:
|
||||
# FIXME
|
||||
# fragments aren't canonicalized. See http://www.w3.org/TR/xmldsig-core/#sec-URI
|
||||
xmlfragment = get_signatureproperty(doc, uri[1:])
|
||||
if xmlfragment is None:
|
||||
continue
|
||||
digest_actual = digest_value
|
||||
#digest_actual = xml_digest(xmlfragment)
|
||||
if digest_value != digest_actual:
|
||||
status = "failed"
|
||||
|
||||
print status
|
||||
signnum += 1
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
.\" Title: odfsign
|
||||
.\" Author: S\(/oren Roug
|
||||
.\" Generator: DocBook XSL Stylesheets v1.74.0 <http://docbook.sf.net/>
|
||||
.\" Date: 03/16/2009
|
||||
.\" Manual: User commands
|
||||
.\" Source: odfpy
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "ODFSIGN" "1" "03/16/2009" "odfpy" "User commands"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * (re)Define some macros
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" toupper - uppercase a string (locale-aware)
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de toupper
|
||||
.tr aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
|
||||
\\$*
|
||||
.tr aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SH-xref - format a cross-reference to an SH section
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de SH-xref
|
||||
.ie n \{\
|
||||
.\}
|
||||
.toupper \\$*
|
||||
.el \{\
|
||||
\\$*
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SH - level-one heading that works better for non-TTY output
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de1 SH
|
||||
.\" put an extra blank line of space above the head in non-TTY output
|
||||
.if t \{\
|
||||
.sp 1
|
||||
.\}
|
||||
.sp \\n[PD]u
|
||||
.nr an-level 1
|
||||
.set-an-margin
|
||||
.nr an-prevailing-indent \\n[IN]
|
||||
.fi
|
||||
.in \\n[an-margin]u
|
||||
.ti 0
|
||||
.HTML-TAG ".NH \\n[an-level]"
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
.nr an-break-flag 1
|
||||
\." make the size of the head bigger
|
||||
.ps +3
|
||||
.ft B
|
||||
.ne (2v + 1u)
|
||||
.ie n \{\
|
||||
.\" if n (TTY output), use uppercase
|
||||
.toupper \\$*
|
||||
.\}
|
||||
.el \{\
|
||||
.nr an-break-flag 0
|
||||
.\" if not n (not TTY), use normal case (not uppercase)
|
||||
\\$1
|
||||
.in \\n[an-margin]u
|
||||
.ti 0
|
||||
.\" if not n (not TTY), put a border/line under subheading
|
||||
.sp -.6
|
||||
\l'\n(.lu'
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SS - level-two heading that works better for non-TTY output
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de1 SS
|
||||
.sp \\n[PD]u
|
||||
.nr an-level 1
|
||||
.set-an-margin
|
||||
.nr an-prevailing-indent \\n[IN]
|
||||
.fi
|
||||
.in \\n[IN]u
|
||||
.ti \\n[SN]u
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
.nr an-break-flag 1
|
||||
.ps \\n[PS-SS]u
|
||||
\." make the size of the head bigger
|
||||
.ps +2
|
||||
.ft B
|
||||
.ne (2v + 1u)
|
||||
.if \\n[.$] \&\\$*
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" BB/BE - put background/screen (filled box) around block of text
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de BB
|
||||
.if t \{\
|
||||
.sp -.5
|
||||
.br
|
||||
.in +2n
|
||||
.ll -2n
|
||||
.gcolor red
|
||||
.di BX
|
||||
.\}
|
||||
..
|
||||
.de EB
|
||||
.if t \{\
|
||||
.if "\\$2"adjust-for-leading-newline" \{\
|
||||
.sp -1
|
||||
.\}
|
||||
.br
|
||||
.di
|
||||
.in
|
||||
.ll
|
||||
.gcolor
|
||||
.nr BW \\n(.lu-\\n(.i
|
||||
.nr BH \\n(dn+.5v
|
||||
.ne \\n(BHu+.5v
|
||||
.ie "\\$2"adjust-for-leading-newline" \{\
|
||||
\M[\\$1]\h'1n'\v'+.5v'\D'P \\n(BWu 0 0 \\n(BHu -\\n(BWu 0 0 -\\n(BHu'\M[]
|
||||
.\}
|
||||
.el \{\
|
||||
\M[\\$1]\h'1n'\v'-.5v'\D'P \\n(BWu 0 0 \\n(BHu -\\n(BWu 0 0 -\\n(BHu'\M[]
|
||||
.\}
|
||||
.in 0
|
||||
.sp -.5v
|
||||
.nf
|
||||
.BX
|
||||
.in
|
||||
.sp .5v
|
||||
.fi
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" BM/EM - put colored marker in margin next to block of text
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de BM
|
||||
.if t \{\
|
||||
.br
|
||||
.ll -2n
|
||||
.gcolor red
|
||||
.di BX
|
||||
.\}
|
||||
..
|
||||
.de EM
|
||||
.if t \{\
|
||||
.br
|
||||
.di
|
||||
.ll
|
||||
.gcolor
|
||||
.nr BH \\n(dn
|
||||
.ne \\n(BHu
|
||||
\M[\\$1]\D'P -.75n 0 0 \\n(BHu -(\\n[.i]u - \\n(INu - .75n) 0 0 -\\n(BHu'\M[]
|
||||
.in 0
|
||||
.nf
|
||||
.BX
|
||||
.in
|
||||
.fi
|
||||
.\}
|
||||
..
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "Name"
|
||||
odfsign \- Verify a signed ODF document
|
||||
.SH "Synopsis"
|
||||
.fam C
|
||||
.HP \w'\fBodfsign\fR\ 'u
|
||||
\fBodfsign\fR \fIpath\fR
|
||||
.fam
|
||||
.SH "Description"
|
||||
.PP
|
||||
\fBodfsign\fR
|
||||
checks that the checksums used in the signature are correct\&.
|
||||
\fIIt does not check that the x509 digest is correct!\fR
|
||||
Therefore it is currently of little use\&.
|
||||
.PP
|
||||
"Path" is assumed to be an OpenDocument file of text, spreadsheet or presentation type\&.
|
||||
.SH "Example"
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.fam C
|
||||
.ps -1
|
||||
.nf
|
||||
.if t \{\
|
||||
.sp -1
|
||||
.\}
|
||||
.BB lightgray adjust-for-leading-newline
|
||||
.sp -1
|
||||
|
||||
odfsign odf\-file
|
||||
.EB lightgray adjust-for-leading-newline
|
||||
.if t \{\
|
||||
.sp 1
|
||||
.\}
|
||||
.fi
|
||||
.fam
|
||||
.ps +1
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.SH "See Also"
|
||||
.PP
|
||||
http://www\&.w3\&.org/TR/xmldsig\-core
|
||||
.SH "Author"
|
||||
.PP
|
||||
\fBS\(/oren Roug\fR
|
||||
.RS 4
|
||||
Original author
|
||||
.RE
|
|
@ -0,0 +1,50 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<refentry id="odfsign">
|
||||
<refentryinfo>
|
||||
<productname>odfpy</productname>
|
||||
<author><firstname>Søren</firstname><surname>Roug</surname>
|
||||
<contrib>Original author</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>odfsign</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">User commands</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname>odfsign</refname>
|
||||
<refpurpose>Verify a signed ODF document</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>odfsign</command>
|
||||
<arg choice="plain"><replaceable>path</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para><command>odfsign</command> checks that the checksums
|
||||
used in the signature are correct.
|
||||
<emphasis>It does not check that the x509 digest is correct!</emphasis>
|
||||
Therefore it is currently of little use.
|
||||
</para>
|
||||
<para>
|
||||
"Path" is assumed to be an
|
||||
OpenDocument file of text, spreadsheet or presentation type.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1><title>Example</title>
|
||||
<screen>
|
||||
odfsign odf-file
|
||||
</screen>
|
||||
</refsect1>
|
||||
<refsect1><title>See Also</title>
|
||||
<para>
|
||||
http://www.w3.org/TR/xmldsig-core
|
||||
</para>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,32 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
PACKAGE = 'OdfToHtml'
|
||||
VERSION = '0.1'
|
||||
|
||||
setup(name='OdfToHtml',
|
||||
version='0.1',
|
||||
packages=['odftohtml'],
|
||||
author='Soren Roug',
|
||||
author_email='soren.roug@eea.europa.eu',
|
||||
description='A plugin for viewing ODF pages as HTML',
|
||||
url='http://trac-hacks.org/wiki/OdfToHtmlConverter',
|
||||
entry_points={'trac.plugins': ['odftohtml.odftohtml=odftohtml.odftohtml']})
|
|
@ -0,0 +1,14 @@
|
|||
all: odf odscell.1
|
||||
|
||||
txt: odscell.txt
|
||||
|
||||
%.1: %.docbook
|
||||
xmlto man $<
|
||||
|
||||
%.txt: %.docbook
|
||||
xmlto txt $<
|
||||
|
||||
clean:
|
||||
rm -f *.txt odf
|
||||
odf:
|
||||
ln -s ../../odf
|
|
@ -0,0 +1,184 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2010 Kartikaya Gupta, https://staktrace.com/
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from odf import opendocument
|
||||
from odf.element import Text
|
||||
from odf.table import *
|
||||
from odf.text import P
|
||||
from optparse import OptionParser
|
||||
import sys,csv,re
|
||||
|
||||
def getSheet( file, sheetIndex ):
|
||||
doc = opendocument.load( file )
|
||||
try:
|
||||
spreadsheet = doc.spreadsheet
|
||||
except NameError:
|
||||
sys.stderr.write("Error: file is not a spreadsheet\n")
|
||||
return (None, None)
|
||||
|
||||
sheets = spreadsheet.getElementsByType( Table )
|
||||
if sheetIndex > len( sheets ):
|
||||
sys.stderr.write( "Error: spreadsheet has only %d sheets; requested invalid sheet %d\n" % (len( sheets ), sheetIndex + 1) )
|
||||
return (None, None)
|
||||
|
||||
sheet = sheets[sheetIndex]
|
||||
return (doc, sheet)
|
||||
|
||||
def displayCells( file, sheetIndex, rowIndex, colIndex, rowCount, colCount ):
|
||||
(doc, sheet) = getSheet( file, sheetIndex )
|
||||
if (doc == None or sheet == None):
|
||||
return 1
|
||||
|
||||
rows = sheet.getElementsByType( TableRow )
|
||||
if rowIndex + rowCount > len( rows ):
|
||||
sys.stderr.write( "Error: sheet has only %d rows; requested invalid row %d\n" % (len( rows ), rowIndex + rowCount) )
|
||||
return 1
|
||||
|
||||
csv_writer = csv.writer( sys.stdout )
|
||||
for i in range( rowIndex, rowIndex + rowCount ):
|
||||
row = rows[ i ]
|
||||
cells = row.getElementsByType( TableCell )
|
||||
if colIndex + colCount > len( cells ):
|
||||
sys.stderr.write( "Error: row has only %d cells; requested invalid column %d\n" % (len( cells ), colIndex + colCount) )
|
||||
return 1
|
||||
for j in range( colIndex, colIndex + colCount ):
|
||||
cells[ j ] = unicode( cells[ j ] )
|
||||
csv_writer.writerow( cells[ colIndex : colIndex + colCount ] )
|
||||
return 0
|
||||
|
||||
def updateCells( file, sheetIndex, rowIndex, colIndex, rowCount, colCount ):
|
||||
(doc, sheet) = getSheet( file, sheetIndex )
|
||||
if (doc == None or sheet == None):
|
||||
return 1
|
||||
|
||||
data = sys.stdin.readlines()
|
||||
if rowCount < 0:
|
||||
rowCount = len( data )
|
||||
elif len( data ) < rowCount:
|
||||
sys.stderr.write( "Error: not enough rows in input\n" )
|
||||
return 1
|
||||
|
||||
# add table rows as necessary
|
||||
rows = sheet.getElementsByType( TableRow )
|
||||
if rowIndex + rowCount > len( rows ):
|
||||
for i in range( rowIndex + rowCount - len( rows ) ):
|
||||
sheet.addElement( TableRow() )
|
||||
rows = sheet.getElementsByType( TableRow )
|
||||
|
||||
csv_reader = csv.reader( data )
|
||||
for i in range( rowIndex, rowIndex + rowCount ):
|
||||
row = rows[ i ]
|
||||
dataRow = csv_reader.next()
|
||||
rowColCount = colCount
|
||||
if rowColCount < 0:
|
||||
rowColCount = len( dataRow )
|
||||
elif len( dataRow ) < rowColCount:
|
||||
sys.stderr.write( "Error: not enough columns in input on row %d\n" % (rowIndex - i + 1) )
|
||||
return 1
|
||||
|
||||
cells = row.getElementsByType( TableCell )
|
||||
if colIndex > len( cells ):
|
||||
for j in range( len( cells ), colIndex ):
|
||||
row.addElement( TableCell() )
|
||||
cells = row.getElementsByType( TableCell )
|
||||
|
||||
for j in range( colIndex, colIndex + rowColCount ):
|
||||
if j < len( cells ):
|
||||
row.insertBefore( TableCell(), cells[ j ].nextSibling );
|
||||
row.removeChild( cells[ j ] )
|
||||
else:
|
||||
row.addElement( TableCell() )
|
||||
|
||||
cells = row.getElementsByType( TableCell )
|
||||
value = dataRow[ j - colIndex ]
|
||||
if re.match( r'^[-]?\d+(\.\d+)?$', value.strip() ):
|
||||
cells[ j ].setAttribute( 'valuetype', 'float' )
|
||||
cells[ j ].setAttribute( 'value', value )
|
||||
else:
|
||||
cells[ j ].setAttribute( 'valuetype', 'string' )
|
||||
cells[ j ].addElement( P( text = dataRow[ j - colIndex ] ) )
|
||||
|
||||
doc.save( file )
|
||||
return 0
|
||||
|
||||
def parseCell( cell ):
|
||||
cellmatch = re.match( r'^([A-Z]+)([0-9]+)$', cell )
|
||||
if cellmatch == None:
|
||||
sys.stderr.write( "Error: the cell specified was not in the required format of <column><row> (e.g. A1)" )
|
||||
exit( 1 )
|
||||
|
||||
cellcol = cellmatch.group( 1 )
|
||||
colIndex = 0
|
||||
for i in range( len( cellcol ) ):
|
||||
colIndex = (colIndex * 26) + (ord( cellcol[i] ) - ord( 'A' ) + 1)
|
||||
colIndex = colIndex - 1
|
||||
|
||||
rowIndex = int( cellmatch.group( 2 ) ) - 1
|
||||
|
||||
return (colIndex, rowIndex)
|
||||
|
||||
def getCount( value, write, label ):
|
||||
if value == None:
|
||||
if write:
|
||||
return -1
|
||||
else:
|
||||
return 1
|
||||
|
||||
value = int( value )
|
||||
if value <= 0:
|
||||
sys.stderr.write( "Error: illegal value specified for %s\n" % label )
|
||||
exit( 1 )
|
||||
return value
|
||||
|
||||
if __name__ == "__main__":
|
||||
usage = "%prog file.ods cell"
|
||||
parser = OptionParser( usage=usage, version="%prog 0.1" )
|
||||
parser.add_option( '-r', '--rows', action='store', dest='rows', help=
|
||||
'''Specify the height of the block of cells, in rows. Must be greater than zero. Defaults to 1 when
|
||||
the -w option is not present. Defaults to the number of input rows when the -w option is present.''', default=None )
|
||||
parser.add_option( '-c', '--cols', action='store', dest='cols', help=
|
||||
'''Specify the width of the block of cells, in columns. Must be greater than zero. Defaults to 1 when
|
||||
the -w option is not present. Defaults to the number of input columns when the -w option is present.''', default=None )
|
||||
parser.add_option( '-s', '--sheet', action='store', dest='sheet', help='The sheet in the ODS file to read/modify. Must be greater than zero; defaults to 1.', default=1 )
|
||||
parser.add_option( '-w', '--write', action='store_true', dest='write', help=
|
||||
'''If specified, the spreadsheet will be modified with data from standard input. If not specified,
|
||||
the cells from the spreadsheet will be written to standard output.''' )
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if len( args ) != 2:
|
||||
parser.print_help()
|
||||
exit( 1 )
|
||||
|
||||
file = args[0]
|
||||
(colIndex, rowIndex) = parseCell( args[1] )
|
||||
|
||||
rowCount = getCount( options.rows, options.write, 'rows' )
|
||||
colCount = getCount( options.cols, options.write, 'cols' )
|
||||
sheet = int( options.sheet ) - 1
|
||||
|
||||
if sheet < 0:
|
||||
sys.stderr.write( "Error: illegal value specified for sheet\n" )
|
||||
exit( 1 )
|
||||
|
||||
if options.write:
|
||||
exit( updateCells( file, sheet, rowIndex, colIndex, rowCount, colCount ) )
|
||||
else:
|
||||
exit( displayCells( file, sheet, rowIndex, colIndex, rowCount, colCount ) )
|
|
@ -0,0 +1,98 @@
|
|||
'\" t
|
||||
.\" Title: odscell
|
||||
.\" Author: Kartikaya Gupta
|
||||
.\" Generator: DocBook XSL Stylesheets v1.76.0 <http://docbook.sf.net/>
|
||||
.\" Date: 12/22/2010
|
||||
.\" Manual: User commands
|
||||
.\" Source: odfpy
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "ODSCELL" "1" "12/22/2010" "odfpy" "User commands"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" http://bugs.debian.org/507673
|
||||
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "NAME"
|
||||
odscell \- Read and update blocks of cells in OpenDocument spreadsheets files
|
||||
.SH "SYNOPSIS"
|
||||
.HP \w'\fBodscell\fR\ 'u
|
||||
\fBodscell\fR \fIfile\&.ods\fR \fIcell\fR
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
This program reads a cell or block of cells from a file in ODS format, and prints it out in a CSV format to standard output\&. Alternatively, if the \-w flag is set, the program reads in a CSV\-formatted block of cells from standard input, and overwites a cell or block of cells in a file in ODS format\&.
|
||||
.SH "OPTIONS"
|
||||
.PP
|
||||
\-\-version
|
||||
.RS 4
|
||||
Display the version and exit\&.
|
||||
.RE
|
||||
.PP
|
||||
\-h, \-\-help
|
||||
.RS 4
|
||||
Display command usage\&.
|
||||
.RE
|
||||
.PP
|
||||
\-r \fIROWS\fR, \-\-rows=\fIROWS\fR
|
||||
.RS 4
|
||||
Specify the height of the block of cells, in rows\&. Must be greater than zero\&. Defaults to 1 when the \-w option is not present\&. Defaults to the number of input rows when the \-w option is present\&.
|
||||
.RE
|
||||
.PP
|
||||
\-c \fICOLS\fR, \-\-cols=\fICOLS\fR
|
||||
.RS 4
|
||||
Specify the width of the block of cells, in columns\&. Must be greater than zero\&. Defaults to 1 when the \-w option is not present\&. Defaults to the number of input columns when the \-w option is present\&.
|
||||
.RE
|
||||
.PP
|
||||
\-s \fISHEET\fR, \-\-sheet=\fISHEET\fR
|
||||
.RS 4
|
||||
The sheet in the ODS file to read/modify\&. Must be greater than zero; defaults to 1\&.
|
||||
.RE
|
||||
.PP
|
||||
\-w
|
||||
.RS 4
|
||||
If specified, the spreadsheet will be modified with data from standard input\&. If not specified, the cells from the spreadsheet will be written to standard output\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIfile\&.ods\fR
|
||||
.RS 4
|
||||
The ODS file to be read from or modified\&.
|
||||
.RE
|
||||
.PP
|
||||
\fIcell\fR
|
||||
.RS 4
|
||||
The top\-left cell of the block of cells to be read from or modified\&. This should be specified in normal spreadsheet format, e\&.g\&. "A1" or "BA23"\&.
|
||||
.RE
|
||||
.SH "EXAMPLE"
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.nf
|
||||
odscell foo\&.ods A4 # display value in cell A4 on sheet 1 of foo\&.ods
|
||||
odscell \-r 2 \-c 2 foo\&.ods B2 # display values for cells B2,B3,C2,C3 on sheet 1 of foo\&.ods
|
||||
echo "hello,world,garbage" | odscell \-c 2 \-w foo\&.ods A1 # write "hello" to cell A1 and "world" to cell A2 on sheet 1 of foo\&.ods
|
||||
cat bar\&.csv | odscell \-s 2 \-w foo\&.ods A1 # put the CSV data from bar\&.csv into sheet 2 of foo\&.ods
|
||||
.fi
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.SH "AUTHOR"
|
||||
.PP
|
||||
\fBKartikaya Gupta\fR
|
||||
.RS 4
|
||||
Original author of odscell
|
||||
.RE
|
|
@ -0,0 +1,117 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<refentry id="odscell">
|
||||
<refentryinfo>
|
||||
<productname>odfpy</productname>
|
||||
<author><firstname>Kartikaya</firstname><surname>Gupta</surname>
|
||||
<contrib>Original author of odscell</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>odscell</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">User commands</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname>odscell</refname>
|
||||
<refpurpose>Read and update blocks of cells in OpenDocument spreadsheets files</refpurpose>
|
||||
</refnamediv>
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>odscell</command>
|
||||
<arg choice="plain"><replaceable>file.ods</replaceable></arg>
|
||||
<arg choice="plain"><replaceable>cell</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
This program reads a cell or block of cells from a file in ODS format, and prints it out
|
||||
in a CSV format to standard output. Alternatively, if the -w flag is set, the program reads
|
||||
in a CSV-formatted block of cells from standard input, and overwites a cell or block of cells
|
||||
in a file in ODS format.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>--version</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Display the version and exit.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-h, --help</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Display command usage.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-r <replaceable>ROWS</replaceable>, --rows=<replaceable>ROWS</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify the height of the block of cells, in rows. Must be greater than zero. Defaults to 1 when
|
||||
the -w option is not present. Defaults to the number of input rows when the -w option is present.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-c <replaceable>COLS</replaceable>, --cols=<replaceable>COLS</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specify the width of the block of cells, in columns. Must be greater than zero. Defaults to 1 when
|
||||
the -w option is not present. Defaults to the number of input columns when the -w option is present.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-s <replaceable>SHEET</replaceable>, --sheet=<replaceable>SHEET</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The sheet in the ODS file to read/modify. Must be greater than zero; defaults to 1.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-w</term>
|
||||
<listitem>
|
||||
<para>
|
||||
If specified, the spreadsheet will be modified with data from standard input. If not specified,
|
||||
the cells from the spreadsheet will be written to standard output.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><replaceable>file.ods</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The ODS file to be read from or modified.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><replaceable>cell</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The top-left cell of the block of cells to be read from or modified. This should be specified
|
||||
in normal spreadsheet format, e.g. "A1" or "BA23".
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Example</title>
|
||||
<screen>
|
||||
odscell foo.ods A4 # display value in cell A4 on sheet 1 of foo.ods
|
||||
odscell -r 2 -c 2 foo.ods B2 # display values for cells B2,B3,C2,C3 on sheet 1 of foo.ods
|
||||
echo "hello,world,garbage" | odscell -c 2 -w foo.ods A1 # write "hello" to cell A1 and "world" to cell A2 on sheet 1 of foo.ods
|
||||
cat bar.csv | odscell -s 2 -w foo.ods A1 # put the CSV data from bar.csv into sheet 2 of foo.ods
|
||||
</screen>
|
||||
</refsect1>
|
||||
</refentry>
|
|
@ -0,0 +1,15 @@
|
|||
all: odf odt2tracwiki.1
|
||||
|
||||
txt: odt2tracwiki.txt
|
||||
|
||||
%.1: %.docbook
|
||||
xmlto man $<
|
||||
|
||||
%.txt: %.docbook
|
||||
xmlto txt $<
|
||||
|
||||
clean:
|
||||
rm -f *.txt odf
|
||||
|
||||
odf:
|
||||
ln -s ../../odf
|
|
@ -0,0 +1,57 @@
|
|||
'\" t
|
||||
.\" Title: odt2tracwiki
|
||||
.\" Author: S\(/oren Roug
|
||||
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
|
||||
.\" Date: 01/09/2013
|
||||
.\" Manual: User commands
|
||||
.\" Source: odfpy
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "ODT2TRACWIKI" "1" "01/09/2013" "odfpy" "User commands"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" http://bugs.debian.org/507673
|
||||
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "NAME"
|
||||
odt2tracwiki \- Convert ODF to Trac Wiki format
|
||||
.SH "SYNOPSIS"
|
||||
.HP \w'\fBodt2tracwiki\fR\ 'u
|
||||
\fBodt2tracwiki\fR \fIpath\fR
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
\fBodt2tracwiki\fR
|
||||
is a program that will create a Trac Wiki format\&. See http://trac\&.edgewall\&.org/\&. I expect to add a feature that will upload the page with images to a Trac Wiki page using XML\-RPC\&. http://trac\-hacks\&.org/wiki/XmlRpcPlugin
|
||||
.PP
|
||||
"Path" is assumed to be an OpenDocument file of text, spreadsheet or presentation type\&.
|
||||
.SH "EXAMPLE"
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.nf
|
||||
odt2tracwiki odf\-file
|
||||
.fi
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.SH "AUTHOR"
|
||||
.PP
|
||||
\fBS\(/oren Roug\fR
|
||||
.RS 4
|
||||
Original author
|
||||
.RE
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<refentry id="odt2tracwiki">
|
||||
<refentryinfo>
|
||||
<productname>odfpy</productname>
|
||||
<author><firstname>Søren</firstname><surname>Roug</surname>
|
||||
<contrib>Original author</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>odt2tracwiki</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">User commands</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname>odt2tracwiki</refname>
|
||||
<refpurpose>Convert ODF to Trac Wiki format</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>odt2tracwiki</command>
|
||||
<arg choice="plain"><replaceable>path</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para><command>odt2tracwiki</command> is a program that will create
|
||||
a Trac Wiki format.
|
||||
See http://trac.edgewall.org/.
|
||||
I expect to add a feature that will upload the page with images to a Trac Wiki page
|
||||
using XML-RPC. http://trac-hacks.org/wiki/XmlRpcPlugin
|
||||
</para>
|
||||
<para>
|
||||
"Path" is assumed to be an
|
||||
OpenDocument file of text, spreadsheet or presentation type.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1><title>Example</title>
|
||||
<screen>
|
||||
odt2tracwiki odf-file
|
||||
</screen>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
import sys
|
||||
from odf.odf2moinmoin import ODF2MoinMoin
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
odt = ODF2MoinMoin(sys.argv[1])
|
||||
out_utf8 = odt.toString().encode("utf-8")
|
||||
sys.stdout.write(out_utf8)
|
|
@ -0,0 +1,15 @@
|
|||
all: odf odf2zwikimoin.1
|
||||
|
||||
txt: odf2zwikimoin.txt
|
||||
|
||||
%.1: %.docbook
|
||||
xmlto man $<
|
||||
|
||||
%.txt: %.docbook
|
||||
xmlto txt $<
|
||||
|
||||
clean:
|
||||
rm -f *.txt odf
|
||||
|
||||
odf:
|
||||
ln -s ../../odf
|
|
@ -0,0 +1,51 @@
|
|||
'\" t
|
||||
.\" Title: odf2zwikimoin
|
||||
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.76.1 <http://docbook.sf.net/>
|
||||
.\" Date: 01/09/2013
|
||||
.\" Manual: [FIXME: manual]
|
||||
.\" Source: [FIXME: source]
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "ODF2ZWIKIMOIN" "1" "01/09/2013" "[FIXME: source]" "[FIXME: manual]"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" http://bugs.debian.org/507673
|
||||
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "NAME"
|
||||
odf2zwikimoin \- Convert ODF to ZWiki MoinMoin format
|
||||
.SH "SYNOPSIS"
|
||||
.HP \w'\fBodf2zwikimoin\fR\ 'u
|
||||
\fBodf2zwikimoin\fR \fIpath\fR
|
||||
.SH "DESCRIPTION"
|
||||
.PP
|
||||
\fBodf2zwikimoin\fR
|
||||
is a program that will create a ZWiki MoinMoin format\&. See http://zwiki\&.org/\&.
|
||||
.PP
|
||||
"Path" is assumed to be an OpenDocument file of text, spreadsheet or presentation type\&.
|
||||
.SH "EXAMPLE"
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.nf
|
||||
odf2zwikimoin odf\-file
|
||||
.fi
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" ?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<refentry id="odf2zwikimoin">
|
||||
<refnamediv>
|
||||
<refname>odf2zwikimoin</refname>
|
||||
<refpurpose>Convert ODF to ZWiki MoinMoin format</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>odf2zwikimoin</command>
|
||||
<arg choice="plain"><replaceable>path</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1><title>Description</title>
|
||||
<para><command>odf2zwikimoin</command> is a program that will create
|
||||
a ZWiki MoinMoin format.
|
||||
See http://zwiki.org/.
|
||||
</para>
|
||||
<para>
|
||||
"Path" is assumed to be an
|
||||
OpenDocument file of text, spreadsheet or presentation type.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1><title>Example</title>
|
||||
<screen>
|
||||
odf2zwikimoin odf-file
|
||||
</screen>
|
||||
</refsect1>
|
||||
</refentry>
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
import sys
|
||||
from odf.odf2moinmoin import ODF2MoinMoin
|
||||
|
||||
class ODF2ZWikiMoin(ODF2MoinMoin):
|
||||
|
||||
def __init__(self, filepath):
|
||||
super(ODF2ZWikiMoin, self).__init__(filepath)
|
||||
self.baseURL = "BaseURL"
|
||||
|
||||
def draw_image(self, node):
|
||||
"""
|
||||
"""
|
||||
link = node.getAttribute("xlink:href")
|
||||
if link and link[:2] == './': # Indicates a sub-object, which isn't supported
|
||||
return "%s\n" % link
|
||||
if link and link[:9] == 'Pictures/':
|
||||
link = self.baseURL + "/" + link[9:]
|
||||
return "%s\n" % link
|
||||
|
||||
def text_line_break(self, node):
|
||||
return "\n"
|
||||
|
||||
if __name__ == "__main__":
|
||||
odt = ODF2ZWikiMoin(sys.argv[1])
|
||||
out_utf8 = odt.toString().encode("utf-8")
|
||||
sys.stdout.write(out_utf8)
|
|
@ -0,0 +1,533 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
|
||||
"""
|
||||
import pdb; pdb.set_trace()
|
||||
odt2moinmoin
|
||||
=======
|
||||
|
||||
odt2moinmoin converts files in Open Document Text format (ODT) into
|
||||
ZWiki MoinMoin-formatted plain text.
|
||||
|
||||
Written by by [Yuri Takhteyev](http://www.freewisdom.org).
|
||||
|
||||
Project website: http://www.freewisdom.org/projects/odt2txt/
|
||||
Contact: yuri [at] freewisdom.org
|
||||
|
||||
License: GPL 2 (http://www.gnu.org/copyleft/gpl.html) or BSD
|
||||
|
||||
Version: 0.1 (April 7, 2006)
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
||||
import sys, zipfile, xml.dom.minidom
|
||||
from odf.namespaces import nsdict
|
||||
from odf.elementtypes import *
|
||||
|
||||
IGNORED_TAGS = [
|
||||
'draw:a'
|
||||
'draw:g',
|
||||
'draw:line',
|
||||
'draw:object-ole',
|
||||
'office:annotation',
|
||||
'svg:desc',
|
||||
] + [ nsdict[item[0]]+":"+item[1] for item in empty_elements]
|
||||
|
||||
INLINE_TAGS = [ nsdict[item[0]]+":"+item[1] for item in inline_elements]
|
||||
|
||||
FOOTNOTE_STYLES = ["Footnote"]
|
||||
|
||||
|
||||
class TextProps:
|
||||
""" Holds properties for a text style. """
|
||||
|
||||
def __init__ (self):
|
||||
|
||||
self.italic = False
|
||||
self.bold = False
|
||||
self.fixed = False
|
||||
self.underlined = False
|
||||
|
||||
def setItalic (self, value):
|
||||
if value == "italic":
|
||||
self.italic = True
|
||||
|
||||
def setBold (self, value):
|
||||
if value == "bold":
|
||||
self.bold = True
|
||||
|
||||
def setFixed (self, value):
|
||||
self.fixed = value
|
||||
|
||||
def __str__ (self):
|
||||
|
||||
return "[i=%s, h=i%s, fixed=%s]" % (str(self.italic),
|
||||
str(self.bold),
|
||||
str(self.fixed))
|
||||
|
||||
class ParagraphProps:
|
||||
""" Holds properties of a paragraph style. """
|
||||
|
||||
def __init__ (self):
|
||||
|
||||
self.blockquote = False
|
||||
self.headingLevel = 0
|
||||
self.code = False
|
||||
self.title = False
|
||||
self.indented = 0
|
||||
|
||||
def setIndented (self, value):
|
||||
self.indented = value
|
||||
|
||||
def setHeading (self, level):
|
||||
self.headingLevel = level
|
||||
|
||||
def setTitle (self, value):
|
||||
self.title = value
|
||||
|
||||
def setCode (self, value):
|
||||
self.code = value
|
||||
|
||||
|
||||
def __str__ (self):
|
||||
|
||||
return "[bq=%s, h=%d, code=%s]" % (str(self.blockquote),
|
||||
self.headingLevel,
|
||||
str(self.code))
|
||||
|
||||
|
||||
class ListProperties:
|
||||
""" Holds properties for a list style. """
|
||||
|
||||
def __init__ (self):
|
||||
self.ordered = False
|
||||
|
||||
def setOrdered (self, value):
|
||||
self.ordered = value
|
||||
|
||||
|
||||
|
||||
class OpenDocumentTextFile:
|
||||
|
||||
|
||||
def __init__ (self, filepath):
|
||||
self.footnotes = []
|
||||
self.footnoteCounter = 0
|
||||
self.textStyles = {"Standard": TextProps()}
|
||||
self.paragraphStyles = {"Standard": ParagraphProps()}
|
||||
self.listStyles = {}
|
||||
self.fixedFonts = []
|
||||
self.hasTitle = 0
|
||||
self.baseURL = "BaseURL"
|
||||
|
||||
self.load(filepath)
|
||||
|
||||
|
||||
def processFontDeclarations (self, fontDecl):
|
||||
""" Extracts necessary font information from a font-declaration
|
||||
element.
|
||||
"""
|
||||
for fontFace in fontDecl.getElementsByTagName("style:font-face"):
|
||||
if fontFace.getAttribute("style:font-pitch") == "fixed":
|
||||
self.fixedFonts.append(fontFace.getAttribute("style:name"))
|
||||
|
||||
|
||||
|
||||
def extractTextProperties (self, style, parent=None):
|
||||
""" Extracts text properties from a style element. """
|
||||
|
||||
textProps = TextProps()
|
||||
|
||||
if parent:
|
||||
parentProp = self.textStyles.get(parent, None)
|
||||
if parentProp:
|
||||
textProp = parentProp
|
||||
|
||||
textPropEl = style.getElementsByTagName("style:text-properties")
|
||||
if not textPropEl: return textProps
|
||||
|
||||
textPropEl = textPropEl[0]
|
||||
|
||||
italic = textPropEl.getAttribute("fo:font-style")
|
||||
bold = textPropEl.getAttribute("fo:font-weight")
|
||||
|
||||
textProps.setItalic(italic)
|
||||
textProps.setBold(bold)
|
||||
|
||||
if textPropEl.getAttribute("style:font-name") in self.fixedFonts:
|
||||
textProps.setFixed(True)
|
||||
|
||||
return textProps
|
||||
|
||||
def extractParagraphProperties (self, style, parent=None):
|
||||
""" Extracts paragraph properties from a style element. """
|
||||
|
||||
paraProps = ParagraphProps()
|
||||
|
||||
name = style.getAttribute("style:name")
|
||||
|
||||
if name.startswith("Heading_20_"):
|
||||
level = name[11:]
|
||||
try:
|
||||
level = int(level)
|
||||
paraProps.setHeading(level)
|
||||
except:
|
||||
level = 0
|
||||
|
||||
if name == "Title":
|
||||
paraProps.setTitle(True)
|
||||
|
||||
paraPropEl = style.getElementsByTagName("style:paragraph-properties")
|
||||
if paraPropEl:
|
||||
paraPropEl = paraPropEl[0]
|
||||
leftMargin = paraPropEl.getAttribute("fo:margin-left")
|
||||
if leftMargin:
|
||||
try:
|
||||
leftMargin = float(leftMargin[:-2])
|
||||
if leftMargin > 0.01:
|
||||
paraProps.setIndented(True)
|
||||
except:
|
||||
pass
|
||||
|
||||
textProps = self.extractTextProperties(style)
|
||||
if textProps.fixed:
|
||||
paraProps.setCode(True)
|
||||
|
||||
return paraProps
|
||||
|
||||
|
||||
def processStyles(self, styleElements):
|
||||
""" Runs through "style" elements extracting necessary information.
|
||||
"""
|
||||
|
||||
for style in styleElements:
|
||||
|
||||
name = style.getAttribute("style:name")
|
||||
|
||||
if name == "Standard": continue
|
||||
|
||||
family = style.getAttribute("style:family")
|
||||
parent = style.getAttribute("style:parent-style-name")
|
||||
|
||||
if family == "text":
|
||||
self.textStyles[name] = self.extractTextProperties(style,
|
||||
parent)
|
||||
|
||||
elif family == "paragraph":
|
||||
self.paragraphStyles[name] = (
|
||||
self.extractParagraphProperties(style,
|
||||
parent))
|
||||
def processListStyles (self, listStyleElements):
|
||||
|
||||
for style in listStyleElements:
|
||||
name = style.getAttribute("style:name")
|
||||
|
||||
prop = ListProperties()
|
||||
if style.childNodes:
|
||||
if ( style.childNodes[0].tagName
|
||||
== "text:list-level-style-number" ):
|
||||
prop.setOrdered(True)
|
||||
|
||||
self.listStyles[name] = prop
|
||||
|
||||
|
||||
def load(self, filepath):
|
||||
""" Loads an ODT file. """
|
||||
|
||||
zip = zipfile.ZipFile(filepath)
|
||||
|
||||
styles_doc = xml.dom.minidom.parseString(zip.read("styles.xml"))
|
||||
self.processFontDeclarations(styles_doc.getElementsByTagName(
|
||||
"office:font-face-decls")[0])
|
||||
self.processStyles(styles_doc.getElementsByTagName("style:style"))
|
||||
self.processListStyles(styles_doc.getElementsByTagName(
|
||||
"text:list-style"))
|
||||
|
||||
self.content = xml.dom.minidom.parseString(zip.read("content.xml"))
|
||||
self.processFontDeclarations(self.content.getElementsByTagName(
|
||||
"office:font-face-decls")[0])
|
||||
self.processStyles(self.content.getElementsByTagName("style:style"))
|
||||
self.processListStyles(self.content.getElementsByTagName(
|
||||
"text:list-style"))
|
||||
|
||||
def compressCodeBlocks(self, text):
|
||||
""" Removes extra blank lines from code blocks. """
|
||||
|
||||
lines = text.split("\n")
|
||||
buffer = []
|
||||
numLines = len(lines)
|
||||
for i in range(numLines):
|
||||
|
||||
if (lines[i].strip() or i == numLines-1 or i == 0 or
|
||||
not ( lines[i-1].startswith(" ")
|
||||
and lines[i+1].startswith(" ") ) ):
|
||||
buffer.append("\n" + lines[i])
|
||||
|
||||
return ''.join(buffer)
|
||||
|
||||
|
||||
def listToString (self, listElement, indent = 0):
|
||||
|
||||
buffer = []
|
||||
|
||||
styleName = listElement.getAttribute("text:style-name")
|
||||
props = self.listStyles.get(styleName, ListProperties())
|
||||
|
||||
i = 0
|
||||
for item in listElement.childNodes:
|
||||
buffer.append(" "*indent)
|
||||
i += 1
|
||||
if props.ordered:
|
||||
number = str(i)
|
||||
number = " " + number + ". "
|
||||
buffer.append(" 1. ")
|
||||
else:
|
||||
buffer.append(" * ")
|
||||
subitems = [el for el in item.childNodes
|
||||
if el.tagName in ["text:p", "text:h", "text:list"]]
|
||||
for subitem in subitems:
|
||||
if subitem.tagName == "text:list":
|
||||
buffer.append("\n")
|
||||
buffer.append(self.listToString(subitem, indent+3))
|
||||
else:
|
||||
buffer.append(self.paragraphToString(subitem, indent+3))
|
||||
buffer.append("\n")
|
||||
|
||||
return ''.join(buffer)
|
||||
|
||||
def tableToString (self, tableElement):
|
||||
""" MoinMoin used || to delimit table cells
|
||||
"""
|
||||
|
||||
buffer = []
|
||||
|
||||
for item in tableElement.childNodes:
|
||||
if item.tagName == "table:table-header-rows":
|
||||
buffer.append(self.tableToString(item))
|
||||
if item.tagName == "table:table-row":
|
||||
buffer.append("\n||")
|
||||
for cell in item.childNodes:
|
||||
buffer.append(self.paragraphToString(cell))
|
||||
buffer.append("||")
|
||||
return ''.join(buffer)
|
||||
|
||||
|
||||
def toString (self):
|
||||
""" Converts the document to a string. """
|
||||
body = self.content.getElementsByTagName("office:body")[0]
|
||||
text = body.childNodes[0]
|
||||
|
||||
buffer = []
|
||||
|
||||
paragraphs = [el for el in text.childNodes
|
||||
if el.tagName in ["text:p", "text:h","text:section",
|
||||
"text:list", "table:table"]]
|
||||
|
||||
for paragraph in paragraphs:
|
||||
if paragraph.tagName == "text:list":
|
||||
text = self.listToString(paragraph)
|
||||
elif paragraph.tagName == "text:section":
|
||||
text = self.textToString(paragraph)
|
||||
elif paragraph.tagName == "table:table":
|
||||
text = self.tableToString(paragraph)
|
||||
else:
|
||||
text = self.paragraphToString(paragraph)
|
||||
if text:
|
||||
buffer.append(text)
|
||||
|
||||
if self.footnotes:
|
||||
|
||||
buffer.append("----")
|
||||
for cite, body in self.footnotes:
|
||||
buffer.append("%s: %s" % (cite, body))
|
||||
|
||||
|
||||
buffer.append("")
|
||||
return self.compressCodeBlocks('\n\n'.join(buffer))
|
||||
|
||||
|
||||
def textToString(self, element):
|
||||
|
||||
buffer = []
|
||||
|
||||
for node in element.childNodes:
|
||||
|
||||
if node.nodeType == xml.dom.Node.TEXT_NODE:
|
||||
buffer.append(node.nodeValue)
|
||||
|
||||
elif node.nodeType == xml.dom.Node.ELEMENT_NODE:
|
||||
tag = node.tagName
|
||||
|
||||
if tag == "text:note":
|
||||
cite = (node.getElementsByTagName("text:note-citation")[0]
|
||||
.childNodes[0].nodeValue)
|
||||
|
||||
body = (node.getElementsByTagName("text:note-body")[0]
|
||||
.childNodes[0])
|
||||
|
||||
self.footnotes.append((cite, self.textToString(body)))
|
||||
|
||||
buffer.append("^%s^" % cite)
|
||||
|
||||
elif tag == "text:s":
|
||||
try:
|
||||
num = int(node.getAttribute("text:c"))
|
||||
buffer.append(" "*num)
|
||||
except:
|
||||
buffer.append(" ")
|
||||
|
||||
elif tag == "text:tab":
|
||||
buffer.append(" ")
|
||||
|
||||
|
||||
elif tag == "text:a":
|
||||
|
||||
text = self.textToString(node)
|
||||
link = node.getAttribute("xlink:href")
|
||||
if link.strip() == text.strip():
|
||||
buffer.append("[%s] " % link.strip())
|
||||
else:
|
||||
buffer.append("[%s %s] " % (link.strip(), text.strip()))
|
||||
|
||||
elif tag == "draw:image":
|
||||
link = node.getAttribute("xlink:href")
|
||||
if link and link[:2] == './': # Indicates a sub-object, which isn't supported
|
||||
continue
|
||||
if link and link[:9] == 'Pictures/':
|
||||
link = self.baseURL + "/" + link[9:]
|
||||
buffer.append("%s\n" % link)
|
||||
|
||||
elif tag == "text:line-break":
|
||||
buffer.append("\n")
|
||||
|
||||
elif tag in ("draw:text-box", "draw:frame"):
|
||||
text = self.textToString(node)
|
||||
buffer.append(text)
|
||||
|
||||
elif tag in ("text:p", "text:h"):
|
||||
text = self.paragraphToString(node)
|
||||
if text:
|
||||
buffer.append(text + "\n\n")
|
||||
|
||||
elif tag in IGNORED_TAGS:
|
||||
pass
|
||||
|
||||
elif tag in INLINE_TAGS:
|
||||
text = self.textToString(node)
|
||||
|
||||
if not text.strip():
|
||||
continue # don't apply styles to white space
|
||||
|
||||
styleName = node.getAttribute("text:style-name")
|
||||
style = self.textStyles.get(styleName, TextProps())
|
||||
|
||||
if style.fixed:
|
||||
buffer.append("`" + text + "`")
|
||||
continue
|
||||
|
||||
if style:
|
||||
if style.italic and style.bold:
|
||||
mark = "'''''"
|
||||
elif style.italic:
|
||||
mark = "''"
|
||||
elif style.bold:
|
||||
mark = "'''"
|
||||
else:
|
||||
mark = ""
|
||||
else:
|
||||
mark = "/" + styleName + "/"
|
||||
|
||||
buffer.append("%s%s%s " % (mark, text, mark))
|
||||
|
||||
|
||||
else:
|
||||
buffer.append(" {" + tag + "} ")
|
||||
|
||||
return ''.join(buffer)
|
||||
|
||||
def paragraphToString(self, paragraph, indent = 0):
|
||||
|
||||
dummyParaProps = ParagraphProps()
|
||||
|
||||
style_name = paragraph.getAttribute("text:style-name")
|
||||
paraProps = self.paragraphStyles.get(style_name, dummyParaProps)
|
||||
text = self.textToString(paragraph)
|
||||
|
||||
#print style_name
|
||||
|
||||
if paraProps and not paraProps.code:
|
||||
text = text.strip()
|
||||
|
||||
if paraProps.title:
|
||||
self.hasTitle = 1
|
||||
return "= " + text + " =\n"
|
||||
|
||||
outlinelevel = paragraph.getAttribute("text:outline-level")
|
||||
if outlinelevel:
|
||||
|
||||
level = int(outlinelevel)
|
||||
if self.hasTitle: level += 1
|
||||
|
||||
if level >= 1:
|
||||
return "\n" + "=" * level + " " + text + " " + "=" * level + "\n"
|
||||
|
||||
elif paraProps.code:
|
||||
return "{{{\n" + text + "\n}}}\n"
|
||||
|
||||
if paraProps.indented:
|
||||
return self.wrapParagraph(text, indent = indent, blockquote = True)
|
||||
|
||||
else:
|
||||
return self.wrapParagraph(text, indent = indent)
|
||||
|
||||
|
||||
def wrapParagraph(self, text, indent = 0, blockquote=False):
|
||||
|
||||
counter = 0
|
||||
buffer = []
|
||||
LIMIT = 50
|
||||
|
||||
if blockquote:
|
||||
buffer.append(" ")
|
||||
|
||||
return ''.join(buffer) + text
|
||||
for token in text.split():
|
||||
|
||||
if counter > LIMIT - indent:
|
||||
buffer.append("\n" + " "*indent)
|
||||
if blockquote:
|
||||
buffer.append(" ")
|
||||
counter = 0
|
||||
|
||||
buffer.append(token + " ")
|
||||
counter += len(token)
|
||||
|
||||
return ''.join(buffer)
|
||||
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
odt = OpenDocumentTextFile(sys.argv[1])
|
||||
unicode = odt.toString()
|
||||
out_utf8 = unicode.encode("utf-8")
|
||||
sys.stdout.write(out_utf8)
|
|
@ -0,0 +1,4 @@
|
|||
Example of script that extracts a table from an SQLite database and produces a spreadsheet.
|
||||
|
||||
Issues:
|
||||
Numbers in the table become strings in the spreadsheet.
|
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
import os, sys
|
||||
import sqlite
|
||||
from odf.opendocument import OpenDocumentSpreadsheet
|
||||
from odf.style import Style, TextProperties, ParagraphProperties, TableColumnProperties
|
||||
from odf.text import P
|
||||
from odf.table import Table, TableColumn, TableRow, TableCell
|
||||
|
||||
if len(sys.argv) != 3:
|
||||
print "Usage: sqlite-db table"
|
||||
sys.exit(2)
|
||||
|
||||
sqldb = sys.argv[1]
|
||||
sqltable = sys.argv[2]
|
||||
textdoc = OpenDocumentSpreadsheet()
|
||||
# Create a style for the table content. One we can modify
|
||||
# later in the word processor.
|
||||
tablecontents = Style(name="Table Contents", family="paragraph")
|
||||
tablecontents.addElement(ParagraphProperties(numberlines="false", linenumber="0"))
|
||||
#tablecontents.addElement(TextProperties(fontweight="bold"))
|
||||
textdoc.styles.addElement(tablecontents)
|
||||
|
||||
# Create automatic styles for the column widths.
|
||||
# We want two different widths, one in inches, the other one in metric.
|
||||
# ODF Standard section 15.9.1
|
||||
widthshort = Style(name="Wshort", family="table-column")
|
||||
widthshort.addElement(TableColumnProperties(columnwidth="1.7cm"))
|
||||
textdoc.automaticstyles.addElement(widthshort)
|
||||
|
||||
widthwide = Style(name="Wwide", family="table-column")
|
||||
widthwide.addElement(TableColumnProperties(columnwidth="1.5in"))
|
||||
textdoc.automaticstyles.addElement(widthwide)
|
||||
|
||||
# Start the table, and describe the columns
|
||||
table = Table(name=sqltable)
|
||||
#table.addElement(TableColumn(numbercolumnsrepeated=4,stylename=widthshort))
|
||||
#table.addElement(TableColumn(numbercolumnsrepeated=3,stylename=widthwide))
|
||||
|
||||
cx = sqlite.connect(sqldb)
|
||||
cu = cx.cursor()
|
||||
cu.execute("select * from %s" % sqltable)
|
||||
for row in cu.fetchall():
|
||||
tr = TableRow()
|
||||
table.addElement(tr)
|
||||
for val in row:
|
||||
tc = TableCell()
|
||||
tr.addElement(tc)
|
||||
if type(val) == type(''):
|
||||
textval = unicode(val,'utf-8')
|
||||
else:
|
||||
textval = str(val)
|
||||
p = P(stylename=tablecontents,text=textval)
|
||||
tc.addElement(p)
|
||||
|
||||
cx.close()
|
||||
|
||||
textdoc.spreadsheet.addElement(table)
|
||||
textdoc.save(sqltable, True)
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
all: odf syntaxhighlight.1
|
||||
|
||||
txt: syntaxhighlight.txt
|
||||
|
||||
%.1: %.docbook
|
||||
xmlto man $<
|
||||
|
||||
%.txt: %.docbook
|
||||
xmlto txt $<
|
||||
|
||||
clean:
|
||||
rm -f *.txt odf
|
||||
odf:
|
||||
ln -s ../../odf
|
|
@ -0,0 +1,220 @@
|
|||
.\" Title: syntaxhighlight
|
||||
.\" Author: S\(/oren Roug
|
||||
.\" Generator: DocBook XSL Stylesheets v1.74.0 <http://docbook.sf.net/>
|
||||
.\" Date: 03/08/2009
|
||||
.\" Manual: User commands
|
||||
.\" Source: odfpy
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "SYNTAXHIGHLIGHT" "1" "03/08/2009" "odfpy" "User commands"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * (re)Define some macros
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" toupper - uppercase a string (locale-aware)
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de toupper
|
||||
.tr aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
|
||||
\\$*
|
||||
.tr aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SH-xref - format a cross-reference to an SH section
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de SH-xref
|
||||
.ie n \{\
|
||||
.\}
|
||||
.toupper \\$*
|
||||
.el \{\
|
||||
\\$*
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SH - level-one heading that works better for non-TTY output
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de1 SH
|
||||
.\" put an extra blank line of space above the head in non-TTY output
|
||||
.if t \{\
|
||||
.sp 1
|
||||
.\}
|
||||
.sp \\n[PD]u
|
||||
.nr an-level 1
|
||||
.set-an-margin
|
||||
.nr an-prevailing-indent \\n[IN]
|
||||
.fi
|
||||
.in \\n[an-margin]u
|
||||
.ti 0
|
||||
.HTML-TAG ".NH \\n[an-level]"
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
.nr an-break-flag 1
|
||||
\." make the size of the head bigger
|
||||
.ps +3
|
||||
.ft B
|
||||
.ne (2v + 1u)
|
||||
.ie n \{\
|
||||
.\" if n (TTY output), use uppercase
|
||||
.toupper \\$*
|
||||
.\}
|
||||
.el \{\
|
||||
.nr an-break-flag 0
|
||||
.\" if not n (not TTY), use normal case (not uppercase)
|
||||
\\$1
|
||||
.in \\n[an-margin]u
|
||||
.ti 0
|
||||
.\" if not n (not TTY), put a border/line under subheading
|
||||
.sp -.6
|
||||
\l'\n(.lu'
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SS - level-two heading that works better for non-TTY output
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de1 SS
|
||||
.sp \\n[PD]u
|
||||
.nr an-level 1
|
||||
.set-an-margin
|
||||
.nr an-prevailing-indent \\n[IN]
|
||||
.fi
|
||||
.in \\n[IN]u
|
||||
.ti \\n[SN]u
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
.nr an-break-flag 1
|
||||
.ps \\n[PS-SS]u
|
||||
\." make the size of the head bigger
|
||||
.ps +2
|
||||
.ft B
|
||||
.ne (2v + 1u)
|
||||
.if \\n[.$] \&\\$*
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" BB/BE - put background/screen (filled box) around block of text
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de BB
|
||||
.if t \{\
|
||||
.sp -.5
|
||||
.br
|
||||
.in +2n
|
||||
.ll -2n
|
||||
.gcolor red
|
||||
.di BX
|
||||
.\}
|
||||
..
|
||||
.de EB
|
||||
.if t \{\
|
||||
.if "\\$2"adjust-for-leading-newline" \{\
|
||||
.sp -1
|
||||
.\}
|
||||
.br
|
||||
.di
|
||||
.in
|
||||
.ll
|
||||
.gcolor
|
||||
.nr BW \\n(.lu-\\n(.i
|
||||
.nr BH \\n(dn+.5v
|
||||
.ne \\n(BHu+.5v
|
||||
.ie "\\$2"adjust-for-leading-newline" \{\
|
||||
\M[\\$1]\h'1n'\v'+.5v'\D'P \\n(BWu 0 0 \\n(BHu -\\n(BWu 0 0 -\\n(BHu'\M[]
|
||||
.\}
|
||||
.el \{\
|
||||
\M[\\$1]\h'1n'\v'-.5v'\D'P \\n(BWu 0 0 \\n(BHu -\\n(BWu 0 0 -\\n(BHu'\M[]
|
||||
.\}
|
||||
.in 0
|
||||
.sp -.5v
|
||||
.nf
|
||||
.BX
|
||||
.in
|
||||
.sp .5v
|
||||
.fi
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" BM/EM - put colored marker in margin next to block of text
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de BM
|
||||
.if t \{\
|
||||
.br
|
||||
.ll -2n
|
||||
.gcolor red
|
||||
.di BX
|
||||
.\}
|
||||
..
|
||||
.de EM
|
||||
.if t \{\
|
||||
.br
|
||||
.di
|
||||
.ll
|
||||
.gcolor
|
||||
.nr BH \\n(dn
|
||||
.ne \\n(BHu
|
||||
\M[\\$1]\D'P -.75n 0 0 \\n(BHu -(\\n[.i]u - \\n(INu - .75n) 0 0 -\\n(BHu'\M[]
|
||||
.in 0
|
||||
.nf
|
||||
.BX
|
||||
.in
|
||||
.fi
|
||||
.\}
|
||||
..
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "Name"
|
||||
syntaxhighlight \- Create OpenDocument with syntax highlighted programming code
|
||||
.SH "Synopsis"
|
||||
.fam C
|
||||
.HP \w'\fBsyntaxhighlight\fR\ 'u
|
||||
\fBsyntaxhighlight\fR [\-e\ \fIencoding\fR] [\-l\ \fIlanguage\fR] [\fIinputfile\fR] [\fIoutputfile\fR]
|
||||
.fam
|
||||
.SH "Description"
|
||||
.PP
|
||||
The syntaxhighlight program will read a source code file, format it with syntax highlighting and write an OpenDocument text file\&.
|
||||
.SH "Options"
|
||||
.PP
|
||||
\-e \fIencoding\fR
|
||||
.RS 4
|
||||
Enter the encoding of the source file\&. Common encodings are: iso\-8859\-1, cp1252, ascii and utf\-8 (default)\&.
|
||||
.RE
|
||||
.PP
|
||||
\-l \fIlanguage\fR
|
||||
.RS 4
|
||||
Programming language of the input file\&. If not specified, it is guessed fron the file ending\&. Values can be: Python, HTML, C, C++ and PHP\&.
|
||||
.RE
|
||||
.SH "Example"
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.fam C
|
||||
.ps -1
|
||||
.nf
|
||||
.if t \{\
|
||||
.sp -1
|
||||
.\}
|
||||
.BB lightgray adjust-for-leading-newline
|
||||
.sp -1
|
||||
|
||||
syntaxhighlight \-e cp1252 \-l Python example\&.py example\&.odt
|
||||
.EB lightgray adjust-for-leading-newline
|
||||
.if t \{\
|
||||
.sp 1
|
||||
.\}
|
||||
.fi
|
||||
.fam
|
||||
.ps +1
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.SH "Author"
|
||||
.PP
|
||||
\fBS\(/oren Roug\fR
|
||||
.RS 4
|
||||
Original author
|
||||
.RE
|
|
@ -0,0 +1,72 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<refentry id="syntaxhighlight">
|
||||
<refentryinfo>
|
||||
<productname>odfpy</productname>
|
||||
<author>
|
||||
<firstname>Søren</firstname>
|
||||
<surname>Roug</surname>
|
||||
<contrib>Original author</contrib>
|
||||
</author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>syntaxhighlight</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">User commands</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname>syntaxhighlight</refname>
|
||||
<refpurpose>Create OpenDocument with syntax highlighted programming code</refpurpose>
|
||||
</refnamediv>
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>syntaxhighlight</command>
|
||||
<arg choice="opt">-e <replaceable>encoding</replaceable></arg>
|
||||
<arg choice="opt">-l <replaceable>language</replaceable></arg>
|
||||
<arg>
|
||||
<replaceable>inputfile</replaceable>
|
||||
</arg>
|
||||
<arg>
|
||||
<replaceable>outputfile</replaceable>
|
||||
</arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
The syntaxhighlight program will read a source code file,
|
||||
format it with syntax highlighting and write an OpenDocument text file.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>-e <replaceable>encoding</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Enter the encoding of the source file. Common encodings are: iso-8859-1,
|
||||
cp1252, ascii and utf-8 (default).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-l <replaceable>language</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Programming language of the input file. If not specified,
|
||||
it is guessed fron the file ending.
|
||||
Values can be:
|
||||
Python, HTML, C, C++ and PHP.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Example</title>
|
||||
<screen>
|
||||
syntaxhighlight -e cp1252 -l Python example.py example.odt
|
||||
</screen>
|
||||
</refsect1>
|
||||
</refentry>
|
|
@ -0,0 +1,508 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
#
|
||||
# Syntax Highlighting
|
||||
# Originally from Peter Clive Wilkinson (http://www.petersblog.org/node/763)
|
||||
#
|
||||
import os, sys, re, getopt
|
||||
from odf.opendocument import OpenDocumentText
|
||||
from odf.style import FontFace, Style, TextProperties, ParagraphProperties
|
||||
from odf.text import P, Span, S
|
||||
|
||||
class Highlight:
|
||||
"""
|
||||
Do syntax highlighting.
|
||||
"""
|
||||
|
||||
courierfont = FontFace(name="Courier", fontfamily="Courier",
|
||||
fontadornments="Normal", fontfamilygeneric="modern", fontpitch="fixed")
|
||||
|
||||
#--- Paragraph style --
|
||||
|
||||
programliststyle = Style(name="Program Listing", family="paragraph")
|
||||
programliststyle.addElement(ParagraphProperties(border="0.002cm solid #000000", margin="0cm", padding="0.2cm"))
|
||||
programliststyle.addElement(TextProperties(fontname="Courier", fontsize="9pt", language="none", country="none"))
|
||||
|
||||
#--- Text styles --
|
||||
puncstyle = Style(name="Highlighted Punctuation", family="text")
|
||||
puncstyle.addElement(TextProperties(fontweight="bold")) # Bold
|
||||
|
||||
numberstyle = Style(name="Highlighted Number", family="text")
|
||||
numberstyle.addElement(TextProperties(color="#ff0000")) # Red
|
||||
|
||||
keywordstyle = Style(name="Highlighted Keyword", family="text")
|
||||
keywordstyle.addElement(TextProperties(color="#b218b2", fontweight="bold")) # Blue, bold
|
||||
|
||||
variablestyle = Style(name="Highlighted Magic", family="text")
|
||||
variablestyle.addElement(TextProperties(color="#0000ff")) # Blue
|
||||
|
||||
tagstyle = Style(name="Highlighted Tag", family="text")
|
||||
tagstyle.addElement(TextProperties(color="#800000")) # Darkred
|
||||
|
||||
attrstyle = Style(name="Highlighted Tag", family="text")
|
||||
attrstyle.addElement(TextProperties(color="#008000", fontweight="bold")) # Dark green bold
|
||||
|
||||
stringstyle = Style(name="Highlighted String", family="text")
|
||||
stringstyle.addElement(TextProperties(color="#800000")) # Red
|
||||
|
||||
commentstyle = Style(name="Highlighted Comment", family="text")
|
||||
commentstyle.addElement(TextProperties(color="#0000ff", fontstyle="italic")) # Blue, Italic
|
||||
|
||||
preprocstyle = Style(name="Highlighted Preprocessing", family="text")
|
||||
preprocstyle.addElement(TextProperties(color="#ff00ff", fontstyle="italic")) # Magenta, Italic
|
||||
|
||||
def __init__(self, strMode):
|
||||
"""
|
||||
Initialise highlighter: strMode = language (PYTHON, C, CPP, PHP, HTML)
|
||||
"""
|
||||
|
||||
self.textdoc = OpenDocumentText()
|
||||
|
||||
self.textdoc.fontfacedecls.addElement(self.courierfont)
|
||||
|
||||
self.textdoc.styles.addElement(self.programliststyle)
|
||||
self.textdoc.styles.addElement(self.puncstyle)
|
||||
self.textdoc.styles.addElement(self.numberstyle)
|
||||
self.textdoc.styles.addElement(self.keywordstyle)
|
||||
self.textdoc.styles.addElement(self.variablestyle)
|
||||
self.textdoc.styles.addElement(self.tagstyle)
|
||||
self.textdoc.styles.addElement(self.attrstyle)
|
||||
self.textdoc.styles.addElement(self.stringstyle)
|
||||
self.textdoc.styles.addElement(self.commentstyle)
|
||||
self.textdoc.styles.addElement(self.preprocstyle)
|
||||
|
||||
self.strSpanStyle = None
|
||||
self.currPara = P(stylename=self.programliststyle)
|
||||
self.textdoc.text.addElement(self.currPara)
|
||||
self.currSpan = None
|
||||
if strMode == 'CPP':
|
||||
strMode = 'C'
|
||||
self.strSuppressTokens = []
|
||||
elif strMode == 'C':
|
||||
self.strSuppressTokens = ['CPPKEYWORD']
|
||||
else:
|
||||
self.strSuppressTokens = []
|
||||
|
||||
self.strMode = strMode
|
||||
|
||||
def PythonHighlightToken(self, strTok, oMatch, strStyle):
|
||||
"""
|
||||
Callback for python specific highlighting.
|
||||
"""
|
||||
#
|
||||
# Input matches this type.
|
||||
#
|
||||
strValue = oMatch.group()
|
||||
|
||||
if strTok == 'MULTILINESTRING':
|
||||
#
|
||||
# If not inside a multiline string then start one now.
|
||||
#
|
||||
self.ChangeStyle(strStyle)
|
||||
self.WriteContent(strValue)
|
||||
#
|
||||
# Remember you are in a string and remember how it was
|
||||
# started (""" vs ''')
|
||||
#
|
||||
self.strMultilineString = oMatch.group(1)
|
||||
return 'PythonMultilineString'
|
||||
|
||||
elif strTok == 'ENDMULTILINESTRING':
|
||||
#
|
||||
# Multiline Token found within a multiline string
|
||||
#
|
||||
if oMatch.group(1) == self.strMultilineString:
|
||||
#
|
||||
# Token is end of multiline so stop here.
|
||||
#
|
||||
self.WriteMultiline(strValue)
|
||||
self.strMultilineString = ''
|
||||
return 'PYTHON'
|
||||
|
||||
self.ChangeStyle(strStyle)
|
||||
self.WriteContent(strValue)
|
||||
|
||||
def CHighlightToken(self, strTok, oMatch, strStyle):
|
||||
"""
|
||||
Callback for C specific highlighting.
|
||||
"""
|
||||
#
|
||||
# Input matches this type.
|
||||
#
|
||||
strValue = oMatch.group()
|
||||
|
||||
#
|
||||
# Not in multiline mode so change display style as appropriate
|
||||
# and output the text.
|
||||
#
|
||||
self.ChangeStyle(strStyle)
|
||||
self.WriteContent(strValue)
|
||||
|
||||
def PHPHighlightToken(self, strTok, oMatch, strStyle):
|
||||
"""
|
||||
Callback for PHP specific highlighting.
|
||||
"""
|
||||
#
|
||||
# Input matches this type.
|
||||
#
|
||||
strValue = oMatch.group()
|
||||
|
||||
if strTok == 'MULTILINESTRING':
|
||||
#
|
||||
# If not inside a multiline string then start one now.
|
||||
#
|
||||
self.ChangeStyle(strStyle)
|
||||
self.WriteContent(strValue)
|
||||
#
|
||||
# Remember you are in a string and remember how it was
|
||||
# started (""" vs ''')
|
||||
#
|
||||
self.strMultilineString = oMatch.group(1)
|
||||
return 'PHPMultilineString'
|
||||
|
||||
elif strTok == 'ENDMULTILINESTRING':
|
||||
#
|
||||
# Multiline Token found within a multiline string
|
||||
#
|
||||
if oMatch.group(1) == self.strMultilineString:
|
||||
#
|
||||
# Token is end of multiline so stop here.
|
||||
#
|
||||
self.WriteMultiline(strValue)
|
||||
self.strMultilineString = ''
|
||||
return 'PHP'
|
||||
|
||||
self.ChangeStyle(strStyle)
|
||||
self.WriteContent(strValue)
|
||||
|
||||
if strTok == 'GOTOHTML':
|
||||
#
|
||||
# Embedded HTML
|
||||
#
|
||||
return 'HTML'
|
||||
else:
|
||||
return None
|
||||
|
||||
def HTMLHighlightToken(self, strTok, oMatch, strStyle):
|
||||
"""
|
||||
Callback for HTML specific highlighting.
|
||||
"""
|
||||
#
|
||||
# Input matches this type.
|
||||
#
|
||||
strValue = oMatch.group()
|
||||
self.ChangeStyle(strStyle)
|
||||
self.WriteContent(strValue)
|
||||
|
||||
if strTok == 'TAG':
|
||||
#
|
||||
# Change to mode 1, 'within tag'.
|
||||
#
|
||||
return 'HTMLTag'
|
||||
|
||||
elif strTok == 'ENDTAG':
|
||||
#
|
||||
# Change to mode 1, 'within tag'.
|
||||
#
|
||||
return 'HTML'
|
||||
|
||||
elif strTok == 'GOTOPHP':
|
||||
#
|
||||
# Embedded PHP
|
||||
#
|
||||
return 'PHP'
|
||||
|
||||
else:
|
||||
#
|
||||
# No state change.
|
||||
#
|
||||
return None
|
||||
|
||||
oStyles = {
|
||||
'PYTHON': ( PythonHighlightToken,
|
||||
(
|
||||
('PUNC', re.compile( r'[-+*!|&^~/%\=<>\[\]{}(),.:]'), puncstyle),
|
||||
('NUMBER', re.compile( r'0x[0-9a-fA-F]+|[+-]?\d+(\.\d+)?([eE][+-]\d+)?|\d+'), numberstyle),
|
||||
('KEYWORD', re.compile( r'(def|class|break|continue|del|exec|finally|pass|' +
|
||||
r'print|raise|return|try|except|global|assert|lambda|' +
|
||||
r'yield|for|while|if|elif|else|and|in|is|not|or|import|' +
|
||||
r'from|True|False)(?![a-zA-Z0-9_])'), keywordstyle),
|
||||
('MAGIC', re.compile( r'self|None'), variablestyle),
|
||||
('MULTILINESTRING', re.compile( r'r?u?(\'\'\'|""")'), stringstyle),
|
||||
('STRING', re.compile( r'r?u?\'(.*?)(?<!\\)\'|"(.*?)(?<!\\)"'), stringstyle),
|
||||
('IDENTIFIER', re.compile( r'[a-zA-Z_][a-zA-Z0-9_]*'), None),
|
||||
('COMMENT', re.compile( r'\#.*'), commentstyle),
|
||||
('NEWLINE', re.compile( r'\r?\n'), 'NewPara'),
|
||||
('WHITESPACE', re.compile( r'[ ]+'), 'Keep'),
|
||||
# if all else fails...
|
||||
('UNKNOWN', re.compile( r'.'), None)
|
||||
)),
|
||||
|
||||
'PythonMultilineString': ( PythonHighlightToken,
|
||||
(
|
||||
('ENDMULTILINESTRING', re.compile( r'.*?("""|\'\'\')', re.DOTALL), stringstyle),
|
||||
('UNKNOWN', re.compile( r'.'), 'Keep')
|
||||
)),
|
||||
|
||||
'C': ( CHighlightToken,
|
||||
(
|
||||
('COMMENT', re.compile( r'//.*\r?\n'), commentstyle),
|
||||
('MULTILINECOMMENT', re.compile( r'/\*.*?\*/', re.DOTALL), commentstyle),
|
||||
('PREPROCESSOR', re.compile( r'\s*#.*?[^\\]\s*\n', re.DOTALL), preprocstyle),
|
||||
('PUNC', re.compile( r'[-+*!&|^~/%\=<>\[\]{}(),.:]'), puncstyle),
|
||||
('NUMBER', re.compile( r'0x[0-9a-fA-F]+|[+-]?\d+(\.\d+)?([eE][+-]\d+)?|\d+'),
|
||||
numberstyle),
|
||||
('KEYWORD', re.compile( r'(sizeof|int|long|short|char|void|' +
|
||||
r'signed|unsigned|float|double|' +
|
||||
r'goto|break|return|continue|asm|' +
|
||||
r'case|default|if|else|switch|while|for|do|' +
|
||||
r'struct|union|enum|typedef|' +
|
||||
r'static|register|auto|volatile|extern|const)(?![a-zA-Z0-9_])'), keywordstyle),
|
||||
( 'CPPKEYWORD', re.compile( r'(class|private|protected|public|template|new|delete|' +
|
||||
r'this|friend|using|inline|export|bool|throw|try|catch|' +
|
||||
r'operator|typeid|virtual)(?![a-zA-Z0-9_])'), keywordstyle),
|
||||
('STRING', re.compile( r'r?u?\'(.*?)(?<!\\)\'|"(.*?)(?<!\\)"'), stringstyle),
|
||||
('IDENTIFIER', re.compile( r'[a-zA-Z_][a-zA-Z0-9_]*'), None),
|
||||
('NEWLINE', re.compile( r'\r?\n'), 'NewPara'),
|
||||
('WHITESPACE', re.compile( r'[ ]+'), 'Keep'),
|
||||
('UNKNOWN', re.compile( r'.'), None)
|
||||
)),
|
||||
|
||||
'PHP': ( PHPHighlightToken,
|
||||
(
|
||||
('COMMENT', re.compile( r'//.*\r?\n'), commentstyle),
|
||||
('MULTILINECOMMENT', re.compile( r'/\*.*?\*/', re.DOTALL), commentstyle),
|
||||
('MULTILINESTRING', re.compile( r'<<<\s*([a-zA-Z0-9_]+)'), stringstyle),
|
||||
('GOTOPHP', re.compile( r'<\?php'), stringstyle),
|
||||
('PUNC', re.compile( r'[-+*!&|^~/%\=<>\[\]{}(),.:]'), puncstyle),
|
||||
('NUMBER', re.compile( r'0x[0-9a-fA-F]+|[+-]?\d+(\.\d+)?([eE][+-]\d+)?|\d+'),
|
||||
numberstyle),
|
||||
('KEYWORD', re.compile( r'(declare|else|enddeclare|endswitch|elseif|endif|if|switch|' +
|
||||
r'as|do|endfor|endforeach|endwhile|for|foreach|while|' +
|
||||
r'case|default|switch|function|return|break|continue|exit|' +
|
||||
r'var|const|boolean|bool|integer|int|real|double|float|string|' +
|
||||
r'array|object|NULL|extends|implements|instanceof|parent|self|' +
|
||||
r'include|require|include_once|require_once|new|true|false)(?![a-zA-Z0-9_])'), keywordstyle),
|
||||
|
||||
('STRING', re.compile( r'r?u?\'(.*?)(?<!\\)\'|"(.*?)(?<!\\)"'), stringstyle),
|
||||
('VARIABLE', re.compile( r'\$[a-zA-Z_][a-zA-Z0-9_]*'), variablestyle),
|
||||
('IDENTIFIER', re.compile( r'[a-zA-Z_][a-zA-Z0-9_]*'), None),
|
||||
('WHITESPACE', re.compile( r'[ \r\n]+'), 'Keep'),
|
||||
('GOTOHTML', re.compile( r'\?>'), stringstyle),
|
||||
('UNKNOWN', re.compile( r'.'), None)
|
||||
)),
|
||||
|
||||
'PHPMultilineString': ( PHPHighlightToken,
|
||||
(
|
||||
('ENDMULTILINESTRING', re.compile( r'.*?\n([a-zA-Z0-9_]+)', re.DOTALL), stringstyle),
|
||||
('UNKNOWN', re.compile( r'.*?(?!\n)'), 'Keep')
|
||||
)),
|
||||
|
||||
'HTML': ( HTMLHighlightToken,
|
||||
# Mode 0: just look for tags
|
||||
(
|
||||
('COMMENT', re.compile( r'<!--[^>]*-->|<!>'), commentstyle),
|
||||
('XMLCRAP', re.compile( r'<![^>]*>'), preprocstyle),
|
||||
('SCRIPT', re.compile( r'<script .*?</script>', re.IGNORECASE + re.DOTALL), tagstyle),
|
||||
('TAG', re.compile( r'</?\s*[a-zA-Z0-9]+'), tagstyle),
|
||||
('GOTOPHP', re.compile( r'<\?php'), stringstyle),
|
||||
('NEWLINE', re.compile( r'\r?\n'), 'NewPara'),
|
||||
('UNKNOWN', re.compile( r'[^<]*'), None)
|
||||
)),
|
||||
# Mode 1: within tags,
|
||||
'HTMLTag': ( HTMLHighlightToken,
|
||||
(
|
||||
('ENDTAG', re.compile( r'>'), tagstyle),
|
||||
('ATTRIBUTE', re.compile( r'[a-zA-Z][a-zA-Z0-9:]*='), attrstyle),
|
||||
('VALUE', re.compile( r'"[^"]*"'), stringstyle),
|
||||
('NEWLINE', re.compile( r'\r?\n'), 'NewPara'),
|
||||
('WHITESPACE', re.compile( r'[ \t\f\v]+'), None),
|
||||
('UNKNOWN', re.compile( r'.'), None)
|
||||
))
|
||||
}
|
||||
|
||||
def generatedoc(self, strData):
|
||||
"""
|
||||
Syntax highlight some python code.
|
||||
Returns html version of code.
|
||||
"""
|
||||
i = 0
|
||||
|
||||
strMode = self.strMode
|
||||
|
||||
#
|
||||
# While input is not exhausted...
|
||||
#
|
||||
while i < len(strData):
|
||||
#
|
||||
# Compare current position with all possible display types.
|
||||
#
|
||||
try:
|
||||
for strTok, oRE, strStyle in Highlight.oStyles[strMode][1]:
|
||||
if not strTok in self.strSuppressTokens:
|
||||
oMatch = oRE.match(strData, i)
|
||||
if oMatch:
|
||||
strNewMode = Highlight.oStyles[strMode][0](self, strTok, oMatch, strStyle)
|
||||
if strNewMode != None:
|
||||
strMode = strNewMode
|
||||
|
||||
i += len(oMatch.group())
|
||||
break
|
||||
else:
|
||||
#
|
||||
# Token not found so dump out raw text. This doesn't have to be bullet proof.
|
||||
#
|
||||
self.ChangeStyle(None)
|
||||
self.WriteContent(strData[i])
|
||||
i += 1
|
||||
except:
|
||||
raise
|
||||
#
|
||||
# Terminate any styles in use.
|
||||
#
|
||||
self.ChangeStyle(None)
|
||||
|
||||
#
|
||||
# Expand tabs to 4 spaces.
|
||||
# Doesn't matter if this number is wrong, the indentation will be butt ugly anyhow.
|
||||
#
|
||||
return self.textdoc
|
||||
|
||||
def WriteSingleline(self, parent, data):
|
||||
ls = len(data)
|
||||
cnt = 0
|
||||
textstart = 0
|
||||
i = -1
|
||||
for i in xrange(ls):
|
||||
if data[i] == ' ':
|
||||
if cnt == 0:
|
||||
# We found the first space. Now print the text before
|
||||
parent.addText(data[textstart:i])
|
||||
cnt = 0
|
||||
textstart = i
|
||||
cnt = cnt+1
|
||||
else:
|
||||
# We didn't see a space
|
||||
# If there are unprinted spaces, print them now, if there are, then we're at text-start
|
||||
if cnt > 0:
|
||||
parent.addText(' ')
|
||||
if cnt > 1:
|
||||
parent.addElement(S(c=cnt-1))
|
||||
if cnt > 0:
|
||||
cnt = 0
|
||||
textstart = i
|
||||
if cnt > 0:
|
||||
parent.addText(' ')
|
||||
if cnt > 1:
|
||||
parent.addElement(S(c=cnt-1))
|
||||
elif i != -1:
|
||||
parent.addText(data[textstart:i+1])
|
||||
|
||||
|
||||
def WriteMultiline(self, data):
|
||||
lines = data.split('\n')
|
||||
self.currPara.addText(lines[0])
|
||||
for line in lines[1:]:
|
||||
self.currPara = P(stylename=self.programliststyle)
|
||||
self.textdoc.text.addElement(self.currPara)
|
||||
self.currSpan = Span(stylename=self.strSpanStyle)
|
||||
self.WriteSingleline(self.currSpan, line)
|
||||
self.currPara.addElement(self.currSpan)
|
||||
|
||||
def WriteContent(self, data):
|
||||
"""
|
||||
Write the content, but convert spaces to <text:s> first
|
||||
"""
|
||||
# re.compile( r'( )\1+(.+)')
|
||||
if self.currSpan is None:
|
||||
self.WriteSingleline(self.currPara, data)
|
||||
else:
|
||||
self.WriteSingleline(self.currSpan, data)
|
||||
|
||||
def ChangeStyle(self, strStyle):
|
||||
"""
|
||||
Generate output to change from existing style to another style only.
|
||||
"""
|
||||
#
|
||||
# Output minimal formatting code: only output anything if the style has
|
||||
# actually changed.
|
||||
#
|
||||
if self.strSpanStyle != strStyle:
|
||||
if strStyle == 'NewPara':
|
||||
self.currPara = P(stylename=self.programliststyle)
|
||||
self.textdoc.text.addElement(self.currPara)
|
||||
self.currSpan = None
|
||||
self.strSpanStyle = None
|
||||
elif strStyle != 'Keep':
|
||||
if strStyle is None:
|
||||
self.currSpan = None
|
||||
else:
|
||||
self.currSpan = Span(stylename=strStyle)
|
||||
self.currPara.addElement(self.currSpan)
|
||||
self.strSpanStyle = strStyle
|
||||
|
||||
def usage():
|
||||
sys.stderr.write("Usage: %s [-l language] [-e encoding] inputfile outputfile\n" % sys.argv[0])
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(sys.argv[1:], "l:e:", ["language=", "encoding="])
|
||||
|
||||
except getopt.GetoptError:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
language = None
|
||||
encoding = 'utf-8'
|
||||
for o, a in opts:
|
||||
if o in ("-l", "--language"):
|
||||
language = a.upper()
|
||||
if o in ("-e", "--encoding"):
|
||||
encoding = a
|
||||
|
||||
if len(args) != 2:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
suffixes = {
|
||||
'.py': 'PYTHON',
|
||||
'.xhtml': 'HTML',
|
||||
'.html': 'HTML',
|
||||
'.htm': 'HTML',
|
||||
'.c': 'C',
|
||||
'.c++': 'CPP',
|
||||
'.php': 'PHP'
|
||||
}
|
||||
|
||||
inputfile = args[0]
|
||||
outputfile = args[1]
|
||||
if language is None:
|
||||
try:
|
||||
suffix = inputfile.lower().rindex('.')
|
||||
language = suffixes[inputfile[suffix:]]
|
||||
except:
|
||||
usage()
|
||||
sys.exit(2)
|
||||
|
||||
data = unicode(open(inputfile).read(),encoding)
|
||||
Highlighted = Highlight(language).generatedoc(data)
|
||||
|
||||
Highlighted.save(args[1])
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
For some reason the script crashes on the make_parser() call in odf2xhtml.py,
|
||||
but only when called from Trac.
|
||||
|
||||
To INSTALL:
|
||||
|
||||
Run python setup.py bdist_egg
|
||||
Then copy the egg to the Trac plugin directory or Python's site-packages
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from odfpreview import OdfPreview
|
|
@ -0,0 +1,85 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from trac.core import *
|
||||
from trac.mimeview.api import IHTMLPreviewRenderer
|
||||
import os
|
||||
from tempfile import mkstemp
|
||||
from odf.odf2xhtml import ODF2XHTML
|
||||
|
||||
|
||||
class ODF2XHTMLBody(ODF2XHTML):
|
||||
|
||||
def __init__(self):
|
||||
ODF2XHTML.__init__(self, generate_css=False, embedable=True)
|
||||
|
||||
def rewritelink(self, imghref):
|
||||
imghref = imghref.replace("Pictures/","index_html?pict=")
|
||||
return imghref
|
||||
|
||||
class OdfPreview(Component):
|
||||
"""Display OpenDocument as HTML."""
|
||||
implements(IHTMLPreviewRenderer)
|
||||
|
||||
def get_quality_ratio(self, mimetype):
|
||||
self.env.log.debug('Trac checking for %s' % mimetype)
|
||||
if mimetype in ('application/vnd.oasis.opendocument.text',
|
||||
'application/vnd.oasis.opendocument.text-template',
|
||||
'application/vnd.oasis.opendocument.spreadsheet',
|
||||
'application/vnd.oasis.opendocument.presentation'):
|
||||
return 7
|
||||
return 0
|
||||
|
||||
def render(self, req, input_type, content, filename=None, url=None):
|
||||
self.env.log.debug('HTML output for ODF')
|
||||
odhandler = ODF2XHTMLBody()
|
||||
hfile, hfilename = mkstemp('tracodf')
|
||||
try:
|
||||
if hasattr(content,'read'):
|
||||
os.write(hfile, content.read())
|
||||
else:
|
||||
os.write(hfile, content)
|
||||
os.close(hfile)
|
||||
out = odhandler.odf2xhtml(hfilename).encode('us-ascii','xmlcharrefreplace')
|
||||
except:
|
||||
self.env.log.error("odf2xhtml failed")
|
||||
finally:
|
||||
os.unlink(hfilename)
|
||||
if out != '':
|
||||
return out
|
||||
return "<h1>HTML preview failed</h1>"
|
||||
|
||||
# def render(self, req, input_type, content, filename=None, url=None):
|
||||
# self.env.log.debug('HTML output for ODF')
|
||||
# hfilename = None
|
||||
# odhandler = ODF2XHTML()
|
||||
# if filename is not None:
|
||||
# infile = filename
|
||||
# else:
|
||||
# hfile, hfilename = mkstemp('tracodf')
|
||||
# if hasattr(content,'read'):
|
||||
# os.write(hfile, content.read())
|
||||
# else:
|
||||
# os.write(hfile, content)
|
||||
# os.close(hfile)
|
||||
# infile = hfilename
|
||||
# out = odhandler.odf2xhtml(infile).encode('us-ascii','xmlcharrefreplace')
|
||||
# if hfilename is not None:
|
||||
# os.unlink(hfilename)
|
||||
# return out
|
|
@ -0,0 +1,20 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from odftohtml import *
|
|
@ -0,0 +1,41 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from trac.core import *
|
||||
from trac.mimeview.api import IContentConverter
|
||||
import os
|
||||
import re
|
||||
from odf.odf2xhtml import ODF2XHTML
|
||||
|
||||
class OdfToHtmlConverter(Component):
|
||||
"""Convert OpenDocument to HTML."""
|
||||
implements(IContentConverter)
|
||||
|
||||
# IContentConverter methods
|
||||
def get_supported_conversions(self):
|
||||
yield ('odt', 'OpenDocument Text', 'odt', 'application/vnd.oasis.opendocument.text', 'text/html', 7)
|
||||
yield ('ott', 'OpenDocument Text', 'ott', 'application/vnd.oasis.opendocument.text-template', 'text/html', 7)
|
||||
yield ('ods', 'OpenDocument Spreadsheet', 'ods', 'application/vnd.oasis.opendocument.spreadsheet', 'text/html', 7)
|
||||
yield ('odp', 'OpenDocument Presentation', 'odp', 'application/vnd.oasis.opendocument.presentation', 'text/html', 7)
|
||||
|
||||
def convert_content(self, req, input_type, source, output_type):
|
||||
odhandler = ODF2XHTML()
|
||||
out = odhandler.odf2xhtml(source).encode('us-ascii','xmlcharrefreplace')
|
||||
self.env.log.debug('HTML output for ODF')
|
||||
return (out, 'text/html')
|
|
@ -0,0 +1,33 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from setuptools import setup
|
||||
|
||||
PACKAGE = 'OdfConversion'
|
||||
VERSION = '0.1'
|
||||
|
||||
setup(name='OdfConversion',
|
||||
version='0.1',
|
||||
packages=['odfpreview','odftohtml'],
|
||||
author='Soren Roug',
|
||||
author_email='soren.roug@eea.europa.eu',
|
||||
description='A plugin for viewing ODF documents as HTML',
|
||||
url='http://trac-hacks.org/wiki/OdfConversion',
|
||||
entry_points={'trac.plugins': ['odfpreview.odfpreview=odfpreview.odfpreview',
|
||||
'odftohtml.odftohtml=odftohtml.odftohtml']})
|
|
@ -0,0 +1,14 @@
|
|||
This script will create a OpenDocument Text out of an XLIFF file.
|
||||
The texts to translate are stored on <user-field-decl> elements.
|
||||
|
||||
Send the OpenDocument Text to the translator.
|
||||
|
||||
You can then extract the translations later with odfuserfields and in
|
||||
principle put them back into the original XLIFF file, but this is an
|
||||
exercise left to the reader.
|
||||
|
||||
Other projects on translation:
|
||||
|
||||
http://translate.sourceforge.net/wiki/toolkit/odf2xliff
|
||||
http://translate.sourceforge.net/wiki/developers/projects/odf
|
||||
http://www.hforge.org/odf-i18n-tests
|
|
@ -0,0 +1,423 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE xliff SYSTEM "http://www.oasis-open.org/committees/xliff/documents/xliff.dtd">
|
||||
<!-- XLIFF Format Copyright © OASIS Open 2001-2003 -->
|
||||
<xliff version="1.0">
|
||||
<file
|
||||
original="global.txt"
|
||||
product-name="Honoloko genxliff"
|
||||
product-version="1.0"
|
||||
datatype="plaintext"
|
||||
source-language="en"
|
||||
target-language="da"
|
||||
date="2005-08-24T21:13:34Z"
|
||||
>
|
||||
<header>
|
||||
</header>
|
||||
<body>
|
||||
<trans-unit id="intro">
|
||||
<source>Welcome to our Island of Honoloko.</source>
|
||||
<target>Velkommen til vores ø, Honoloko.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="introHealth">
|
||||
<source>I am the Health Machine.</source>
|
||||
<target>Jeg er Sundheds-maskinen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="introEnergy">
|
||||
<source>I am the Energy Robot.</source>
|
||||
<target>Jeg er Energirobotten.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="introResources">
|
||||
<source>I am the Resources Creature.</source>
|
||||
<target>Jeg er Ressource-dyret.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="introFitness">
|
||||
<source>I am the Fitness Bunny.</source>
|
||||
<target>Jeg er Kondikaninen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="introGroup">
|
||||
<source>We will help you around Honoloko by giving you tips. Enjoy your time here, but be careful what you decide to do. Your actions will affect the environment and the health of our Island and of the people that live here.</source>
|
||||
<target>Vi vil hjælpe dig rundt på Honoloko ved at give dig tips. Hav det sjovt her, men pas på, hvad du beslutter dig for at gøre. Dine handlinger vil påvirke miljøet og sundheden for øen og dens indbyggere.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="charChoose1">
|
||||
<source>Would you like to be a breakdancer or a kung-fu master?</source>
|
||||
<target>Vil du være breakdancer eller kung-fu mester?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="charChoose2">
|
||||
<source>Would you like to be a Boy/Girl?</source>
|
||||
<target>Vil du være dreng eller pige?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="charChoose3">
|
||||
<source>Choose your name</source>
|
||||
<target>Vælg dit navn</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="instructions1">
|
||||
<source>Hi</source>
|
||||
<target>Hej</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="instructions2">
|
||||
<source>You are about to depart for our beautiful Island of Honoloko. Remember, answer the questions and think about the people and environment. Keep an eye on the gameboard so you can see the effect of your decisions.</source>
|
||||
<target>Du skal snart af sted til vores smukke ø, Honoloko. Husk på at besvare spørgsmålene og at tænke på folk og miljø. Hold øje med spillebrættet, så du kan se dine beslutningers virkninger.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l2">
|
||||
<source>Choose which building you would like to build on the board:</source>
|
||||
<target>Vælg, hvilken bygning du vil bygge på spillebrættet:</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l2c1">
|
||||
<source>Sewage Plant</source>
|
||||
<target>Rensningsanlæg</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l2c2">
|
||||
<source>Luxury Hotel</source>
|
||||
<target>Luksushotel</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l2c3">
|
||||
<source>Car Factory</source>
|
||||
<target>Bilfabrik</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l1">
|
||||
<source>Choose how you would like to travel around the board:</source>
|
||||
<target>Vælg hvordan du vil bevæge dig rundt på spillebrættet:</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l1c1">
|
||||
<source>Car</source>
|
||||
<target>Bil</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l1c2">
|
||||
<source>Bus</source>
|
||||
<target>Bus</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l1c3">
|
||||
<source>Bike</source>
|
||||
<target>Cykel</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l3">
|
||||
<source>Choose how you would like to spend your time:</source>
|
||||
<target>Vælg hvordan du vil bruge din tid:</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l3c1">
|
||||
<source>Play</source>
|
||||
<target>Lege</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l3c2">
|
||||
<source>Laze</source>
|
||||
<target>Dovne</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="l3c3">
|
||||
<source>Explore</source>
|
||||
<target>Udforske</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="score90to100">
|
||||
<source>Well Done! You scored really well. You are obviously a master at breakdance/kung-fu and your coolness has helped you make the right decisions. The healthy, fit, happy people of lucious Honoloko throw a party in your honour. Please come back soon!</source>
|
||||
<target>Godt gået! Du scorede mange points. Du er åbenbart mester i breakdance/kung-fu, og det har hjulpet dig til at træffe de rigtige beslutninger. De sunde, veltrænede og lykkelige folk på Honoloko holder en fest til ære for dig. Kom snart igen!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="score80to89">
|
||||
<source>Excellent! You scored really well. Your advanced handling of the resources and environment has made the people of Honoloko very healthy and fit. Keep them happy and come back soon!</source>
|
||||
<target>Glimrende! Du scorede mange points. Din dygtige håndtering af ressourcerne og miljøet har gjort folkene på Honoloko meget raske og veltrænede. Bliv ved med at gøre dem glade og kom snart igen!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="score70to79">
|
||||
<source>Great. It seems like you know what you are doing when it comes to handling Honoloko's resources and energy. The island's people are fit and healthy. They want you to come back!</source>
|
||||
<target>Flot. Du lader til at have styr på at håndtere Honolokos ressourcer og energi. Øens indbyggere er i god form og raske. De vil have, at du kommer tilbage!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="score60to69">
|
||||
<source>Good. You scored above average, but you need to spend more attention on how you care for the environment and your health. You should practice more by playing again.</source>
|
||||
<target>Godt. Du scorede flere points end gennemsnittet, men du skal være mere opmærksom på, hvordan du passer på miljøet og dit helbred. Du burde øve dig mere ved at spille spillet igen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="score50to59">
|
||||
<source>You scored OK but you did some damage too. You haven't improved our Island either and there is a lot you could do better. The people of Honoloko allow you to leave the Island without paying for the damage you have done. Come back to put it right!</source>
|
||||
<target>Du klarede dig godt, men du forvoldte også nogen skade. Du har ikke forbedret øen, og der er meget, du kunne gøre bedre. Folkene på Honoloko vil lade dig forlade øen uden at betale for den skade, som du forvoldte. Kom tilbage og ret bod på skaden!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="score40to49">
|
||||
<source>You scored OK but you did some damage too. You haven't improved our Island either and there is a lot you could do better. The people of Honoloko allow you to leave the Island without paying for the damage you have done. Come back to put it right!</source>
|
||||
<target>Du klarede dig godt, men du forvoldte også nogen skade. Du har ikke forbedret øen, og der er meget, du kunne gøre bedre. Folkene på Honoloko vil lade dig forlade øen uden at betale for den skade, som du forvoldte. Kom tilbage og ret bod på skaden!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="score30to39">
|
||||
<source>You scored below average and as a result the island is less healthy and more polluted than when you arrived. People are unhealthy and are wasting resources. You should come back to put it right.</source>
|
||||
<target>Du scorede mindre end gennemsnittet, og som følge deraf er øen mindre sund og mere forurenet, end da du ankom. Folk er usunde og spilder ressourcer. Du burde komme tilbage og rette bod på skaden.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="score20to29">
|
||||
<source>You scored pretty badly. You have managed to cause a lot of damage to the health and environment of Honoloko and its people. The people demand that you come back and repair the damage you inflicted on them. Click to play again.</source>
|
||||
<target>Du scorede temmelig dårligt. Du har forvoldt stor skade på Honoloko og dens indbyggeres helbred og miljø. Folkene forlanger, at du kommer tilbage og udbedrer den skade, du har forvoldt dem. Klik for at spille igen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="score10to19">
|
||||
<source>Are you being serious! Is this the best you can do!? You've caused pollution and wasted our resources, and Honoloko is in a complete mess!! You need to change your attitude now. The unhealthy, overweight people of Honoloko won't let you leave the island. You have to stay and clear up the mess! Click to play again.</source>
|
||||
<target>Tager du det overhovedet alvorligt? Er det virkelig dit bedste? Du har forårsaget forurening og spildt vores ressourcer. Honoloko er i suppedasen! Du må straks ændre din holdning. De usunde, overvægtige folk på Honoloko vil ikke lade dig forlade øen. Du må blive og rydde op i redeligheden! Klik for at spille igen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="score0to09">
|
||||
<source>You should be locked away! Armageddon is now upon us. You completely destroyed all the resources on Honoloko and its people are miserably unhealthy. How long do you think will you survive without food or water? Click to play again.</source>
|
||||
<target>Du burde spærres inde! Dommedag er over os. Du har fuldstændig ødelagt alle ressourcer på Honoloko, og øens indbyggere er jammerligt usunde. Hvor længe tror du, du kan overleve uden mad og drikke? Klik for at spille igen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="scoretop100">
|
||||
<source>To enter our high score table and for the opportunity to win a prize enter your email and select your country here. Click here if you are not on line</source>
|
||||
<target>Indtast din e-mail-adresse og vælg dit land her, hvis du vil på listen over topscorere og vinde en præmie. Klik her, hvis du ikke er tilsluttet internettet.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="scoreTop100Offline">
|
||||
<source>Here is your code, write it down and when you are next online visit www.honoloko.com/score.php and enter your code.</source>
|
||||
<target>Her er din adgangskode. Skriv den ned. Besøg www.honoloko.com/score.php næste gang du er på nettet, og indtast din kode.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreRes9to10">
|
||||
<source>Congratulations, You've helped us use our resources wisely! Come back with your friends.</source>
|
||||
<target>Tillykke. Du har hjulpet os med at bruge vores ressourcer fornuftigt! Kom tilbage med dine venner.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreRes7to8">
|
||||
<source>Thanks, you've helped us keep on using our resources quite well!</source>
|
||||
<target>Tak. Du har hjulpet os med at bruge vores ressourcer ganske godt!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreRes5to6">
|
||||
<source>Your use of resources is average and can be improved.</source>
|
||||
<target>Din anvendelse af ressourcer er gennemsnitlig og kan forbedres.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreRes3to4">
|
||||
<source>Using so much of Honoloko's resources has proved disastrous. Better shape up next time.</source>
|
||||
<target>Brug af så mange af Honolokos ressourcer har været katastrofalt. Tag dig sammen næste gang.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreRes0to2">
|
||||
<source>You managed to waste all of Honoloko's natural resources in your short stay.</source>
|
||||
<target>Det lykkedes dig at spilde alle Honolokos naturressourcer under dit korte ophold.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreEnergy9to10">
|
||||
<source>Well done, you didn't waste any energy and you helped our environment!</source>
|
||||
<target>Godt gået! Du spildte ingen energi, og du hjalp miljøet.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreEnergy7to8">
|
||||
<source>Good work, you managed to use energy sensibly.</source>
|
||||
<target>Flot! Du forvaltede energien fornuftigt.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreEnergy5to6">
|
||||
<source>You could have done better, but at least you didn't blow the power station up!</source>
|
||||
<target>Du kunne have klaret dig bedre, men du sprang i det mindste ikke kraftværket i luften!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreEnergy3to4">
|
||||
<source>You wasted a huge amount of energy while you were here.</source>
|
||||
<target>Du spildte en enorm mængde energi, mens du var her.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreEnergy0to2">
|
||||
<source>You wasted so much energy that you blew up our power station. Thanks a lot!</source>
|
||||
<target>Du spildte så megen energi, at kraftværket sprængte i luften. Tak skal du have!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreFit9to10">
|
||||
<source>You are super fit! We all fancy you!</source>
|
||||
<target>Du er i topform! Vi er alle vilde med dig!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreFit7to8">
|
||||
<source>You are quite fit. But visit Honoloko again and try to get fitter!</source>
|
||||
<target>Du er i god form. Besøg Honoloko igen og prøv at forbedre din kondi!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreFit5to6">
|
||||
<source>You are doing ok, but there's room for improvement.</source>
|
||||
<target>Du klarer dig fint, men der er plads til forbedring.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreFit3to4">
|
||||
<source>You're not fit enough. Walking to the fridge and back is not real exercise.</source>
|
||||
<target>Din kondi er for dårlig. At gå hen til køleskabet og tilbage igen tæller ikke som idræt.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreFit0to2">
|
||||
<source>You are super lazy. Did you spend the whole day sitting in front of the TV?</source>
|
||||
<target>Du er superdoven. Sad du foran fjernsynet hele dagen?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreHealth9to10">
|
||||
<source>You are very healthy. You probably eat well and don't smoke. Keep it up!</source>
|
||||
<target>Du er ved godt helbred. Du spiser sikkert godt og ryger ikke. Bliv ved med det!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreHealth7to8">
|
||||
<source>You are in good health. Keep it up.</source>
|
||||
<target>Du er ved godt helbred. Hold det ved lige.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreHealth5to6">
|
||||
<source>You don't look well. You could do better</source>
|
||||
<target>Du ser ikke for sund ud. Det kunne du forbedre.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreHealth3to4">
|
||||
<source>You are pretty unhealthy. Shape up!</source>
|
||||
<target>Du er temmelig usund. Se at komme i form!</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="enviroScoreHealth0to2">
|
||||
<source>Are you still breathing?</source>
|
||||
<target>Trækker du stadig vejret?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="extendedInstructions1">
|
||||
<source>Our Island of Honoloko is very similar to the real world, where your actions really do make a difference to your surroundings. The effects of your actions are immediately visible.</source>
|
||||
<target>Vores ø, Honoloko, minder meget om den virkelige verden, hvor dine handlinger har indflydelse på dine omgivelser. Dine handlingers virkninger kan ses med det samme.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="extendedInstructions2">
|
||||
<source>The aim of the game is to make decisions that most improve the health and environment on Honoloko.</source>
|
||||
<target>Formålet med spillet er at forbedre helbredet og miljøet på Honoloko.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="extendedInstructions3">
|
||||
<source>If your decisions score well in Resources or Energy you improve the Environment. When Health or Fitness scores go up or down, you see the Health of the people who live on Honoloko getting better or worse. Remember a better environment means healthier people.</source>
|
||||
<target>Hvis dine beslutninger giver mange ressource- og energipoints, forbedrer du miljøet. Når pointene for helbred og kondition går op eller ned, ser du, hvordan folks helbred på Honoloko bliver bedre eller værre. Husk på, at et bedre miljø betyder sundere mennesker.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="extendedInstructions4">
|
||||
<source>Keep an eye on the island, where you will see changes taking place according to your decisions.</source>
|
||||
<target>Hold øje med øen, hvor du kan se forandringer afhængigt af dine beslutninger.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="extendedInstructions5">
|
||||
<source>The scores show up in the billboards beside the road, and the colour of the billboard shows how you are doing. Red means you are doing badly in that sector, orange means average, and green means really good.</source>
|
||||
<target>Dine points kan aflæses på pointtavlerne ved vejsiden, og tavlens farve viser, hvor godt du klarer dig. Rødt betyder, at du klarer dig dårligt i den sektor, orange betyder gennemsnitligt, og grønt betyder rigtig godt.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="extendedInstructions6">
|
||||
<source>Your total score appears at the end of the game with your scores for each of the four sections.</source>
|
||||
<target>Dine samlede points og dine points for hver af de fire sektioner kan ses, når spillet er forbi.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="topScoreboard">
|
||||
<source>Top Scoreboard</source>
|
||||
<target>Topscorertavle</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="top100Scoreboard">
|
||||
<source>Top 100 Scoreboard</source>
|
||||
<target>Topscorertavle med de 100 bedste</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="topScorers">
|
||||
<source>These are the top scorers from Honoloko Island. You can win a prize if you get onto this board. If your name is drawn we will contact you so you can claim your prize.</source>
|
||||
<target>Her er topscorerne fra øen Honoloko. Du kan vinde en præmie, hvis du kommer med på tavlen. Hvis dit navn bliver udtrukket, kontakter vi dig, så du kan få din præmie.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="topScoresFrom">
|
||||
<source>Top scores from</source>
|
||||
<target>Topscoring fra</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tellAFriend">
|
||||
<source>Tell a friend</source>
|
||||
<target>Fortæl en ven om det</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tellAFriendNotes">
|
||||
<source>You completed the game. Bring a friend here and see if you can score higher than them!</source>
|
||||
<target>Du fuldførte spillet. Tag en ven med og se, om du kan få flere points end ham/hende.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="playAgain">
|
||||
<source>Play Again</source>
|
||||
<target>Spil igen</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="totalScore">
|
||||
<source>Total Score</source>
|
||||
<target>Samlet scoring</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="volume">
|
||||
<source>Volume</source>
|
||||
<target>Lydstyrke</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="on">
|
||||
<source>On</source>
|
||||
<target>Tænd</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="off">
|
||||
<source>Off</source>
|
||||
<target>Sluk</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="homePage">
|
||||
<source>Homepage</source>
|
||||
<target>Hjemmeside</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="credits">
|
||||
<source>Credits</source>
|
||||
<target>Rulletekst</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="inst">
|
||||
<source>Instructions</source>
|
||||
<target>Instrukser</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="audioControls">
|
||||
<source>Audio Controls</source>
|
||||
<target>Lydstyring</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="creditsText1">
|
||||
<source>European Environment Agency</source>
|
||||
<target>Det Europæiske Miljøagentur</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="creditsText2">
|
||||
<source>Produced by</source>
|
||||
<target>Produceret af</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="creditsText3">
|
||||
<source>The EEA in co-operation with the WHO Regional Office for Europe</source>
|
||||
<target>EEA i samarbejde med WHO's regionale kontor for Europa</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="cancel">
|
||||
<source>Cancel</source>
|
||||
<target>Annullér</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tellAFriendError">
|
||||
<source>Sorry the email address you gave didn't work properly</source>
|
||||
<target>E-mail-adressen, du angav, virkede desværre ikke</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tellAFriendSuccess">
|
||||
<source>Your friend has been asked to come to Honoloko</source>
|
||||
<target>Din ven er blevet inviteret til Honoloko</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tellAFriendsEmailText">
|
||||
<source>Friend's email</source>
|
||||
<target>Vennens e-mail-adresse</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tellAFriendsNameText">
|
||||
<source>Friend's name</source>
|
||||
<target>Vennens navn</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="yourName">
|
||||
<source>Your name</source>
|
||||
<target>Dit navn</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="next">
|
||||
<source>Next</source>
|
||||
<target>Videre</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="newGameButton">
|
||||
<source>New game</source>
|
||||
<target>Nyt spil</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="scoreboardButton">
|
||||
<source>Scoreboard</source>
|
||||
<target>Pointtavle</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="tellAFriendButton">
|
||||
<source>Tell a Friend</source>
|
||||
<target>Fortæl en ven</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="correctLanguage">
|
||||
<source>Is this the correct language for you?</source>
|
||||
<target>Er det det rette sprog for dig?</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="checkCountryScores">
|
||||
<source>Click on your country name to view the scores of people that are also from the same country.</source>
|
||||
<target>Klik på dit land for at se scoringslisten for folk fra samme land.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="checkPosition">
|
||||
<source>Click on your score to view what your position is.</source>
|
||||
<target>Klik på din scoring for at se, hvad din stilling er.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="checkRank">
|
||||
<source>Click on your name to see how you rank in the scoreboard.</source>
|
||||
<target>Klik på dit navn for at se, hvor du er på pointtavlen.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="feedbackSent">
|
||||
<source>This has been sent successfully.</source>
|
||||
<target>Din besked er blevet sendt.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="feedbackWait">
|
||||
<source>Please wait for confirmation</source>
|
||||
<target>Vent venligst på bekræftelse</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="continue">
|
||||
<source>Continue</source>
|
||||
<target>Fortsæt</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="country">
|
||||
<source>Country</source>
|
||||
<target>Land</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="email">
|
||||
<source>Email address</source>
|
||||
<target>E-mail-adresse</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="characterName">
|
||||
<source>Your character's name</source>
|
||||
<target>Din figurs navn</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="playerName">
|
||||
<source>Your real name</source>
|
||||
<target>Dit virkelige navn</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="formError">
|
||||
<source>Please check your details and make sure you have spelt your email address correctly and have filled in all the sections.</source>
|
||||
<target>Efterprøv dine detaljer og sørg for, at du har indtastet din e-mail-adresse korrekt og udfyldt alle dele.</target>
|
||||
</trans-unit>
|
||||
</body>
|
||||
</file>
|
||||
</xliff>
|
|
@ -0,0 +1,87 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
from xliff_parser import HandleXliffParsing
|
||||
import sys
|
||||
|
||||
from odf.opendocument import OpenDocumentText
|
||||
from odf import style, table
|
||||
from odf.text import P, UserFieldDecls, UserFieldDecl, UserFieldInput
|
||||
from odf.namespaces import TABLENS
|
||||
|
||||
textdoc = OpenDocumentText()
|
||||
# Create a style for the table content. One we can modify
|
||||
# later in the word processor.
|
||||
tablecontents = style.Style(name="Table Contents", family="paragraph")
|
||||
tablecontents.addElement(style.ParagraphProperties(numberlines="false", linenumber="0"))
|
||||
textdoc.styles.addElement(tablecontents)
|
||||
|
||||
#tablestyle = style.Style(name="Table style", family="table")
|
||||
#tablestyle.addElement(style.TableProperties(protected="true"))
|
||||
#textdoc.automaticstyles.addElement(tablestyle)
|
||||
|
||||
# Create automatic styles for the column widths.
|
||||
widthwide = style.Style(name="Wwide", family="table-column")
|
||||
widthwide.addElement(style.TableColumnProperties(columnwidth="8cm"))
|
||||
textdoc.automaticstyles.addElement(widthwide)
|
||||
|
||||
tcstyle = style.Style(name="Table Cell", family="table-cell")
|
||||
tcstyle.addElement(style.TableCellProperties(cellprotect="protected"))
|
||||
textdoc.automaticstyles.addElement(tcstyle)
|
||||
|
||||
parser = HandleXliffParsing()
|
||||
xliff = file('global.xlf').read()
|
||||
chandler = parser.parseXLIFFSTring(xliff)
|
||||
if chandler is None:
|
||||
print "Unable to parse XLIFF file"
|
||||
sys.exit(0)
|
||||
|
||||
header_info = chandler.getFileTag()
|
||||
body_info = chandler.getBody() #return a dictionary
|
||||
|
||||
uf = UserFieldDecls()
|
||||
textdoc.text.addElement(uf)
|
||||
|
||||
# Add user fields
|
||||
for id,transunit in body_info.items():
|
||||
uf.addElement(UserFieldDecl(name=id,valuetype="string", stringvalue=transunit['target']))
|
||||
|
||||
|
||||
# Start the table, and describe the columns
|
||||
mytable = table.Table(protected="true")
|
||||
mytable.addElement(table.TableColumn(numbercolumnsrepeated=2,stylename=widthwide))
|
||||
|
||||
for id,transunit in body_info.items():
|
||||
tr = table.TableRow()
|
||||
mytable.addElement(tr)
|
||||
|
||||
tc = table.TableCell(stylename=tcstyle, qattributes={(TABLENS,'protected'):'true'})
|
||||
tr.addElement(tc)
|
||||
p = P(stylename=tablecontents,text=transunit['source'])
|
||||
tc.addElement(p)
|
||||
|
||||
tc = table.TableCell(qattributes={(TABLENS,'protected'):'true'})
|
||||
tr.addElement(tc)
|
||||
p = P(stylename=tablecontents)
|
||||
tc.addElement(p)
|
||||
f = UserFieldInput(name=id,description="Enter translation")
|
||||
p.addElement(f)
|
||||
|
||||
textdoc.text.addElement(mytable)
|
||||
textdoc.save("translations.odt")
|
|
@ -0,0 +1,169 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2000-2004 Juan David Ibáñez Palomar <jdavid@itaapy.com>
|
||||
# 2003 Roberto Quero, Eduardo Corrales
|
||||
# 2004 Søren Roug
|
||||
#
|
||||
# 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.
|
||||
|
||||
# NOTE:
|
||||
# This parser doesn't understand the ALT-TRANS element.
|
||||
|
||||
from xml.sax.handler import ContentHandler
|
||||
from xml.sax import *
|
||||
from cStringIO import StringIO
|
||||
from types import StringType, UnicodeType
|
||||
|
||||
#constants
|
||||
_FILE_ATTRS = ['original', 'source-language', 'datatype', 'date',
|
||||
'target-language', 'product-name', 'product-version', 'build-num']
|
||||
_PHASE_ATTRS = ['phase-name', 'process-name', 'tool', 'date', 'contact-name',
|
||||
'contact-email', 'company-name']
|
||||
|
||||
|
||||
class XLIFFHandler(ContentHandler):
|
||||
""" This is used to parse the xliff file
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
"""constructor """
|
||||
self.__currentTag = ''
|
||||
self.__filetag = []
|
||||
self.__phase_group = []
|
||||
self.__source = 0
|
||||
self.__body = {}
|
||||
self.__data = []
|
||||
self.__inside_alttrans = 0
|
||||
self.__tuid = ''
|
||||
|
||||
#functions related with <file> tag
|
||||
def getFileTag(self):
|
||||
return self.__filetag
|
||||
|
||||
def setFileTag(self, dict):
|
||||
self.__filetag.extend(dict)
|
||||
|
||||
#functions related with <phase-group> tag
|
||||
def getPhaseGroup(self):
|
||||
return self.__phase_group
|
||||
|
||||
def setPhaseGroup(self, dict):
|
||||
self.__phase_group.append(dict)
|
||||
|
||||
def getBody(self):
|
||||
return self.__body
|
||||
|
||||
def setBody(self, key, value):
|
||||
self.__body[key] = value
|
||||
|
||||
def startElement(self, name, attrs):
|
||||
self.__currentTag = name
|
||||
|
||||
if name == 'alt-trans':
|
||||
self.__inside_alttrans = 1
|
||||
# Make the attributes available
|
||||
# Implicit assumption: There is only one <file> element.
|
||||
if name == 'file':
|
||||
tmp = attrs.items()
|
||||
for i in [elem for elem in attrs.keys() if elem not in _FILE_ATTRS]:
|
||||
tmp.remove((i, attrs[i]))
|
||||
self.setFileTag(tmp)
|
||||
|
||||
if name == 'phase':
|
||||
tmp = attrs.items()
|
||||
for i in [elem for elem in attrs.keys() if elem not in _PHASE_ATTRS]:
|
||||
tmp.remove((i, attrs[i]))
|
||||
self.setPhaseGroup(tmp)
|
||||
|
||||
if name == 'trans-unit':
|
||||
self.__tuid = attrs['id']
|
||||
self.__source = u''
|
||||
self.__target = u''
|
||||
self.__note = u''
|
||||
|
||||
def endElement(self, name):
|
||||
if name == 'alt-trans':
|
||||
self.__inside_alttrans = 0
|
||||
|
||||
if name == 'source' and self.__inside_alttrans == 0:
|
||||
content = u''.join(self.__data).strip()
|
||||
self.__data = []
|
||||
self.__source = content
|
||||
|
||||
if name == 'target' and self.__inside_alttrans == 0:
|
||||
content = u''.join(self.__data).strip()
|
||||
self.__data = []
|
||||
self.__target = content
|
||||
|
||||
if name == 'note' and self.__inside_alttrans == 0:
|
||||
content = u''.join(self.__data).strip()
|
||||
self.__data = []
|
||||
self.__note = content
|
||||
|
||||
if name == 'trans-unit':
|
||||
self.setBody(self.__tuid, {'source':self.__source,
|
||||
'target':self.__target, 'note':self.__note})
|
||||
|
||||
self.__currentTag = ''
|
||||
|
||||
def characters(self, content):
|
||||
currentTag = self.__currentTag
|
||||
if currentTag in ( 'source', 'target', 'note'):
|
||||
self.__data.append(content)
|
||||
|
||||
class HandleXliffParsing:
|
||||
""" class for parse xliff files """
|
||||
|
||||
def __init__(self):
|
||||
""" """
|
||||
pass
|
||||
|
||||
def parseXLIFFSTring(self, xml_string):
|
||||
""" """
|
||||
chandler = XLIFFHandler()
|
||||
parser = make_parser()
|
||||
# Tell the parser to use our handler
|
||||
parser.setContentHandler(chandler)
|
||||
# Don't load the DTD from the Internet
|
||||
parser.setFeature(handler.feature_external_ges, 0)
|
||||
inpsrc = InputSource()
|
||||
inpsrc.setByteStream(StringIO(xml_string))
|
||||
try:
|
||||
parser.parse(inpsrc)
|
||||
return chandler
|
||||
except:
|
||||
return None
|
||||
|
||||
def parseXLIFFFile(self, file):
|
||||
# Create a parser
|
||||
parser = make_parser()
|
||||
chandler = XLIFFHandler()
|
||||
# Tell the parser to use our handler
|
||||
parser.setContentHandler(chandler)
|
||||
# Don't load the DTD from the Internet
|
||||
parser.setFeature(handler.feature_external_ges, 0)
|
||||
inputsrc = InputSource()
|
||||
|
||||
try:
|
||||
if type(file) is StringType:
|
||||
inputsrc.setByteStream(StringIO(file))
|
||||
else:
|
||||
filecontent = file.read()
|
||||
inputsrc.setByteStream(StringIO(filecontent))
|
||||
parser.parse(inputsrc)
|
||||
return chandler
|
||||
except:
|
||||
return None
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
all: odf csv2ods.1
|
||||
|
||||
txt: csv2ods.txt
|
||||
|
||||
%.1: %.docbook
|
||||
xmlto man $<
|
||||
|
||||
%.txt: %.docbook
|
||||
xmlto txt $<
|
||||
|
||||
clean:
|
||||
rm -f *.1 *~ *.txt odf test.csv test2.ods test3.ods
|
||||
odf:
|
||||
ln -s ../odf
|
||||
|
||||
test: clean odf
|
||||
@echo 1,2,3,4 > test.csv
|
||||
@echo 5,6,7,8 >> test.csv
|
||||
@echo 9,10,11,12 >> test.csv
|
||||
@python2 csv2ods -i test.csv -o test2.ods
|
||||
@python3 csv2ods -i test.csv -o test3.ods
|
||||
@echo created files test.csv, test2.ods and test3.ods
|
|
@ -0,0 +1,229 @@
|
|||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2008 Agustin Henze -> agustinhenze at gmail.com
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
# Søren Roug
|
||||
#
|
||||
# Oct 2014: Georges Khaznadar <georgesk@debian.org>
|
||||
# - ported to Python3
|
||||
# - imlemented the missing switch -c / --encoding, with an extra
|
||||
# feature for POSIX platforms which can guess encoding.
|
||||
|
||||
from odf.opendocument import OpenDocumentSpreadsheet
|
||||
from odf.style import Style, TextProperties, ParagraphProperties, TableColumnProperties
|
||||
from odf.text import P
|
||||
from odf.table import Table, TableColumn, TableRow, TableCell
|
||||
from optparse import OptionParser
|
||||
import sys,csv,re, os, codecs
|
||||
|
||||
if sys.version_info[0]==3: unicode=str
|
||||
|
||||
if sys.version_info[0]==2:
|
||||
class UTF8Recoder:
|
||||
"""
|
||||
Iterator that reads an encoded stream and reencodes the input to UTF-8
|
||||
"""
|
||||
def __init__(self, f, encoding):
|
||||
self.reader = codecs.getreader(encoding)(f)
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
return self.reader.next().encode("utf-8")
|
||||
|
||||
class UnicodeReader:
|
||||
"""
|
||||
A CSV reader which will iterate over lines in the CSV file "f",
|
||||
which is encoded in the given encoding.
|
||||
"""
|
||||
|
||||
def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
|
||||
f = UTF8Recoder(f, encoding)
|
||||
self.reader = csv.reader(f, dialect=dialect, **kwds)
|
||||
|
||||
def next(self):
|
||||
row = self.reader.next()
|
||||
return [unicode(s, "utf-8") for s in row]
|
||||
|
||||
def __iter__(self):
|
||||
return self
|
||||
|
||||
|
||||
def csvToOds( pathFileCSV, pathFileODS, tableName='table',
|
||||
delimiter=',', quoting=csv.QUOTE_MINIMAL,
|
||||
quotechar = '"', escapechar = None,
|
||||
skipinitialspace = False, lineterminator = '\r\n',
|
||||
encoding="utf-8"):
|
||||
textdoc = OpenDocumentSpreadsheet()
|
||||
# Create a style for the table content. One we can modify
|
||||
# later in the word processor.
|
||||
tablecontents = Style(name="Table Contents", family="paragraph")
|
||||
tablecontents.addElement(ParagraphProperties(numberlines="false", linenumber="0"))
|
||||
tablecontents.addElement(TextProperties(fontweight="bold"))
|
||||
textdoc.styles.addElement(tablecontents)
|
||||
|
||||
# Start the table
|
||||
table = Table( name=tableName )
|
||||
|
||||
if sys.version_info[0]==3:
|
||||
reader = csv.reader(open(pathFileCSV, encoding=encoding),
|
||||
delimiter=delimiter,
|
||||
quoting=quoting,
|
||||
quotechar=quotechar,
|
||||
escapechar=escapechar,
|
||||
skipinitialspace=skipinitialspace,
|
||||
lineterminator=lineterminator)
|
||||
else:
|
||||
reader = UnicodeReader(open(pathFileCSV),
|
||||
encoding=encoding,
|
||||
delimiter=delimiter,
|
||||
quoting=quoting,
|
||||
quotechar=quotechar,
|
||||
escapechar=escapechar,
|
||||
skipinitialspace=skipinitialspace,
|
||||
lineterminator=lineterminator)
|
||||
fltExp = re.compile('^\s*[-+]?\d+(\.\d+)?\s*$')
|
||||
|
||||
for row in reader:
|
||||
tr = TableRow()
|
||||
table.addElement(tr)
|
||||
for val in row:
|
||||
if fltExp.match(val):
|
||||
tc = TableCell(valuetype="float", value=val.strip())
|
||||
else:
|
||||
tc = TableCell(valuetype="string")
|
||||
tr.addElement(tc)
|
||||
p = P(stylename=tablecontents,text=val)
|
||||
tc.addElement(p)
|
||||
|
||||
textdoc.spreadsheet.addElement(table)
|
||||
textdoc.save( pathFileODS )
|
||||
|
||||
if __name__ == "__main__":
|
||||
usage = "%prog -i file.csv -o file.ods -d"
|
||||
parser = OptionParser(usage=usage, version="%prog 0.1")
|
||||
parser.add_option('-i','--input', action='store',
|
||||
dest='input', help='File input in csv')
|
||||
parser.add_option('-o','--output', action='store',
|
||||
dest='output', help='File output in ods')
|
||||
parser.add_option('-d','--delimiter', action='store',
|
||||
dest='delimiter', help='specifies a one-character string to use as the field separator. It defaults to ",".')
|
||||
|
||||
parser.add_option('-c','--encoding', action='store',
|
||||
dest='encoding', help='specifies the encoding the file csv. It defaults to utf-8')
|
||||
|
||||
parser.add_option('-t','--table', action='store',
|
||||
dest='tableName', help='The table name in the output file')
|
||||
|
||||
parser.add_option('-s','--skipinitialspace',
|
||||
dest='skipinitialspace', help='''specifies how to interpret whitespace which
|
||||
immediately follows a delimiter. It defaults to False, which
|
||||
means that whitespace immediately following a delimiter is part
|
||||
of the following field.''')
|
||||
|
||||
parser.add_option('-l','--lineterminator', action='store',
|
||||
dest='lineterminator', help='''specifies the character sequence which should
|
||||
terminate rows.''')
|
||||
|
||||
parser.add_option('-q','--quoting', action='store',
|
||||
dest='quoting', help='''It can take on any of the following module constants:
|
||||
0 = QUOTE_MINIMAL means only when required, for example, when a field contains either the quotechar or the delimiter
|
||||
1 = QUOTE_ALL means that quotes are always placed around fields.
|
||||
2 = QUOTE_NONNUMERIC means that quotes are always placed around fields which do not parse as integers or floating point numbers.
|
||||
3 = QUOTE_NONE means that quotes are never placed around fields.
|
||||
It defaults is QUOTE_MINIMAL''')
|
||||
|
||||
parser.add_option('-e','--escapechar', action='store',
|
||||
dest='escapechar', help='''specifies a one-character string used to escape the delimiter when quoting is set to QUOTE_NONE.''')
|
||||
|
||||
parser.add_option('-r','--quotechar', action='store',
|
||||
dest='quotechar', help='''specifies a one-character string to use as the quoting character. It defaults to ".''')
|
||||
|
||||
(options, args) = parser.parse_args()
|
||||
|
||||
if options.input:
|
||||
pathFileCSV = options.input
|
||||
else:
|
||||
parser.print_help()
|
||||
exit( 0 )
|
||||
|
||||
if options.output:
|
||||
pathFileODS = options.output
|
||||
else:
|
||||
parser.print_help()
|
||||
exit( 0 )
|
||||
|
||||
if options.delimiter:
|
||||
delimiter = options.delimiter
|
||||
else:
|
||||
delimiter = ","
|
||||
|
||||
if options.skipinitialspace:
|
||||
skipinitialspace = True
|
||||
else:
|
||||
skipinitialspace=False
|
||||
|
||||
if options.lineterminator:
|
||||
lineterminator = options.lineterminator
|
||||
else:
|
||||
lineterminator ="\r\n"
|
||||
|
||||
if options.escapechar:
|
||||
escapechar = options.escapechar
|
||||
else:
|
||||
escapechar=None
|
||||
|
||||
if options.tableName:
|
||||
tableName = options.tableName
|
||||
else:
|
||||
tableName = "table"
|
||||
|
||||
if options.quotechar:
|
||||
quotechar = options.quotechar
|
||||
else:
|
||||
quotechar = "\""
|
||||
|
||||
encoding = "utf-8" # default setting
|
||||
###########################################################
|
||||
## try to guess the encoding; this is implemented only with
|
||||
## POSIX platforms. Can it be improved?
|
||||
output = os.popen('/usr/bin/file ' + pathFileCSV).read()
|
||||
m=re.match(r'^.*: ([-a-zA-Z0-9]+) text$', output)
|
||||
if m:
|
||||
encoding=m.group(1)
|
||||
if 'ISO-8859' in encoding:
|
||||
encoding="latin-1"
|
||||
else:
|
||||
encoding="utf-8"
|
||||
############################################################
|
||||
# when the -c or --coding switch is used, it takes precedence
|
||||
if options.encoding:
|
||||
encoding = options.encoding
|
||||
|
||||
csvToOds( pathFileCSV=unicode(pathFileCSV),
|
||||
pathFileODS=unicode(pathFileODS),
|
||||
delimiter=delimiter, skipinitialspace=skipinitialspace,
|
||||
escapechar=escapechar,
|
||||
lineterminator=unicode(lineterminator),
|
||||
tableName=tableName, quotechar=quotechar,
|
||||
encoding=encoding)
|
||||
|
||||
# Local Variables: ***
|
||||
# mode: python ***
|
||||
# End: ***
|
|
@ -0,0 +1,270 @@
|
|||
.\" Title: csv2ods
|
||||
.\" Author: Agustin Henze <agustinhenze at gmail.com>
|
||||
.\" Generator: DocBook XSL Stylesheets v1.74.0 <http://docbook.sf.net/>
|
||||
.\" Date: 01/04/2009
|
||||
.\" Manual: User commands
|
||||
.\" Source: odfpy
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "CSV2ODS" "1" "01/04/2009" "odfpy" "User commands"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * (re)Define some macros
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" toupper - uppercase a string (locale-aware)
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de toupper
|
||||
.tr aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ
|
||||
\\$*
|
||||
.tr aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SH-xref - format a cross-reference to an SH section
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de SH-xref
|
||||
.ie n \{\
|
||||
.\}
|
||||
.toupper \\$*
|
||||
.el \{\
|
||||
\\$*
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SH - level-one heading that works better for non-TTY output
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de1 SH
|
||||
.\" put an extra blank line of space above the head in non-TTY output
|
||||
.if t \{\
|
||||
.sp 1
|
||||
.\}
|
||||
.sp \\n[PD]u
|
||||
.nr an-level 1
|
||||
.set-an-margin
|
||||
.nr an-prevailing-indent \\n[IN]
|
||||
.fi
|
||||
.in \\n[an-margin]u
|
||||
.ti 0
|
||||
.HTML-TAG ".NH \\n[an-level]"
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
.nr an-break-flag 1
|
||||
\." make the size of the head bigger
|
||||
.ps +3
|
||||
.ft B
|
||||
.ne (2v + 1u)
|
||||
.ie n \{\
|
||||
.\" if n (TTY output), use uppercase
|
||||
.toupper \\$*
|
||||
.\}
|
||||
.el \{\
|
||||
.nr an-break-flag 0
|
||||
.\" if not n (not TTY), use normal case (not uppercase)
|
||||
\\$1
|
||||
.in \\n[an-margin]u
|
||||
.ti 0
|
||||
.\" if not n (not TTY), put a border/line under subheading
|
||||
.sp -.6
|
||||
\l'\n(.lu'
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" SS - level-two heading that works better for non-TTY output
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de1 SS
|
||||
.sp \\n[PD]u
|
||||
.nr an-level 1
|
||||
.set-an-margin
|
||||
.nr an-prevailing-indent \\n[IN]
|
||||
.fi
|
||||
.in \\n[IN]u
|
||||
.ti \\n[SN]u
|
||||
.it 1 an-trap
|
||||
.nr an-no-space-flag 1
|
||||
.nr an-break-flag 1
|
||||
.ps \\n[PS-SS]u
|
||||
\." make the size of the head bigger
|
||||
.ps +2
|
||||
.ft B
|
||||
.ne (2v + 1u)
|
||||
.if \\n[.$] \&\\$*
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" BB/BE - put background/screen (filled box) around block of text
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de BB
|
||||
.if t \{\
|
||||
.sp -.5
|
||||
.br
|
||||
.in +2n
|
||||
.ll -2n
|
||||
.gcolor red
|
||||
.di BX
|
||||
.\}
|
||||
..
|
||||
.de EB
|
||||
.if t \{\
|
||||
.if "\\$2"adjust-for-leading-newline" \{\
|
||||
.sp -1
|
||||
.\}
|
||||
.br
|
||||
.di
|
||||
.in
|
||||
.ll
|
||||
.gcolor
|
||||
.nr BW \\n(.lu-\\n(.i
|
||||
.nr BH \\n(dn+.5v
|
||||
.ne \\n(BHu+.5v
|
||||
.ie "\\$2"adjust-for-leading-newline" \{\
|
||||
\M[\\$1]\h'1n'\v'+.5v'\D'P \\n(BWu 0 0 \\n(BHu -\\n(BWu 0 0 -\\n(BHu'\M[]
|
||||
.\}
|
||||
.el \{\
|
||||
\M[\\$1]\h'1n'\v'-.5v'\D'P \\n(BWu 0 0 \\n(BHu -\\n(BWu 0 0 -\\n(BHu'\M[]
|
||||
.\}
|
||||
.in 0
|
||||
.sp -.5v
|
||||
.nf
|
||||
.BX
|
||||
.in
|
||||
.sp .5v
|
||||
.fi
|
||||
.\}
|
||||
..
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" BM/EM - put colored marker in margin next to block of text
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.de BM
|
||||
.if t \{\
|
||||
.br
|
||||
.ll -2n
|
||||
.gcolor red
|
||||
.di BX
|
||||
.\}
|
||||
..
|
||||
.de EM
|
||||
.if t \{\
|
||||
.br
|
||||
.di
|
||||
.ll
|
||||
.gcolor
|
||||
.nr BH \\n(dn
|
||||
.ne \\n(BHu
|
||||
\M[\\$1]\D'P -.75n 0 0 \\n(BHu -(\\n[.i]u - \\n(INu - .75n) 0 0 -\\n(BHu'\M[]
|
||||
.in 0
|
||||
.nf
|
||||
.BX
|
||||
.in
|
||||
.fi
|
||||
.\}
|
||||
..
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "Name"
|
||||
csv2ods \- Create OpenDocument spreadsheet from comma separated values
|
||||
.SH "Synopsis"
|
||||
.fam C
|
||||
.HP \w'\fBcsv2ods\fR\ 'u
|
||||
\fBcsv2ods\fR \-i\ \fIfile\&.csv\fR \-o\ \fIfile\&.ods\fR
|
||||
.fam
|
||||
.SH "Description"
|
||||
.PP
|
||||
This program reads a file in CSV format \- table of columns delimited by commas, tabs or any other character\&. It then creates a spreadsheet\&. If a value looks like a number the cell is formatted as a number as well\&.
|
||||
.SH "Options"
|
||||
.PP
|
||||
\-\-version
|
||||
.RS 4
|
||||
Show program\'s version number and exit
|
||||
.RE
|
||||
.PP
|
||||
\-h, \-\-help
|
||||
.RS 4
|
||||
Show help message and exit
|
||||
.RE
|
||||
.PP
|
||||
\-i \fIINPUT\fR, \-\-input=\fIINPUT\fR
|
||||
.RS 4
|
||||
File input in csv\&.
|
||||
.RE
|
||||
.PP
|
||||
\-o \fIOUTPUT\fR, \-\-output=\fIOUTPUT\fR
|
||||
.RS 4
|
||||
File output in ods\&.
|
||||
.RE
|
||||
.PP
|
||||
\-d \fIDELIMITER\fR, \-\-delimiter=\fIDELIMITER\fR
|
||||
.RS 4
|
||||
Specifies a one\-character string to use as the field separator\&. It defaults to ","\&.
|
||||
.RE
|
||||
.PP
|
||||
\-c \fIENCODING\fR, \-\-encoding=\fIENCODING\fR
|
||||
.RS 4
|
||||
Specifies the encoding the file csv\&. It defaults to utf\-8\&.
|
||||
.RE
|
||||
.PP
|
||||
\-t \fITABLENAME\fR, \-\-table=\fITABLENAME\fR
|
||||
.RS 4
|
||||
The table name in the output file\&.
|
||||
.RE
|
||||
.PP
|
||||
\-s \fISKIPINITIALSPACE\fR, \-\-skipinitialspace=\fISKIPINITIALSPACE\fR
|
||||
.RS 4
|
||||
Specifies how to interpret whitespace which immediately follows a delimiter\&. It defaults to False, which means that whitespace immediately following a delimiter is part of the following field\&.
|
||||
.RE
|
||||
.PP
|
||||
\-l \fILINETERMINATOR\fR, \-\-lineterminator=\fILINETERMINATOR\fR
|
||||
.RS 4
|
||||
Specifies the character sequence which should terminate rows\&.
|
||||
.RE
|
||||
.PP
|
||||
\-q \fIQUOTING\fR, \-\-quoting=\fIQUOTING\fR
|
||||
.RS 4
|
||||
It can take on any of the following module constants: 0 = QUOTE_MINIMAL means only when required, for example, when a field contains either the quotechar or the delimiter\&. 1 = QUOTE_ALL means that quotes are always placed around fields\&. 2 = QUOTE_NONNUMERIC means that quotes are always placed around fields which do not parse as integers or floating point numbers\&. 3 = QUOTE_NONE means that quotes are never placed around fields\&. It defaults is QUOTE_MINIMAL\&.
|
||||
.RE
|
||||
.PP
|
||||
\-e \fIESCAPECHAR\fR, \-\-escapechar=\fIESCAPECHAR\fR
|
||||
.RS 4
|
||||
Specifies a one\-character string used to escape the delimiter when quoting is set to QUOTE_NONE\&.
|
||||
.RE
|
||||
.PP
|
||||
\-r \fIQUOTECHAR\fR, \-\-quotechar=\fIQUOTECHAR\fR
|
||||
.RS 4
|
||||
Specifies a one\-character string to use as the quoting character\&. It defaults to "\&.
|
||||
.RE
|
||||
.SH "Example"
|
||||
.sp
|
||||
.if n \{\
|
||||
.RS 4
|
||||
.\}
|
||||
.fam C
|
||||
.ps -1
|
||||
.nf
|
||||
.if t \{\
|
||||
.sp -1
|
||||
.\}
|
||||
.BB lightgray adjust-for-leading-newline
|
||||
.sp -1
|
||||
|
||||
csv2ods \-i /etc/passwd \-o accounts\&.odt \-d:
|
||||
.EB lightgray adjust-for-leading-newline
|
||||
.if t \{\
|
||||
.sp 1
|
||||
.\}
|
||||
.fi
|
||||
.fam
|
||||
.ps +1
|
||||
.if n \{\
|
||||
.RE
|
||||
.\}
|
||||
.SH "Author"
|
||||
.PP
|
||||
\fBAgustin Henze\fR <\&agustinhenze at gmail\&.com\&>
|
||||
.RS 4
|
||||
Original author of csv\-ods\&.py
|
||||
.RE
|
|
@ -0,0 +1,162 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<refentry id="csv2ods">
|
||||
<refentryinfo>
|
||||
<productname>odfpy</productname>
|
||||
<author><firstname>Agustin</firstname><surname>Henze</surname>
|
||||
<contrib>Original author of csv-ods.py</contrib>
|
||||
<email>agustinhenze at gmail.com</email></author>
|
||||
</refentryinfo>
|
||||
<refmeta>
|
||||
<refentrytitle>csv2ods</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
<refmiscinfo class="manual">User commands</refmiscinfo>
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname>csv2ods</refname>
|
||||
<refpurpose>Create OpenDocument spreadsheet from comma separated values</refpurpose>
|
||||
</refnamediv>
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>csv2ods</command>
|
||||
<arg choice="plain">-i <replaceable>file.csv</replaceable></arg>
|
||||
<arg choice="plain">-o <replaceable>file.ods</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
<para>
|
||||
This program reads a file in CSV format - table of columns delimited by commas,
|
||||
tabs or any other character. It then creates a spreadsheet. If a value looks like a number
|
||||
the cell is formatted as a number as well.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>--version</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Show program's version number and exit
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-h, --help</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Show help message and exit
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-i <replaceable>INPUT</replaceable>, --input=<replaceable>INPUT</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
File input in csv.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-o <replaceable>OUTPUT</replaceable>, --output=<replaceable>OUTPUT</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
File output in ods.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-d <replaceable>DELIMITER</replaceable>, --delimiter=<replaceable>DELIMITER</replaceable></term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies a one-character string to use as the field
|
||||
separator. It defaults to ",".
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-c <replaceable>ENCODING</replaceable>, --encoding=<replaceable>ENCODING</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies the encoding the file csv. It defaults to utf-8.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-t <replaceable>TABLENAME</replaceable>, --table=<replaceable>TABLENAME</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The table name in the output file.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-s <replaceable>SKIPINITIALSPACE</replaceable>, --skipinitialspace=<replaceable>SKIPINITIALSPACE</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies how to interpret whitespace which
|
||||
immediately follows a delimiter. It defaults to
|
||||
False, which
|
||||
means that whitespace immediately following a
|
||||
delimiter is part
|
||||
of the following field.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-l <replaceable>LINETERMINATOR</replaceable>, --lineterminator=<replaceable>LINETERMINATOR</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies the character sequence which should
|
||||
terminate rows.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-q <replaceable>QUOTING</replaceable>, --quoting=<replaceable>QUOTING</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
It can take on any of the following module constants:
|
||||
0 = QUOTE_MINIMAL means only when required, for
|
||||
example, when a field contains either the quotechar or
|
||||
the delimiter.
|
||||
1 = QUOTE_ALL means that quotes are always placed
|
||||
around fields.
|
||||
2 = QUOTE_NONNUMERIC means that quotes are always
|
||||
placed around fields which do not parse as integers or
|
||||
floating point numbers.
|
||||
3 = QUOTE_NONE means that quotes are never placed
|
||||
around fields.
|
||||
It defaults is QUOTE_MINIMAL.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-e <replaceable>ESCAPECHAR</replaceable>, --escapechar=<replaceable>ESCAPECHAR</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies a one-character string used to escape the
|
||||
delimiter when quoting is set to QUOTE_NONE.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>-r <replaceable>QUOTECHAR</replaceable>, --quotechar=<replaceable>QUOTECHAR</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Specifies a one-character string to use as the quoting
|
||||
character. It defaults to ".
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect1>
|
||||
<refsect1>
|
||||
<title>Example</title>
|
||||
<screen>
|
||||
csv2ods -i /etc/passwd -o accounts.odt -d:
|
||||
</screen>
|
||||
</refsect1>
|
||||
</refentry>
|
|
@ -0,0 +1,85 @@
|
|||
python-odf (1.3.1+dfsg-1) unstable; urgency=medium
|
||||
|
||||
* New upstream version, which allowed to remove all previous patches.
|
||||
* Set HTML_TIMESTAMP = NO (Closes: #777635).
|
||||
* Added patch which (Closes: #783789).
|
||||
* Remove doc/ in source, because of uglified JS.
|
||||
* Updated watch file.
|
||||
|
||||
-- W. Martin Borgert <debacle@debian.org> Sat, 25 Jul 2015 13:36:45 +0000
|
||||
|
||||
python-odf (1.2.0-6) unstable; urgency=medium
|
||||
|
||||
* fixed a lot of issues due to inconsistencies of the code initially
|
||||
written for Python2, mainly confusions between byte strings
|
||||
and unicode strings. The new code tries to use byte strings for
|
||||
file-like streams and unicode strings for in-memory objects.
|
||||
* added JavaDoc strings to document thoroughly functions and methods,
|
||||
mainly in odf/opendocument.py
|
||||
* added a config.dox file to allow one to build a documentation in HTML
|
||||
and LaTeX, for library developpers and users.
|
||||
* added many assert() clauses to ensure the types of parameters in
|
||||
functions and methods
|
||||
* modified the utilities to make them usable with both Python2 and Python3
|
||||
* implemented a feature announced in csv2ods manfiles but not previously
|
||||
active: -c / --encoding switch to take in account the encoding of
|
||||
the CSV source file.
|
||||
* added rules to build the developer's documentation and install it in
|
||||
usr/share/python-odf/API-doc/html
|
||||
* added a dependency python-odf-doc -> libjs-jquery necessary because
|
||||
of HTML code output by Doxygen
|
||||
|
||||
-- Georges Khaznadar <georgesk@debian.org> Tue, 28 Oct 2014 10:41:32 +0100
|
||||
|
||||
python-odf (1.2.0-5) unstable; urgency=medium
|
||||
|
||||
* fixed a small mistake: the new Standards-Version is 3.9.6
|
||||
* recalled that this upload Closes: #766389
|
||||
|
||||
-- Georges Khaznadar <georgesk@debian.org> Sun, 26 Oct 2014 22:39:40 +0100
|
||||
|
||||
python-odf (1.2.0-3) unstable; urgency=medium
|
||||
|
||||
* added myself to Uploaders
|
||||
* modified the library to work with python3
|
||||
* upgraded Standards-Version to 3.9.5, debhelper to 9
|
||||
* added three new binary packages: python3-odf pythn-odf-tools
|
||||
and python-odf-doc; the last one provides the documentation
|
||||
for Odfpy's API as an opendocument
|
||||
* modified the test routine to run tests with both python 2 and 3.
|
||||
* fixed algorithms which might work with Python2 but were defeated by
|
||||
Python3's unpredictability for order of iterables like dictionaries.
|
||||
* modified the source of "binaries" to work with Python3 and checked
|
||||
their features.
|
||||
|
||||
-- Georges Khaznadar <georgesk@debian.org> Tue, 21 Oct 2014 12:04:55 +0200
|
||||
|
||||
python-odf (1.2.0-2) unstable; urgency=low
|
||||
|
||||
* Build-dep on dh-python (Closes: #764984)
|
||||
* New policy version, no changes
|
||||
|
||||
-- W. Martin Borgert <debacle@debian.org> Sun, 12 Oct 2014 19:59:27 +0000
|
||||
|
||||
python-odf (1.2.0-1) unstable; urgency=low
|
||||
|
||||
* New upstream version (Closes: #763870)
|
||||
* Use improved short and long description by upstream
|
||||
* New policy version, no changes
|
||||
* Moved packaging to git
|
||||
|
||||
-- W. Martin Borgert <debacle@debian.org> Fri, 03 Oct 2014 21:47:40 +0000
|
||||
|
||||
python-odf (0.9.6-2) unstable; urgency=low
|
||||
|
||||
[Jakub Wilk <jwilk@debian.org> Sun, 05 May 2013 16:03:01 +0200]
|
||||
* Use canonical URIs for Vcs-* fields.
|
||||
* New policy version, no changes. Upload to unstable.
|
||||
|
||||
-- W. Martin Borgert <debacle@debian.org> Thu, 09 May 2013 12:57:04 +0000
|
||||
|
||||
python-odf (0.9.6-1) experimental; urgency=low
|
||||
|
||||
* Initial release. (Closes: #484584)
|
||||
|
||||
-- Thomas Bechtold <thomasbechtold@jpberlin.de> Tue, 11 Dec 2012 17:15:17 +0100
|
|
@ -0,0 +1 @@
|
|||
9
|
|
@ -0,0 +1,79 @@
|
|||
Source: python-odf
|
||||
Section: python
|
||||
Priority: optional
|
||||
Maintainer: Debian Python Modules Team <python-modules-team@lists.alioth.debian.org>
|
||||
Uploaders: Thomas Bechtold <thomasbechtold@jpberlin.de>,
|
||||
W. Martin Borgert <debacle@debian.org>,
|
||||
Georges Khaznadar <georgesk@debian.org>
|
||||
Standards-Version: 3.9.6
|
||||
Build-Depends: debhelper (>= 9), python-all, python3-all, xmlto,
|
||||
python-setuptools, dh-python, doxygen, doxypy, graphviz
|
||||
Homepage: https://github.com/eea/odfpy
|
||||
Vcs-Git: git://anonscm.debian.org/python-modules/packages/python-odf.git
|
||||
Vcs-Browser: http://anonscm.debian.org/gitweb/?p=python-modules/packages/python-odf.git
|
||||
|
||||
Package: python-odf
|
||||
Architecture: all
|
||||
Recommends: python-odf-doc, python-odf-tools
|
||||
Depends: ${misc:Depends}, ${python:Depends}
|
||||
Description: Python API and tools to manipulate OpenDocument files
|
||||
Odfpy is a library to read and write OpenDocument v. 1.1 files.
|
||||
The main focus has been to prevent the programmer from creating invalid
|
||||
documents. It has checks that raise an exception if the programmer adds
|
||||
an invalid element, adds an attribute unknown to the grammar, forgets to
|
||||
add a required attribute or adds text to an element that doesn't allow it.
|
||||
.
|
||||
These checks and the API itself were generated from the RelaxNG
|
||||
schema, and then hand-edited. Therefore the API is complete and can
|
||||
handle all ODF constructions.
|
||||
|
||||
Package: python-odf-tools
|
||||
Architecture: all
|
||||
Conflicts: python-odf (<< 1.2.0-3)
|
||||
Depends: ${misc:Depends}, ${python:Depends}, python3-odf
|
||||
Description: Python API and tools to manipulate OpenDocument files
|
||||
Odfpy is a library to read and write OpenDocument v. 1.1 files.
|
||||
The main focus has been to prevent the programmer from creating invalid
|
||||
documents. It has checks that raise an exception if the programmer adds
|
||||
an invalid element, adds an attribute unknown to the grammar, forgets to
|
||||
add a required attribute or adds text to an element that doesn't allow it.
|
||||
.
|
||||
These checks and the API itself were generated from the RelaxNG
|
||||
schema, and then hand-edited. Therefore the API is complete and can
|
||||
handle all ODF constructions.
|
||||
|
||||
Package: python3-odf
|
||||
Architecture: all
|
||||
Recommends: python-odf-doc, python-odf-tools
|
||||
Depends: ${misc:Depends}, ${python:Depends}, python3
|
||||
Description: Python API and tools to manipulate OpenDocument files
|
||||
Odfpy is a library to read and write OpenDocument v. 1.1 files.
|
||||
The main focus has been to prevent the programmer from creating invalid
|
||||
documents. It has checks that raise an exception if the programmer adds
|
||||
an invalid element, adds an attribute unknown to the grammar, forgets to
|
||||
add a required attribute or adds text to an element that doesn't allow it.
|
||||
.
|
||||
These checks and the API itself were generated from the RelaxNG
|
||||
schema, and then hand-edited. Therefore the API is complete and can
|
||||
handle all ODF constructions.
|
||||
.
|
||||
In addition to the API, there are a few scripts:
|
||||
.
|
||||
- csv2ods - Create OpenDocument spreadsheet from comma separated values
|
||||
- mailodf - Email ODF file as HTML archive
|
||||
- odf2xhtml - Convert ODF to (X)HTML
|
||||
- odf2mht - Convert ODF to HTML archive
|
||||
- odf2xml - Create OpenDocument XML file from OD? package
|
||||
- odfimgimport - Import external images
|
||||
- odflint - Check ODF file for problems
|
||||
- odfmeta - List or change the metadata of an ODF file
|
||||
- odfoutline - Show outline of OpenDocument
|
||||
- odfuserfield - List or change the user-field declarations in an ODF file
|
||||
- xml2odf - Create OD? package from OpenDocument in XML form
|
||||
|
||||
Package: python-odf-doc
|
||||
Architecture: all
|
||||
Section: doc
|
||||
Depends: ${misc:Depends}, libjs-jquery
|
||||
Description: documentation and examples for python-odf and python3-odf
|
||||
Odfpy is a library to read and write OpenDocument v. 1.1 files.
|
|
@ -0,0 +1,105 @@
|
|||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: odfpy
|
||||
Source: https://joinup.ec.europa.eu/software/odfpy/home
|
||||
|
||||
Files: *
|
||||
Copyright: 2006-2009 Søren Roug, European Environment Agency
|
||||
License: GPL-2+ and Apache-2
|
||||
|
||||
Files: csv2ods/*
|
||||
Copyright: 2008 Agustin Henze <agustinhenze@gmail.com>
|
||||
License: GPL-2+ and Apache-2
|
||||
|
||||
Files: examples/easylists.py
|
||||
Copyright: 2008 J. David Eisenberg
|
||||
License: GPL-2+
|
||||
|
||||
Files: examples/ods-currency.py
|
||||
Copyright: 2009 Brad Ralph
|
||||
License: GPL-2+ and Apache-2
|
||||
|
||||
Files: contrib/gutenberg/*
|
||||
Copyright: 2007 Søren Roug, European Environment Agency
|
||||
License: LGPL-2.1+
|
||||
|
||||
Files: contrib/xliff/*
|
||||
Copyright: 2000-2004 Juan David Ibáñez Palomar
|
||||
2003 Roberto Quero, Eduardo Corrales
|
||||
2004 Søren Roug
|
||||
License: GPL-2+
|
||||
|
||||
Files: odf/*
|
||||
Copyright: 2006-2009 Søren Roug, European Environment Agency
|
||||
License: LGPL-2.1+
|
||||
|
||||
Files: odf/easyliststyle.py odf/teletype.py
|
||||
Copyright: 2008 J. David Eisenberg
|
||||
License: GPL-2+
|
||||
|
||||
Files: odf/__init__.py odf/userfield.py
|
||||
Copyright: 2006-2009 Søren Roug, European Environment Agency
|
||||
License: GPL-2+ and Apache-2
|
||||
|
||||
Files: odf/thumbnail.py
|
||||
Copyright: The Document Foundation
|
||||
License: CC-BY-SA-3.0
|
||||
|
||||
License: CC-BY-SA-3.0
|
||||
You are free:
|
||||
to Share (to copy, distribute and transmit the work) and
|
||||
to Remix (to adapt the work) under the following conditions:
|
||||
.
|
||||
Attribution — You must attribute the work in the manner specified by the
|
||||
author or licensor (but not in any way that suggests that they endorse you
|
||||
or your use of the work).
|
||||
.
|
||||
Share Alike — If you alter, transform, or build upon this work, you may
|
||||
distribute the resulting work only under the same, similar or a compatible
|
||||
license.
|
||||
.
|
||||
For more information, see http://creativecommons.org/licenses/by-sa/3.0/
|
||||
|
||||
License: Apache-2
|
||||
On Debian systems, the full text of the Apache
|
||||
License version 2 can be found in the file
|
||||
`/usr/share/common-licenses/Apache-2.0'.
|
||||
|
||||
License: LGPL-2.1+
|
||||
This package is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this package; 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 Lesser General
|
||||
Public License can be found in `/usr/share/common-licenses/LGPL-2'.
|
||||
|
||||
License: GPL-2+
|
||||
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 package; if not, write to the Free
|
||||
Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
||||
Boston, MA 02110-1301 USA
|
||||
.
|
||||
On Debian systems, the full text of the GNU General Public
|
||||
License version 2 can be found in the file
|
||||
`/usr/share/common-licenses/GPL-2'.
|
|
@ -0,0 +1,19 @@
|
|||
Description: Fixes loading of Chinese ODS file
|
||||
Author: W. Martin Borgert <debacle@debian.org>
|
||||
Origin: vendor
|
||||
Bug: https://github.com/eea/odfpy/issues/19
|
||||
Bug-Debian: https://bugs.debian.org/783789
|
||||
Last-Update: 2015-07-25
|
||||
---
|
||||
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
|
||||
--- a/odf/attrconverters.py
|
||||
+++ b/odf/attrconverters.py
|
||||
@@ -103,7 +103,7 @@
|
||||
def __save_prefix(attribute, arg, element):
|
||||
prefix = arg.split(':',1)[0]
|
||||
if prefix == arg:
|
||||
- return str(arg)
|
||||
+ return arg
|
||||
namespace = element.get_knownns(prefix)
|
||||
if namespace is None:
|
||||
#raise ValueError( "'%s' is an unknown prefix" % str(prefix))
|
|
@ -0,0 +1,19 @@
|
|||
Description: unset HTML_TIMESTAMP for reproducible builds
|
||||
Author: W. Martin Borgert <debacle@debian.org>
|
||||
Origin: vendor
|
||||
Bug: https://github.com/eea/odfpy/issues/20
|
||||
Bug-Debian: https://bugs.debian.org/777635
|
||||
Last-Update: 2015-07-25
|
||||
---
|
||||
This patch header follows DEP-3: http://dep.debian.net/deps/dep3/
|
||||
--- a/config.dox
|
||||
+++ b/config.dox
|
||||
@@ -1127,7 +1127,7 @@
|
||||
# The default value is: YES.
|
||||
# This tag requires that the tag GENERATE_HTML is set to YES.
|
||||
|
||||
-HTML_TIMESTAMP = YES
|
||||
+HTML_TIMESTAMP = NO
|
||||
|
||||
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
|
||||
# documentation will contain sections that can be hidden and shown after the
|
|
@ -0,0 +1,2 @@
|
|||
no_html_timestamp.patch
|
||||
fix_chinese_ods.patch
|
|
@ -0,0 +1,3 @@
|
|||
api-for-odfpy.odt usr/share/python-odf
|
||||
examples usr/share/python-odf
|
||||
doc/html usr/share/python-odf/API-doc
|
|
@ -0,0 +1,2 @@
|
|||
debian/python3-odfpy/usr/share usr
|
||||
debian/python3-odfpy/usr/bin usr
|
|
@ -0,0 +1 @@
|
|||
debian/python-odfpy/usr/lib usr
|
|
@ -0,0 +1 @@
|
|||
debian/python3-odfpy/usr/lib usr
|
|
@ -0,0 +1,45 @@
|
|||
#!/usr/bin/make -f
|
||||
|
||||
#DH_VERBOSE=1
|
||||
|
||||
export PYBUILD_NAME=odfpy
|
||||
PYTHON2=$(shell pyversions -vr)
|
||||
|
||||
%:
|
||||
dh $@ --buildsystem=pybuild --with python2 --with python3
|
||||
|
||||
ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS)))
|
||||
test-python%:
|
||||
cd tests; \
|
||||
PYTHONPATH=../`python$* -c "import sys; print ':'.join(sys.path)"`; \
|
||||
for F in `ls test*.py` ; do \
|
||||
PYTHONPATH=$$PYTHONPATH python$* $$F; \
|
||||
done
|
||||
|
||||
override_dh_auto_test: $(PYTHON2:%=test-python%)
|
||||
endif
|
||||
|
||||
UTILITIES = csv2ods mailodf odf2xhtml odf2mht odf2xml odfimgimport \
|
||||
odflint odfmeta odfoutline odfuserfield xml2odf
|
||||
|
||||
override_dh_clean:
|
||||
# clean directories used for utilities
|
||||
for D in $(UTILITIES); do make -C $$D clean; done
|
||||
# remove build space
|
||||
rm -rf build
|
||||
# remove generated symlinks
|
||||
find . -name odf -type l | xargs rm -f
|
||||
# remove documentation made by Doxygen
|
||||
rm -rf doc
|
||||
dh_clean
|
||||
|
||||
override_dh_auto_build:
|
||||
for D in $(UTILITIES); do make -C $$D; done
|
||||
doxygen config.dox
|
||||
dh_auto_build
|
||||
|
||||
override_dh_install:
|
||||
dh_install
|
||||
# remove an embedded JS library
|
||||
f=debian/python-odf-doc/usr/share/python-odf/API-doc/html/jquery.js; \
|
||||
[ -e $$f ] && rm $$f && ln -s /usr/share/javascript/jquery/jquery.js $$f
|
|
@ -0,0 +1 @@
|
|||
3.0 (quilt)
|
|
@ -0,0 +1,3 @@
|
|||
# example file to run tests: an odf file with
|
||||
# an image as a hyperlink
|
||||
odfimgimport/textWithImages.odt
|
|
@ -0,0 +1,3 @@
|
|||
version=3
|
||||
opts=dversionmangle=s/\+(debian|dfsg|ds|deb)(\.\d+)?$// \
|
||||
https://github.com/eea/odfpy/releases /eea/odfpy/archive/release-(.+)\.tar\.gz
|
|
@ -0,0 +1,148 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
# This is an example of an OpenDocument Chart.
|
||||
#
|
||||
# Opendocument charts are usually not found in the wild. They are intended to be
|
||||
# subobojects of e.g. spreadsheets. But the KDE application called kchart
|
||||
# (http://www.koffice.org/kchart/) is able to read and write ODC files.
|
||||
#
|
||||
# Kchart is able to understand a document without <chart:series>, whereas
|
||||
# OOo misinterprets the label rows and columns. So if you embed the
|
||||
# spectre-balance.odc file in an OOo Writer document, expect to see some
|
||||
# oddities.
|
||||
|
||||
from odf.opendocument import OpenDocumentChart
|
||||
from odf import chart, style, table, text
|
||||
|
||||
# import a support class from the examples directory
|
||||
from datatable import DataTable
|
||||
|
||||
class BarChart(object):
|
||||
|
||||
def __init__(self):
|
||||
self.charttype = 'chart:bar'
|
||||
self.subtype = 'normal' # 'percentage', 'stacked' or 'normal'
|
||||
self.threedimensional = "true"
|
||||
self.x_axis = "X"
|
||||
self.y_axis = "Y"
|
||||
self.values = (1,2,3)
|
||||
self.title = None
|
||||
self.subtitle = None
|
||||
|
||||
def __call__(self, doc):
|
||||
chartstyle = style.Style(name="chartstyle", family="chart")
|
||||
chartstyle.addElement( style.GraphicProperties(stroke="none", fillcolor="#ffffff"))
|
||||
doc.automaticstyles.addElement(chartstyle)
|
||||
|
||||
mychart = chart.Chart( width="576pt", height="504pt", stylename=chartstyle, attributes={'class':self.charttype})
|
||||
doc.chart.addElement(mychart)
|
||||
|
||||
# Title
|
||||
if self.title:
|
||||
titlestyle = style.Style(name="titlestyle", family="chart")
|
||||
titlestyle.addElement( style.GraphicProperties(stroke="none", fill="none"))
|
||||
titlestyle.addElement( style.TextProperties(fontfamily="'Nimbus Sans L'",
|
||||
fontfamilygeneric="swiss", fontpitch="variable", fontsize="13pt"))
|
||||
doc.automaticstyles.addElement(titlestyle)
|
||||
|
||||
mytitle = chart.Title(x="385pt", y="27pt", stylename=titlestyle)
|
||||
mytitle.addElement( text.P(text=self.title))
|
||||
mychart.addElement(mytitle)
|
||||
|
||||
# Subtitle
|
||||
if self.subtitle:
|
||||
subtitlestyle = style.Style(name="subtitlestyle", family="chart")
|
||||
subtitlestyle.addElement( style.GraphicProperties(stroke="none", fill="none"))
|
||||
subtitlestyle.addElement( style.TextProperties(fontfamily="'Nimbus Sans L'",
|
||||
fontfamilygeneric="swiss", fontpitch="variable", fontsize="10pt"))
|
||||
doc.automaticstyles.addElement(subtitlestyle)
|
||||
|
||||
subtitle = chart.Subtitle(x="0pt", y="123pt", stylename=subtitlestyle)
|
||||
subtitle.addElement( text.P(text= self.subtitle))
|
||||
mychart.addElement(subtitle)
|
||||
|
||||
# Legend
|
||||
legendstyle = style.Style(name="legendstyle", family="chart")
|
||||
legendstyle.addElement( style.GraphicProperties(fill="none"))
|
||||
legendstyle.addElement( style.TextProperties(fontfamily="'Nimbus Sans L'",
|
||||
fontfamilygeneric="swiss", fontpitch="variable", fontsize="6pt"))
|
||||
doc.automaticstyles.addElement(legendstyle)
|
||||
|
||||
mylegend = chart.Legend(legendposition="end", legendalign="center", stylename=legendstyle)
|
||||
mychart.addElement(mylegend)
|
||||
|
||||
# Plot area
|
||||
plotstyle = style.Style(name="plotstyle", family="chart")
|
||||
if self.subtype == "stacked": percentage="false"; stacked="true"
|
||||
elif self.subtype == "percentage": percentage="true"; stacked="false"
|
||||
else: percentage="false"; stacked="false"
|
||||
plotstyle.addElement( style.ChartProperties(seriessource="columns",
|
||||
percentage=percentage, stacked=stacked,
|
||||
threedimensional=self.threedimensional))
|
||||
doc.automaticstyles.addElement(plotstyle)
|
||||
|
||||
plotarea = chart.PlotArea(datasourcehaslabels=self.datasourcehaslabels, stylename=plotstyle)
|
||||
mychart.addElement(plotarea)
|
||||
|
||||
# Style for the X,Y axes
|
||||
axisstyle = style.Style(name="axisstyle", family="chart")
|
||||
axisstyle.addElement( style.ChartProperties(displaylabel="true"))
|
||||
doc.automaticstyles.addElement(axisstyle)
|
||||
|
||||
# Title for the X axis
|
||||
xaxis = chart.Axis(dimension="x", name="primary-x", stylename=axisstyle)
|
||||
plotarea.addElement(xaxis)
|
||||
xt = chart.Title()
|
||||
xaxis.addElement(xt)
|
||||
xt.addElement(text.P(text=self.x_axis))
|
||||
|
||||
# Title for the Y axis
|
||||
yaxis = chart.Axis(dimension="y", name="primary-y", stylename=axisstyle)
|
||||
plotarea.addElement(yaxis)
|
||||
yt = chart.Title()
|
||||
yaxis.addElement(yt)
|
||||
yt.addElement(text.P(text=self.y_axis))
|
||||
|
||||
# Data area
|
||||
datatable = DataTable( self.values )
|
||||
datatable.datasourcehaslabels = self.datasourcehaslabels
|
||||
mychart.addElement(datatable())
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Create the document
|
||||
doc = OpenDocumentChart()
|
||||
mychart = BarChart()
|
||||
mychart.title = "SPECTRE"
|
||||
mychart.subtitle = "SPecial Executive for Counter-intelligence, Terrorism, Revenge and Extortion"
|
||||
mychart.x_axis = u"Divisions"
|
||||
mychart.y_axis = u"€ (thousand)"
|
||||
# These represent the data. Six rows in three columns
|
||||
mychart.values = (
|
||||
('', 'Expense', 'Revenue'),
|
||||
('Counterfeit', 1000, 1500),
|
||||
('Murder', 1100, 1150),
|
||||
('Prostitution', 3200, 2350),
|
||||
('Blackmail', 1100, 1150),
|
||||
('Larceny', 1000, 1750)
|
||||
)
|
||||
mychart.datasourcehaslabels = "both"
|
||||
mychart(doc)
|
||||
doc.save("spectre-balance", True)
|
Binary file not shown.
|
@ -0,0 +1,94 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
# Copyright (C) 2007 Søren Roug, European Environment Agency
|
||||
#
|
||||
# This is free software. You may redistribute it under the terms
|
||||
# of the Apache license and the GNU General Public License Version
|
||||
# 2 or at your option any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public
|
||||
# License along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
#
|
||||
# Contributor(s):
|
||||
#
|
||||
|
||||
from odf import table, text
|
||||
|
||||
def valuetype(val):
|
||||
valuetype="string"
|
||||
if isinstance(val,str): valuetype="string"
|
||||
if isinstance(val,int): valuetype="float"
|
||||
if isinstance(val,float): valuetype="float"
|
||||
if isinstance(val,bool): valuetype="boolean"
|
||||
return valuetype
|
||||
|
||||
class DataTable(object):
|
||||
|
||||
def __init__(self, values=()):
|
||||
self.values = values
|
||||
self.datasourcehaslabels = "none"
|
||||
|
||||
def _set_values(self, value):
|
||||
if isinstance(value, list) or isinstance(value, tuple):
|
||||
self.__dict__['values'] = value
|
||||
firstrow = value[0]
|
||||
if isinstance(firstrow, list) or isinstance(firstrow, tuple):
|
||||
self.numcols = len(firstrow)
|
||||
else:
|
||||
self.numcols = 1
|
||||
else:
|
||||
raise ValueError, "Value must be list or tuple"
|
||||
|
||||
def __setattr__(self, name, value):
|
||||
if name == 'values':
|
||||
self._set_values(value)
|
||||
else:
|
||||
self.__dict__[name] = value
|
||||
|
||||
def __call__(self):
|
||||
datatable = table.Table(name="local-table")
|
||||
if self.datasourcehaslabels in ('row','both'):
|
||||
t = table.TableHeaderColumns()
|
||||
t.addElement(table.TableColumn())
|
||||
datatable.addElement(t)
|
||||
|
||||
t = table.TableColumns()
|
||||
if self.datasourcehaslabels in ('row','both'):
|
||||
t.addElement(table.TableColumn(numbercolumnsrepeated=str(self.numcols-1)))
|
||||
else:
|
||||
t.addElement(table.TableColumn(numbercolumnsrepeated=str(self.numcols)))
|
||||
datatable.addElement(t)
|
||||
|
||||
if self.datasourcehaslabels in ('column','both'):
|
||||
t = table.TableHeaderRows()
|
||||
datatable.addElement(t)
|
||||
tr = table.TableRow()
|
||||
t.addElement(tr)
|
||||
content = self.values[0]
|
||||
for val in content:
|
||||
tc = table.TableCell(valuetype=valuetype(val))
|
||||
tr.addElement(tc)
|
||||
tc.addElement(text.P(text=str(val)))
|
||||
|
||||
t = table.TableRows()
|
||||
datatable.addElement(t)
|
||||
rownum = 0
|
||||
for content in self.values:
|
||||
if rownum == 0 and self.datasourcehaslabels in ('column','both'):
|
||||
rownum += 1
|
||||
continue
|
||||
tr = table.TableRow()
|
||||
t.addElement(tr)
|
||||
for val in content:
|
||||
tc = table.TableCell(valuetype=valuetype(val), value=val)
|
||||
tr.addElement(tc)
|
||||
tc.addElement(text.P(text=str(val)))
|
||||
rownum += 1
|
||||
return datatable
|
||||
|
|
@ -0,0 +1,122 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Show the easyliststyle.py module
|
||||
# Copyright (C) 2008 J. David Eisenberg
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License along
|
||||
# with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
from odf import easyliststyle
|
||||
from odf.opendocument import OpenDocumentText
|
||||
from odf.style import Style, TextProperties
|
||||
from odf.text import P, List, ListItem
|
||||
|
||||
"""
|
||||
This program shows the easyliststyle.py module.
|
||||
It creates a file named "easylist_odfpy.odt"
|
||||
with a bulleted list, a numbered list, and a
|
||||
mixed list.
|
||||
"""
|
||||
|
||||
bulletListSpec = '*,>,#,%'
|
||||
mixedListSpec = u'1.!\u273f!a)'
|
||||
numberListSpecArray = ('I', '1:', 'a')
|
||||
|
||||
itemList = (
|
||||
"Cats",
|
||||
">Domestic Shorthair",
|
||||
">Domestic Longhair",
|
||||
">Purebred",
|
||||
">>Russian Blue",
|
||||
">>Siamese",
|
||||
">>>Seal Point",
|
||||
">>>Flame Point",
|
||||
"Dogs",
|
||||
">Retrievers",
|
||||
">>Golden Retriever",
|
||||
">>Labrador Retriever",
|
||||
">Poodles",
|
||||
">>Toy Poodle",
|
||||
">>Standard Poodle"
|
||||
)
|
||||
|
||||
def createList(itemList, indentDelim, styleName):
|
||||
listArray = []
|
||||
listItem = ListItem()
|
||||
level = 0
|
||||
lastLevel = 0
|
||||
|
||||
for levCount in range(0,10):
|
||||
listArray.append(None)
|
||||
listArray[0] = List()
|
||||
|
||||
for item in itemList:
|
||||
level = 0;
|
||||
while (level < len(item) and item[level] == indentDelim):
|
||||
level +=1
|
||||
item = item[level:]
|
||||
|
||||
if (level > lastLevel): # open the sub-levels
|
||||
for levCount in range(lastLevel+1, level+1):
|
||||
listArray[levCount] = List()
|
||||
elif (level < lastLevel): # close off the intervening lists
|
||||
for levCount in range(lastLevel, level, -1):
|
||||
listArray[levCount-1].childNodes[-1].addElement(listArray[levCount])
|
||||
|
||||
# now that we are at the proper level, add the item.
|
||||
listArray[level].setAttribute( 'stylename', styleName );
|
||||
listItem = ListItem()
|
||||
para = P(text=item);
|
||||
listItem.addElement(para);
|
||||
listArray[level].addElement(listItem);
|
||||
lastLevel = level;
|
||||
|
||||
# close off any remaining open lists
|
||||
for levCount in range(lastLevel, 0, -1):
|
||||
listArray[levCount-1].childNodes[-1].addElement(listArray[levCount])
|
||||
return listArray[0]
|
||||
|
||||
textdoc = OpenDocumentText()
|
||||
|
||||
s = textdoc.styles
|
||||
listStyle = easyliststyle.styleFromString('bullet1', bulletListSpec,
|
||||
',', '0.6cm', easyliststyle.SHOW_ONE_LEVEL)
|
||||
s.addElement(listStyle)
|
||||
|
||||
listElement = createList(itemList, '>', 'bullet1')
|
||||
textdoc.text.addElement(listElement)
|
||||
|
||||
para = P(text="-----------------------");
|
||||
textdoc.text.addElement(para)
|
||||
|
||||
listStyle = easyliststyle.styleFromList('num1', numberListSpecArray,
|
||||
'0.25in', easyliststyle.SHOW_ALL_LEVELS)
|
||||
s.addElement(listStyle)
|
||||
|
||||
listElement = createList(itemList, '>', 'num1')
|
||||
textdoc.text.addElement(listElement)
|
||||
|
||||
para = P(text="-----------------------");
|
||||
textdoc.text.addElement(para)
|
||||
|
||||
listStyle = easyliststyle.styleFromString('mix1', mixedListSpec,
|
||||
'!', '0.8cm', easyliststyle.SHOW_ONE_LEVEL)
|
||||
s.addElement(listStyle)
|
||||
|
||||
listElement = createList(itemList, '>', 'mix1')
|
||||
textdoc.text.addElement(listElement)
|
||||
|
||||
textdoc.save("easylist_odfpy.odt")
|
||||
|
||||
# vim: set expandtab sw=4 :
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue