2 # -*- coding: iso-8859-1 -*-
4 # Based on sample.py,v 4.1.2.6 2006/04/14 13:59:26 cvs Exp
6 # Copyright (C) 2009 Stefan Merten
8 # xml2rst.py is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published
10 # by the Free Software Foundation; either version 2 of the License,
11 # or (at your option) any later version.
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # General Public License for more details.
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
24 Convert a docutils XML file to reStructuredText syntax.
36 xml2rst.py -- convert a docutils XML file to reStructuredText syntax
40 B<xml2rst.py> [B<-v>] I<xml> [I<reST>]
42 B<xml2rst.py> B<--help>
46 Converts a docutils XML input file to reStructuredText source.
48 This can be used to transform another format to reStructuredText given you have
49 a transformation to docutils XML.
54 ###############################################################################
55 ###############################################################################
62 from optparse
import OptionParser
, OptionGroup
, OptionValueError
, Option
64 from rst
import rst_xslt
66 ###############################################################################
67 ###############################################################################
71 @var options: Options given on the command line
72 @type options: optparse.Values
76 ###############################################################################
77 ###############################################################################
82 @param pod: Snippet in POD format to be analyzed.
85 @return: String of first `=headX' entry in POD snippet or empty string if
89 for line
in pod
.split("\n"):
90 if line
.startswith("=head"):
91 return line
[len("=headX"):].strip()
94 ###############################################################################
96 def pod2Description(pod
):
98 @param pod: Snippet in POD format to be analyzed.
101 @return: Stripped text from all lines not being a POD line command.
105 for line
in pod
.split("\n"):
106 if not line
.startswith("="):
107 result
= result
.strip() + " " + line
.strip()
108 return result
.strip()
110 ###############################################################################
112 def pod2OptionList(pod
):
114 Return option names found in POD snippet. Option names are recognized in
115 `=item B<option>' constructs.
117 @param pod: Snippet in POD format to be analyzed.
120 @return: All option names contained in POD snippet as a list.
121 @rtype: [ str, ..., ]
124 for line
in pod
.split("\n"):
125 found
= re
.search("^=item\s*B<(-[^>]+)>", line
)
127 result
.append(found
.group(1))
130 ###############################################################################
132 def pod2OptionKeywords(pod
):
134 Return a dict mapping `OptionParser.add_option' keywords to values found in
137 @param pod: Snippet in POD format to be analyzed.
140 @return: Mapping for all values found. Currently `help' and `dest' are
142 @rtype: { keyword: value, ..., }
144 result
= { 'help': "", }
145 for line
in pod
.split("\n"):
146 if line
.startswith("=cut"):
148 found
= re
.search("^=item\s*B<--?([^>]+)>(?:=|\s*)", line
)
151 optionName
= found
.group(1)
152 found
= re
.search("I<([^>]+)>", line
)
154 result
['dest'] = found
.group(1)
155 elif len(optionName
) > 1:
156 result
['dest'] = optionName
158 result
['help'] += line
+ "\n"
159 result
['help'] = result
['help'].strip()
160 if result
.has_key('dest'):
161 result
['dest'] = result
['dest'].replace("-", "_")
163 errorExit(1, ( "Internal error: Missing `dest' in documentation string:",
167 ###############################################################################
169 def pod2Argument(pod
):
171 Return a list of two strings for `OptionGroup.__init__' describing the
172 argument found in POD snippet.
174 @param pod: Snippet in POD format to be analyzed.
177 @return: Name of the argument and its description.
178 @rtype: [ argument, description, ]
182 for line
in pod
.split("\n"):
183 if line
.startswith("=cut"):
185 found
= re
.search("^=item\s*I<([^>]+)>", line
)
188 argument
= found
.group(1)
190 description
+= line
+ "\n"
191 description
= description
.strip()
192 return [ argument
, description
, ]
194 ###############################################################################
198 Sets options and returns arguments.
200 @return: Name of input file and optionally of output file.
201 @rtype: ( str, [str,] )
210 optionParser
= OptionParser("usage: %prog [option]... <xml> [<rst>]")
214 =head2 General options
220 generalGroup
= OptionGroup(optionParser
, pod2Head(pod
),
221 pod2Description(pod
))
225 =item B<-a> I<adornment>
227 =item B<--adornment>=I<adornment>
229 Configures title markup to use so different styles can be requested
232 The value of the parameter must be a string made up of a sequence of
233 character pairs. The first character of a pair is C<o> (overline) or
234 C<u> (underline) and the second character is the character to use for
237 The first and the second character pair is used for document title and
238 subtitle, the following pairs are used for section titles where the
239 third pair is used for the top level section title.
241 Defaults to C<o=o-u=u-u~u:u.u`>.
245 generalGroup
.add_option(default
=None, *pod2OptionList(pod
),
246 **pod2OptionKeywords(pod
))
252 =item B<--fold>=I<fold>
254 Configures whether long text lines in paragraphs should be folded and
255 to which length. This option is for input not coming from reST which
256 may have no internal line feeds in plain text strings.
258 If folding is enabled text strings not in a line feed preserving
259 context are first white-space normalized and then broken according to
260 the folding rules. Folding rules put out the first word and continue
261 to do so with the following words unless the next word would cross
262 the folding boundary. Words are delimited by white-space.
264 Defaults to C<0>, i.e. no folding.
268 generalGroup
.add_option(type="int", default
=None,
269 *pod2OptionList(pod
), **pod2OptionKeywords(pod
))
281 generalGroup
.add_option(action
="store_true",
282 *pod2OptionList(pod
), **pod2OptionKeywords(pod
))
283 optionParser
.add_option_group(generalGroup
)
295 argumentGroup
= OptionGroup(optionParser
, pod2Head(pod
),
296 pod2Description(pod
))
297 optionParser
.add_option_group(argumentGroup
)
303 The XML input file containing docutils XML.
308 argument1Group
= OptionGroup(optionParser
, *pod2Argument(pod
))
309 optionParser
.add_option_group(argument1Group
)
315 The optional output file containing reStructuredText.
317 If not given output is put to C<STDOUT>.
321 argument2Group
= OptionGroup(optionParser
, *pod2Argument(pod
))
322 optionParser
.add_option_group(argument2Group
)
330 ( options
, args
, ) = optionParser
.parse_args()
333 optionParser
.error("An input file is required")
335 optionParser
.error("At most two arguments are allowed")
336 if (options
.adornment
is not None
337 and re
.search('^([ou][]!"#$%&\'()*+,\-./:;<=>?@[\\^_`{|}~])+$',
338 options
.adornment
) is None):
339 optionParser
.error("Invalid adornment string given")
343 ###############################################################################
347 Outputs messages as error.
349 @param lines: Messages to be output as single lines.
350 @type lines: ( str, ..., )
355 scriptName
= os
.path
.basename(sys
.argv
[0])
357 print >>sys
.stderr
, ("%s: %s" % ( scriptName
, line
, ))
360 ###############################################################################
362 def verboseOut(lines
):
364 Outputs messages as a verbose message.
366 @param lines: Messages to be output as single lines.
367 @type lines: ( str, ..., )
373 errorOut([ "## " + line
377 ###############################################################################
379 def errorExit(code
, lines
):
381 Exit program with an error message.
383 @param code: Exit Code to use.
386 @param lines: Strings to output as error message.
387 @type lines: ( str, ..., )
389 @return: Does not return.
394 ###############################################################################
395 ###############################################################################
396 # Specialized functions
398 ###############################################################################
399 ###############################################################################
402 ########################################################################
403 ##############################################################################
406 if __name__
== '__main__':
407 arguments
= parseOptions()
409 if len(arguments
) > 1:
414 rst_xslt
.convert(inF
, outF
, options
)
418 ##############################################################################
419 ##############################################################################
421 # TODO Accept additional XSLT sheets to create a transformation pipeline
423 # TODO Move from XSLT to Python implementation step by step by replacing
424 # XSLT-code by Python code through extensions and other means
427 # TODO The docutils XML reader must be used