Fix a regression in [r8062] (extra space with French smartquotes again).
[docutils.git] / sandbox / rst2wordml / docutils_wordml.py
blob98db510adae8f8d2ed9c3e930ca7405cd8b349eb
1 # Authors: Jay Kint
2 # Contact: bilbo@hobbit-hole.org
3 # Revision: $Revision$
4 # Date: $Date$
5 # Copyright: This module is copyright 2007 by Jay Kint, licensed under the BSD License.
7 """
8 WordML writer for Docutils. WordML is the XML format for MS Word documents.
10 The output conforms to basic WordML and can be read by MS Word to be output in any of the formats it supports
11 (i.e. PDF).
13 The way it works is that it uses a template file *(default template.xml)* and looks for the <w:rest /> node
14 for where to insert the generated WordML. This allows you to save a preformatted template with the formatting
15 you want (e.g., styles, fonts, paper size).
17 Known bugs:
19 - Mixing bulleted lists and enumerated lists doesn't work quite the same way that MS Word does it. It works,
20 but the output isn't the same as if you'd typed it in Word.
22 - You can't mix paper types. That stands to reason, but it's still a limitation.
24 - Titles and subtitles are only allowed up to 3 levels for now.
26 Of course, there's nothing to prevent you from loading up the generated file and
27 fixing these things yourself in MS Word.
29 """
31 __docformat__ = 'reStructuredText'
33 import sys
34 import os
35 import docutils
36 from docutils import frontend, writers, nodes, utils, languages
37 import xml.parsers.expat
38 from xml.etree.ElementTree import TreeBuilder, dump, tostring
39 import copy
40 try:
41 import Image
42 except ImportError:
43 Image = None
45 class Writer(writers.Writer):
47 supported = ('wordml',)
48 """Formats this writer supports."""
50 default_template = 'template.xml'
52 default_template_path = utils.relative_path(
53 os.path.join(os.getcwd(), 'dummy'),
54 os.path.join(os.path.dirname(__file__), default_template))
56 settings_spec = (
57 '"Docutils WordML" Writer Options',
58 None,
59 (('Specify the template file (UTF-8 encoded). Default is "%s".'
60 % default_template_path,
61 ['--template'],
62 {'default': default_template_path, 'metavar': '<file>'}),))
64 settings_defaults = {'output-encoding-error-handler': 'xmlcharrefreplace'}
66 config_section = 'docutils_wordml writer'
67 config_section_dependencies = ('writers',)
69 def __init__(self):
70 writers.Writer.__init__(self)
71 self.translator_class = WordMLTranslator
73 def translate(self):
74 self.visitor = visitor = self.translator_class(self.document)
75 self.document.walkabout(visitor)
76 self.output = visitor.astext()
79 class TextNoEncoding(nodes.Text):
81 """A text node that is meant to take its contents literally and not
82 have it encoded."""
84 def __init__( self, data, rawsource=''):
85 nodes.Text.__init__( self, data, rawsource )
88 class TextWithStyle( nodes.Text ):
90 """A text node that has an attached style."""
92 def __init__( self, data, style, rawsource='' ):
93 nodes.Text.__init__( self, data, rawsource )
94 self.style = style
96 # contain an xml tag within a region (with styles if needed)
97 class XMLRegion( nodes.General, nodes.Element ): pass
100 class WordMLTranslator(nodes.NodeVisitor):
103 This WordML writer handles most of the features for now, You can get the gist of it rather easily. It's not nearly
104 as complicated as the HTML writer, surprisingly.
107 title_styles = [ "Heading1", "Heading2", "Heading3" ]
108 xml_spaces = ' '
110 # these are meant to be default lists, one for bullet and one for enumerated.
111 # other list types should be added here later.
113 def __init__(self, document):
114 nodes.NodeVisitor.__init__(self, document)
115 self.document = document
116 self.doc = ''
117 self.body = [] # the body of the document
118 self.in_docinfo = None
119 self.in_sidebar = None
120 self.settings = settings = document.settings
121 self.section_level = 0
122 self.title_level = 0
123 self.text_properties = {} # the list of properties for a run of test
124 self.text_prefix = [] # text or commands inserted before next text run
125 self.paragraph_properties = {}
126 self.id = 1000
127 self.in_footnote = 0
128 self.no_text = 0 # flag to suppress any text output
129 self.literal_text = 0 # flag to output newlines in text
130 self.skip_encode = 0 # flag to skip the encoding of text to xml friendly output
131 self.has_text_output = 0 # flag if any text output since last reset
132 self.figure_count = 0
133 self.in_figure = 0
134 self.indentation = 0
135 # list related variables
136 self.lists = []
137 self.list_level = -1
138 self.list_count = 0
139 self.list_properties = []
140 self.list_defs = []
141 self.template_list_defs = []
142 self.current_listdef = []
143 self.in_listdef = 0
144 self.show_list_properties = 0
145 self.extract_listdefs()
146 self.substitutions = {}
147 # table related variables
148 self.in_table = 0
149 self.colspecs = []
150 self.row = 0
151 self.col = 0
152 self.spans = {} # for multispan columns and rows
153 self.total_col_width = 0
154 # xml output variables
155 self.doc_tree = TreeBuilder()
156 self.doc_tree.start( 'w:document', {} )
157 self.xml_spacing = 0
160 def gen_id(self):
161 self.id += 1
162 return self.id
165 def template_start_element( self, name, attr ):
166 if name == 'w:rest':
167 self.doc_tree.end( 'w:document' )
168 tree = self.doc_tree.close()
169 doc_string = tostring( tree )
170 p = xml.parsers.expat.ParserCreate();
171 p.StartElementHandler = self.body_start_element
172 p.EndElementHandler = self.body_end_element
173 p.CharacterDataHandler = self.body_data
174 p.Parse( doc_string )
175 # for b in self.body:
176 # self.doc += b
177 elif name == 'w:rstlists':
178 for l in self.lists:
179 self.doc += l
180 elif name == 'w:rstlistdefs':
181 for l in self.list_defs:
182 self.doc += l
183 else:
184 self.doc += "<" + name + " "
185 for k, v in attr.iteritems():
186 self.doc += k + '="' + v + '" '
187 self.doc += ">"
190 def template_end_element( self, name ):
191 if name == 'w:rest' or name == 'w:rstlists' or name == 'w:rstlistdefs':
192 pass
193 else:
194 self.doc += '</' + name + '>'
197 def template_char_data( self, data ):
198 self.doc += data
201 # routines for extracting the listdef elements from the template
202 def start_listdef_extract( self, name, attr ):
203 if name == 'w:listDef':
204 self.in_listdef = 1
205 self.current_listdef = []
206 if name == 'w:lsid':
207 return
208 if self.in_listdef == 1:
209 self.current_listdef.append( [ name, attr ] )
212 def end_listdef_extract( self, name ):
213 self.current_listdef.append( [ "/" + name ] )
214 if name == 'w:listDef':
215 self.template_list_defs.append( self.current_listdef )
216 self.in_listdef = 0
217 if name == 'w:lsid':
218 return
220 def list_def_data( self, data ):
221 pass
224 def extract_listdefs( self ):
225 p = xml.parsers.expat.ParserCreate();
226 p.StartElementHandler = self.start_listdef_extract
227 p.EndElementHandler = self.end_listdef_extract
228 p.CharacterDataHandler = self.list_def_data
229 template = file( self.document.settings.template )
230 p.ParseFile( template )
233 def listdef_to_xml( self, list_number, level, start, nfc ):
234 """Modify a listdef to include an alternate numbering scheme and new starting number.
235 Then convert it to XML and return the XML string."""
236 xml = ''
237 lvl = -1000
238 for x in self.template_list_defs[ list_number ]:
239 # change the listDefId to match the new list
240 if x[0] == 'w:listDef':
241 x[1]['w:listDefId'] = str( self.list_count + 1 )
242 # get the level if it has changed
243 if x[0] == 'w:lvl':
244 lvl = int( x[1]['w:ilvl'] )
245 # skip an existing nfc node
246 if ( x[0] == 'w:nfc' or x[0] == '/w:nfc' ) and level == lvl:
247 continue
248 xml += '<' + x[0] + ' '
249 if len( x ) == 2:
250 for k, v in x[1].iteritems():
251 if x[0] == 'w:start' and k == 'w:val' and lvl == level:
252 xml += k + '="' + str( start ) + '" '
253 else:
254 xml += k + '="' + v + '" '
255 xml += '>\n'
256 # add in our nfc node right after the start node
257 if x[0] == '/w:start' and level == lvl:
258 xml += '<w:nfc w:val="' + str( nfc ) + '" />\n'
259 return xml
262 def body_start_element( self, name, attr ):
263 if name == 'w:document':
264 return
265 element = self.xml_spaces[ 0 : self.xml_spacing ] + "<" + name + " "
266 for k, v in attr.iteritems():
267 element += k + '="' + v + '" '
268 element = element[:-1]
269 element += ">"
270 if name != 'w:t':
271 element += '\n'
272 self.xml_spacing += 2
273 self.doc += element
276 def body_end_element( self, name ):
277 if name == 'w:document':
278 return
279 self.xml_spacing -= 2
280 element = ''
281 if name != 'w:t':
282 element += self.xml_spaces[ 0 : self.xml_spacing ]
283 element += '</' + name + '>\n'
284 self.doc += element
286 def body_data( self, data ):
287 self.doc += data
290 def check_for_span( self, col, row ):
291 check_span = '{' + str( col ) + ',' + str( row ) + '}'
292 if self.spans.has_key( check_span ):
293 self.doc_tree.start( 'w:tc', {} )
294 self.doc_tree.start( 'w:tcPr', {} )
295 self.doc_tree.start( 'w:tcW', { 'w' : str( self.calc_col_pct( self.col )), 'w:type' : 'pct' })
296 self.doc_tree.start( self.spans[ check_span ][0], self.spans[ check_span ][1] )
297 self.doc_tree.end( self.spans[ check_span ][0] )
298 self.doc_tree.end( 'w:tcW' )
299 self.doc_tree.end( 'w:tcPr' )
300 self.doc_tree.start( 'w:p', {} )
301 self.doc_tree.end( 'w:p' )
302 self.doc_tree.end( 'w:tc' )
303 self.body.append( '<w:tc>\n <w:tcPr>\n <w:tcW w="' + str( self.calc_col_pct( col )) + '" w:type="pct" />\n <' + self.spans[ check_span ][0] + ' />\n </w:tcPr>\n <w:p />\n</w:tc>\n' )
304 return True
305 return False
308 def astext( self ):
309 p = xml.parsers.expat.ParserCreate();
310 p.StartElementHandler = self.template_start_element
311 p.EndElementHandler = self.template_end_element
312 p.CharacterDataHandler = self.template_char_data
313 template = file( self.document.settings.template )
314 p.ParseFile( template )
315 return self.doc
318 def encode(self, text):
319 """Encode special characters in `text` & return."""
320 text = text.replace("&", "&amp;")
321 text = text.replace("<", "&lt;")
322 text = text.replace('"', "&quot;")
323 text = text.replace(">", "&gt;")
324 if self.literal_text == 1:
325 text = text.replace( "\n", "</w:t><w:br /><w:t>" )
326 else:
327 text = text.replace("\n", " " )
328 return text
331 def visit_Text(self, node):
332 # if we have turned off text input, then just return
333 if self.no_text:
334 return
335 # skip encode allows us to inject custom wordml as a text node without
336 self.doc_tree.start( 'w:r', {} )
337 self.body.append( "<w:r>" )
338 if len( self.text_properties ) > 0:
339 self.doc_tree.start( 'w:rPr', {} )
340 self.body.append( "<w:rPr>\n" )
341 for v in self.text_properties.values():
342 if type( v ) == type( () ):
343 element = '<' + v[0] + ' '
344 for k,a in v[1].iteritems():
345 element += k + '="' + a + '" '
346 element += '/>'
347 self.doc_tree.start( v[0], v[1] )
348 self.doc_tree.end( v[0] )
349 self.body.append( element )
350 else:
351 self.body.append( v )
352 self.doc_tree.end( 'w:rPr' )
353 self.body.append( "</w:rPr>\n" )
354 self.doc_tree.start( 'w:t', {} )
355 self.body.append( "<w:t>" )
356 text = node.astext()
357 encoded = self.encode(text)
358 self.doc_tree.data( encoded )
359 self.body.append(encoded)
360 self.has_text_output = 1
363 def depart_Text(self, node):
364 # if we have turned off text input, then just return
365 if self.no_text:
366 return
367 self.doc_tree.end( 'w:t' )
368 self.doc_tree.end( 'w:r' )
369 self.body.append( "</w:t></w:r>\n" )
372 def visit_TextNoEncoding( self, node ):
373 if self.no_text:
374 return
375 self.doc_tree.data( node.astext() )
376 self.body.append( node.astext() )
379 def depart_TextNoEncoding( self, node ):
380 pass
383 def visit_TextWithStyle( self, node ):
384 self.text_properties[ node.style[0] ] = node.style[1]
385 self.visit_Text( node )
388 def depart_TextWithStyle( self, node ):
389 del self.text_properties[ node.style[0] ]
390 self.depart_Text( node )
393 def visit_abbreviation(self, node):
394 pass
397 def depart_abbreviation(self, node):
398 pass
401 def visit_acronym(self, node):
402 pass
405 def depart_acronym(self, node):
406 pass
409 def visit_address(self, node):
410 pass
413 def depart_address(self, node):
414 pass
417 def visit_admonition(self, node, name=''):
418 pass
421 def depart_admonition(self, node=None):
422 pass
425 def visit_attention(self, node):
426 pass
429 def depart_attention(self, node):
430 pass
433 def visit_attribution(self, node):
434 pass
437 def depart_attribution(self, node):
438 pass
441 def visit_author(self, node):
442 self.paragraph_properties[ 'author' ] = ('w:pStyle', { 'w:val' : 'AuthorName' })
443 # self.paragraph_properties[ 'author' ] = '<w:pStyle w:val="AuthorName" />'
444 self.visit_paragraph( node )
447 def depart_author(self, node):
448 del self.paragraph_properties[ 'author' ]
449 self.depart_paragraph( node )
452 def visit_authors(self, node):
453 pass
456 def depart_authors(self, node):
457 pass
460 def visit_block_quote(self, node):
461 self.indentation += 720
464 def depart_block_quote(self, node):
465 self.indentation -= 720
468 def visit_bullet_list(self, node):
469 self.list_level += 1
470 self.list_count += 1
471 self.lists.append( '<w:list w:ilfo="' + str( self.list_count ) + '">\n <w:ilst w:val="1">\n </w:ilst>\n</w:list>\n' )
472 self.list_properties.append( '<w:listPr>\n<w:ilvl w:val="' + str( self.list_level ) + '" />\n<w:ilfo w:val="' + str( self.list_count ) + '" />\n</w:listPr>\n' )
475 def depart_bullet_list(self, node):
476 self.list_properties.pop()
477 self.list_level -= 1
480 def visit_caption(self, node):
481 self.figure_count += 1
482 self.text_properties[ 'caption' ] = ('w:rStyle', { 'w:val' : 'Caption' })
483 # self.text_properties[ 'caption' ] = '<w:rStyle w:val="Caption" />'
484 node.children.insert( 0, nodes.Text( 'Figure ' + str( self.figure_count ) + ' ' ));
487 def depart_caption(self, node):
488 del self.text_properties[ 'caption' ]
491 def visit_caution(self, node):
492 pass
495 def depart_caution(self, node):
496 pass
499 def visit_citation(self, node):
500 if not self.in_footnote:
501 self.no_text += 1
504 def depart_citation(self, node):
505 if not self.in_footnote:
506 self.no_text -= 1
509 def visit_citation_reference(self, node):
510 citation = self.document.ids[ node['refid'] ]
511 citation_reference_text = ''
512 if not isinstance( citation, nodes.citation ):
513 raise TypeError( 'not a citation node mapped to id' )
514 self.doc_tree.start( 'w:r', {} )
515 self.doc_tree.start( 'w:rPr', {} )
516 self.doc_tree.start( 'w:rStyle', { 'w:val' : 'CitationReference' })
517 self.doc_tree.end( 'w:rStyle' )
518 self.doc_tree.end( 'w:rPr' )
519 self.doc_tree.start( 'w:endnote', { 'w:suppressRef' : 'on' } )
520 self.body.append( '<w:r>\n<w:rPr>\n<w:rStyle w:val="CitationReference"/>\n</w:rPr>\n<w:endnote w:suppressRef="on">\n' )
521 self.in_footnote = 1
522 former_paragraph_properties = self.paragraph_properties.copy()
523 self.paragraph_properties = {}
524 self.paragraph_properties[ 'citation' ] = ( 'w:pStyle', { 'w:val' : 'EndnoteText' })
525 # self.paragraph_properties[ 'citation' ] = '<w:pStyle w:val="EndnoteText"/>'
526 labels = citation.traverse( condition=nodes.label )
527 for n in labels:
528 citation_reference_text += n.astext()
529 citation.children.remove( n )
530 p = citation.traverse( condition=nodes.paragraph )
531 # t_head = TextNoEncoding( '<w:r>\n<w:rPr>\n<w:rStyle w:val="CitationReference" />\n</w:rPr>\n<w:t>' )
532 # t_tail = TextNoEncoding( '</w:t>\n</w:r>\n')
533 # p[0].children.insert( 0, t_tail )
534 # p[0].children.insert( 0, TextNoEncoding( '[' + citation_reference_text + '] ' ))
535 # p[0].children.insert( 0, nodes.Text( '[' + citation_reference_text + '] ' ))
536 t = TextWithStyle( '[' + citation_reference_text + '] ', ( 'citation', ( 'w:rStyle', { 'w:val' : 'CitationReference' })))
537 p[0].children.insert( 0, t )
538 # p[0].children.insert( 0, t_head )
539 citation.walkabout( self )
540 p[0].children.remove( t )
541 self.doc_tree.end( 'w:endnote' )
542 self.doc_tree.start( 'w:t', {} )
543 self.doc_tree.data( '[' + citation_reference_text + ']' )
544 self.doc_tree.end( 'w:t' )
545 self.doc_tree.end( 'w:r' )
546 self.body.append( '</w:endnote>\n' )
547 self.body.append( '<w:t>' )
548 self.body.append( '[' + citation_reference_text + ']' )
549 self.body.append( '</w:t>\n</w:r>\n' )
550 del self.paragraph_properties[ 'citation' ]
551 self.in_footnote = 0
552 self.no_text += 1
553 self.paragraph_properties = former_paragraph_properties
556 def depart_citation_reference(self, node):
557 self.no_text -= 1
558 pass
561 def visit_classifier(self, node):
562 pass
565 def depart_classifier(self, node):
566 pass
569 def visit_colspec(self, node):
570 self.colspecs.append( node )
571 self.total_col_width += node['colwidth']
574 def depart_colspec(self, node):
575 pass
578 def visit_comment(self, node):
579 self.no_text += 1
582 def depart_comment( self, node ):
583 self.no_text -= 1
586 def visit_compound(self, node):
587 pass
590 def depart_compound(self, node):
591 pass
594 def visit_contact(self, node):
595 self.paragraph_properties[ 'contact' ] = ( 'w:pStyle', { 'w:val' : 'AuthorContact' })
596 # self.paragraph_properties[ 'contact' ] = '<w:pStyle w:val="AuthorContact" />'
597 self.visit_paragraph( node )
600 def depart_contact(self, node):
601 del self.paragraph_properties[ 'contact' ]
602 self.depart_paragraph( node )
605 def visit_container(self, node):
606 pass
609 def depart_container(self, node):
610 pass
613 def visit_copyright(self, node):
614 self.paragraph_properties[ 'copyright' ] = ( 'w:pStyle', { 'w:val' : 'BibliographMatter' })
615 # self.paragraph_properties[ 'copyright' ] = '<w:pStyle w:val="BibliographMatter" />'
616 self.visit_paragraph( node )
619 def depart_copyright(self, node):
620 del self.paragraph_properties[ 'copyright' ]
621 self.depart_paragraph( node )
624 def visit_danger(self, node):
625 pass
628 def depart_danger(self, node):
629 pass
632 def visit_date(self, node):
633 self.paragraph_properties[ 'date' ] = ( 'w:pStyle', { 'w:val' : 'BibliographMatter' })
634 # self.paragraph_properties[ 'date' ] = '<w:pStyle w:val="BibliographMatter" />'
635 self.visit_paragraph( node )
638 def depart_date(self, node):
639 del self.paragraph_properties[ 'date' ]
640 self.depart_paragraph( node )
643 def visit_decoration(self, node):
644 pass
647 def depart_decoration(self, node):
648 pass
651 def visit_definition(self, node):
652 self.indentation += 720
653 self.paragraph_properties[ 'definition' ] = ( 'w:pStyle', { 'w:val' : 'Definition' })
654 # self.paragraph_properties[ 'definition' ] = '<w:pStyle w:val="Definition" />'
657 def depart_definition(self, node):
658 self.indentation -= 720
659 del self.paragraph_properties[ 'definition' ]
662 def visit_definition_list(self, node):
663 pass
666 def depart_definition_list(self, node):
667 pass
670 def visit_definition_list_item(self, node):
671 pass
674 def depart_definition_list_item(self, node):
675 pass
678 def visit_description(self, node):
679 pass
682 def depart_description(self, node):
683 pass
686 def visit_docinfo(self, node):
687 pass
690 def depart_docinfo(self, node):
691 pass
694 def visit_docinfo_item(self, node, name, meta=1):
695 pass
698 def depart_docinfo_item(self):
699 pass
702 def visit_doctest_block(self, node):
703 pass
706 def depart_doctest_block(self, node):
707 pass
710 def visit_document(self, node):
711 pass
714 def depart_document(self, node):
715 pass
718 def visit_emphasis(self, node):
719 self.text_properties[ '*' ] = ('w:i', {})
720 # self.text_properties[ '*' ] = '<w:i/>'
723 def depart_emphasis(self, node):
724 del self.text_properties[ '*' ]
727 def calc_col_pct( self, col ):
728 width = int( self.colspecs[ col ][ 'colwidth' ] * 100.0 / self.total_col_width + 0.5 )
729 return width
732 def visit_entry(self, node):
733 width = self.calc_col_pct( self.col )
734 self.doc_tree.start( 'w:tc', {} )
735 self.doc_tree.start( 'w:tcPr', {} )
736 self.doc_tree.start( 'w:tcW', { 'w' : str( width ), 'w:type' : 'pct' } )
737 self.doc_tree.end( 'w:tcW' )
738 self.body.append( '<w:tc>\n <w:tcPr>\n <w:tcW w="' + str( width ) + '" w:type="pct" />\n' )
739 self.has_text_output = 0
740 if node.has_key('morecols') and node.has_key('morerows'):
741 raise NotImplementedError( "Table cell " + str( self.col ) + "," + str( self.row ) + " can't have both merged rows and columns." )
742 if node.has_key('morecols'):
743 self.doc_tree.start( 'w:hmerge', { 'w:val' : 'restart' } )
744 self.doc_tree.end( 'w:hmerge' )
745 self.body.append( '<w:hmerge w:val="restart" />' )
746 for i in range( node['morecols'] ):
747 span = '{' + str( self.col + i + 1 ) + ',' + str( self.row ) + '}'
748 self.spans[ span ] = ('w:hmerge', {}) # '<w:hmerge />'
749 if node.has_key('morerows'):
750 self.doc_tree.start( 'w:vmerge', { 'w:val' : 'restart' })
751 self.doc_tree.end( 'w:vmerge' )
752 self.body.append( '<w:vmerge w:val="restart" />' )
753 for i in range( node['morerows'] ):
754 span = '{' + str( self.col ) + ',' + str( self.row + i + 1 ) + '}'
755 self.spans[ span ] = ('w:vmerge', {} ) # '<w:vmerge />'
756 self.doc_tree.end( 'w:tcPr' )
757 self.body.append( '</w:tcPr>\n' )
760 def depart_entry(self, node):
761 if self.has_text_output == 0:
762 self.doc_tree.start( 'w:p', {} )
763 self.doc_tree.end( 'w:p' )
764 self.body.append( ' <w:p />\n' )
765 self.doc_tree.end( 'w:tc' )
766 self.body.append( '</w:tc>\n' )
767 # if there are any cells that are part of a span, then include them here as empty cells.
768 col = self.col + 1
769 row = self.row
770 while self.check_for_span( col, row ):
771 col = col + 1
772 self.col = col
773 self.row = row
776 def visit_enumerated_list(self, node):
777 # to put any sort of customization in, it's necessary to add an entirely new listDef element.
778 # so, I need to load the listDefs at the beginning of the run, and then customize them as needed.
779 self.list_level += 1
780 self.list_count += 1
781 list_props = '<w:listPr>\n<w:ilvl w:val="' + str( self.list_level ) + '" />\n<w:ilfo w:val="' + str( self.list_count ) + '" />\n'
782 #if the list has an explicit start, then set the text for it
783 start = 1
784 if node.has_key('start'):
785 start = int( node['start'] )
786 nfc = 0
787 if node['enumtype'] == 'arabic':
788 nfc = 0
789 elif node['enumtype'] == 'upperalpha':
790 nfc = 3
791 elif node['enumtype'] == 'loweralpha':
792 nfc = 4
793 elif node['enumtype'] == 'lowerroman':
794 nfc = 2
795 elif node['enumtype'] == 'upperroman':
796 nfc = 1
797 self.list_defs.append( self.listdef_to_xml( 0, self.list_level, start, nfc ))
798 self.lists.append( '<w:list w:ilfo="' + str( self.list_count ) + '">\n <w:ilst w:val="' + str( self.list_count + 1 ) + '">\n </w:ilst>\n</w:list>\n' )
799 list_props += '</w:listPr>\n'
800 self.list_properties.append( list_props )
803 def depart_enumerated_list(self, node):
804 self.show_list_properties -= 1
805 self.list_properties.pop()
806 self.list_level -= 1
809 def visit_error(self, node):
810 pass
813 def depart_error(self, node):
814 pass
817 def visit_field(self, node):
818 self.paragraph_properties[ 'field' ] = ( 'w:pStyle', { 'w:val' : 'BibliographMatter' })
819 # self.paragraph_properties[ 'field' ] = '<w:pStyle w:val="BibliographMatter" />'
820 self.visit_paragraph( node )
823 def depart_field(self, node):
824 del self.paragraph_properties[ 'field' ]
825 self.depart_paragraph( node )
828 def visit_field_body(self, node):
829 pass
832 def depart_field_body(self, node):
833 pass
836 def visit_field_list(self, node):
837 pass
840 def depart_field_list(self, node):
841 pass
844 def visit_field_name(self, node):
845 pass
848 def depart_field_name(self, node):
849 pass
852 def visit_figure(self, node):
853 self.in_figure = 1
856 def depart_figure(self, node):
857 if self.in_figure:
858 self.doc_tree.end( 'w:p' )
859 self.body.append( '</w:p>\n' )
860 self.in_figure = 0
863 def visit_footer(self, node):
864 pass
867 def depart_footer(self, node):
868 pass
871 def visit_footnote(self, node):
872 if not self.in_footnote:
873 self.no_text += 1
876 def depart_footnote(self, node):
877 if not self.in_footnote:
878 self.no_text -= 1
881 def visit_footnote_reference(self, node):
882 if not node.has_key( 'auto' ):
883 raise TypeError( 'footnotes required to be auto numbered' )
884 footnote = self.document.ids[ node['refid'] ]
885 if not isinstance( footnote, nodes.footnote ):
886 raise TypeError( 'not a footnote node mapped to id' )
887 self.doc_tree.start( 'w:r', {} )
888 self.doc_tree.start( 'w:rPr', {} )
889 self.doc_tree.start( 'w:rStyle', { 'w:val' : 'EndnoteReference' })
890 self.doc_tree.end( 'w:rStyle' )
891 self.doc_tree.end( 'w:rPr' )
892 self.doc_tree.start( 'w:endnote', {} )
893 self.body.append( '<w:r>\n<w:rPr>\n<w:rStyle w:val="EndnoteReference"/>\n</w:rPr>\n<w:endnote>\n' )
894 # figure out how to get the <w:endnoteRef/>
895 self.in_footnote = 1
896 former_paragraph_properties = self.paragraph_properties.copy()
897 self.paragraph_properties = {}
898 self.paragraph_properties[ 'footnote' ] = ( 'w:pStyle', { 'w:val' : 'EndnoteText' })
899 # self.paragraph_properties[ 'footnote' ] = '<w:pStyle w:val="EndnoteText"/>'
900 # self.body.append( '<w:p>\n<w:pPr>\n<w:pStyle w:val="EndnoteText"/>\n</w:pPr>\n<w:r>\n<w:r>\n<w:rPr>\n<w:rStyle w:val="EndnoteReference"/>\n</w:rPr>\n<w:endnoteRef/>\n' )
901 # Find the label in the target footnode node and add it here.
902 labels = footnote.traverse( condition=nodes.label )
903 # replace label text with <w:endnoteRef />
904 for n in labels:
905 footnote.children.remove( n )
906 # n.children.append( nodes.Text('<w:r>\n<w:rPr>\n<w:rStyle w:val="EndnoteReference" />\n</w:rPr>\n<w:endnoteRef />\n</w:r>\n'))
907 p = footnote.traverse( condition=nodes.paragraph )
908 # t = TextNoEncoding( '<w:r>\n<w:rPr>\n<w:rStyle w:val="EndnoteReference" />\n</w:rPr>\n<w:endnoteRef />\n</w:r>\n')
909 t = XMLRegion( xml=[( 'w:endnoteRef', {} )], styles=[( 'w:rStyle', { 'w:val' : 'EndnoteReference' })] )
910 p[0].children.insert( 0, t )
911 footnote.walkabout( self )
912 p[0].children.remove(t)
913 self.doc_tree.end( 'w:endnote' )
914 self.doc_tree.end( 'w:r' )
915 self.body.append( '</w:endnote>\n</w:r>\n' )
916 del self.paragraph_properties[ 'footnote' ]
917 self.in_footnote = 0
918 self.no_text += 1
919 self.paragraph_properties = former_paragraph_properties
922 def depart_footnote_reference(self, node):
923 # del self.paragraph_properties[ 'footnote' ]
924 # self.in_footnote = 0
925 self.no_text -= 1
928 def visit_generated(self, node):
929 pass
932 def depart_generated(self, node):
933 pass
936 def visit_header(self, node):
937 pass
940 def depart_header(self, node):
941 pass
944 def visit_hint(self, node):
945 pass
948 def depart_hint(self, node):
949 pass
952 def visit_image(self, node):
953 width = 100
954 height = 100
955 align = 'center'
956 use_width = 0
957 use_height = 0
958 if Image:
959 try:
960 im = Image.open( node['uri'] )
961 width = im.size[0]
962 height = im.size[1]
963 use_width = 1
964 use_height = 1
965 except (IOError, UnicodeError):
966 pass
967 if node.has_key( 'width' ):
968 width = node[ 'width' ]
969 use_width = 1
970 if node.has_key( 'height' ):
971 height = node[ 'height' ]
972 use_height = 1
973 if node.has_key( 'align' ):
974 align = node[ 'align' ]
975 self.doc_tree.start( 'w:p', {} )
976 self.doc_tree.start( 'w:pPr', {} )
977 self.doc_tree.start( 'w:jc', { 'w:val' : str( align ) } )
978 self.doc_tree.end( 'w:jc' )
979 self.doc_tree.end( 'w:pPr' )
980 self.doc_tree.start( 'w:pict', {} )
981 style = 'position:absolute;left:0;text-align:left;margin-left:0;margin-top:0;width:'
982 if use_width:
983 style += str(width) + 'px'
984 else:
985 style += 'auto'
986 style += ';height:'
987 if use_height:
988 style += str( height ) + 'px'
989 else:
990 style += 'auto'
991 style += ';z-index:1;mso-position-horizontal:center'
992 self.doc_tree.start( 'v:shape', { 'id' : str( self.gen_id() ), 'style' : style, 'coordsize' : '', 'o:spt' : '100', 'adj' : '0,,0', 'path' : '', 'stroked' : 'f' } )
993 self.doc_tree.start( 'v:imagedata', { 'src' : node['uri'] } )
994 self.doc_tree.end( 'v:imagedata' )
995 self.doc_tree.start( 'w10:wrap', { 'type' : 'square' } )
996 self.doc_tree.end( 'w10:wrap' )
997 self.doc_tree.end( 'v:shape' )
998 self.doc_tree.end( 'w:pict' )
999 self.body.append( '<w:p>\n<w:pPr>\n<w:jc w:val="' + str( align ) + '" />\n</w:pPr>\n<w:pict>\n<v:shape id="' + str( self.gen_id() ) + '" ')
1000 self.body.append( 'style="position:absolute;left:0;text-align:left;margin-left:0;margin-top:0;width:' )
1001 if use_width:
1002 self.body.append( str(width) + 'px' )
1003 else:
1004 self.body.append( 'auto' )
1005 self.body.append(';height:')
1006 if use_height:
1007 self.body.append( str(height) + 'px')
1008 else:
1009 self.body.append( 'auto' )
1010 self.body.append( ';z-index:1;mso-position-horizontal:center" coordsize="" o:spt="100" adj="0,,0" path="" stroked="f" >\n' )
1011 self.body.append( '<v:imagedata src="' + node['uri'] + '"/>\n<w10:wrap type="square"/>\n</v:shape>\n</w:pict>\n' )
1014 def depart_image(self, node):
1015 if not self.in_figure:
1016 self.doc_tree.end( 'w:p' )
1017 self.body.append( '</w:p>\n' )
1020 def visit_important(self, node):
1021 pass
1024 def depart_important(self, node):
1025 pass
1028 def visit_inline(self, node):
1029 pass
1032 def depart_inline(self, node):
1033 pass
1036 def visit_label(self, node):
1037 self.text_properties[ 'label' ] = ( 'w:rStyle', { 'w:val' : '"EndnoteReference"' } )
1038 # self.text_properties[ 'label' ] = '<w:rStyle w:val="EndnoteReference"/>\n'
1039 #if self.in_footnote:
1040 # self.no_text += 1
1041 # self.body.append( '<w:r>\n<w:rPr>\n<w:rStyle w:val="EndnoteReference"/>\n</w:rPr>\n<w:endnoteRef/>\n</w:r>\n' )
1042 pass
1044 def depart_label(self, node):
1045 del self.text_properties[ 'label' ]
1046 #if self.in_footnote:
1047 # self.no_text -= 1
1048 pass
1050 def visit_legend(self, node):
1051 pass
1054 def depart_legend(self, node):
1055 pass
1058 def visit_line(self, node):
1059 pass
1062 def depart_line(self, node):
1063 pass
1066 def visit_line_block(self, node):
1067 pass
1070 def depart_line_block(self, node):
1071 pass
1074 def visit_list_item(self, node):
1075 pass
1078 def depart_list_item(self, node):
1079 pass
1082 def visit_literal(self, node):
1083 self.text_properties[ 'literal' ] = ( 'w:rStyle', { 'w:val' : 'Literal' } )
1084 # self.text_properties[ 'literal' ] = '<w:rStyle w:val="Literal"/>\n'
1087 def depart_literal( self, node ):
1088 del self.text_properties[ 'literal' ]
1091 def visit_literal_block(self, node):
1092 self.paragraph_properties[ 'literal' ] = ( 'w:pStyle', { 'w:val' : 'LiteralBlock' })
1093 #~ self.paragraph_properties[ 'literal' ] = '<w:pStyle w:val="LiteralBlock" />\n'
1094 self.visit_paragraph( node )
1095 self.literal_text = 1
1098 def depart_literal_block(self, node):
1099 del self.paragraph_properties[ 'literal' ]
1100 self.depart_paragraph( node )
1101 self.literal_text = 0
1104 def visit_meta(self, node):
1105 pass
1108 def depart_meta(self, node):
1109 pass
1112 def visit_note(self, node):
1113 pass
1116 def depart_note(self, node):
1117 pass
1120 def visit_option(self, node):
1121 pass
1124 def depart_option(self, node):
1125 pass
1128 def visit_option_argument(self, node):
1129 pass
1132 def depart_option_argument(self, node):
1133 pass
1136 def visit_option_group(self, node):
1137 pass
1140 def depart_option_group(self, node):
1141 pass
1144 def visit_option_list(self, node):
1145 pass
1148 def depart_option_list(self, node):
1149 pass
1152 def visit_option_list_item(self, node):
1153 pass
1156 def depart_option_list_item(self, node):
1157 pass
1160 def visit_option_string(self, node):
1161 pass
1164 def depart_option_string(self, node):
1165 pass
1168 def visit_organization(self, node):
1169 self.paragraph_properties[ 'organization' ] = ( 'w:pStyle', { 'w:val' : 'BibliographMatter' } )
1170 #~ self.paragraph_properties[ 'organization' ] = '<w:pStyle w:val="BibliographMatter" />'
1171 self.visit_paragraph( node )
1174 def depart_organization(self, node):
1175 del self.paragraph_properties[ 'organization' ]
1176 self.depart_paragraph( node )
1179 def visit_paragraph(self, node):
1180 self.doc_tree.start( 'w:p', {} )
1181 self.body.append( "<w:p>\n" )
1182 if len( self.paragraph_properties ) > 0 or len( self.list_properties ) > 0 or (self.indentation > 0 and not self.in_footnote):
1183 self.doc_tree.start( 'w:pPr', {} )
1184 self.body.append( "<w:pPr>\n" )
1185 if self.indentation > 0 and not self.in_footnote:
1186 self.doc_tree.start( 'w:ind', { 'w:left' : str( self.indentation ), 'w:right' : str( self.indentation ) })
1187 self.doc_tree.end( 'w:ind' )
1188 self.body.append( '<w:ind w:left="' + str( self.indentation ) +
1189 '" w:right="' + str( self.indentation ) + '" />\n' )
1190 for v in self.paragraph_properties.values():
1191 if type( v ) == type( () ):
1192 element = '<' + v[0] + ' '
1193 for k,a in v[1].iteritems():
1194 element += k + '="' + a + '" '
1195 element += '/>'
1196 self.doc_tree.start( v[0], v[1] )
1197 self.doc_tree.end( v[0] )
1198 self.body.append( element )
1199 else:
1200 self.body.append( v )
1201 if len( self.list_properties ) > 0 and isinstance( node.parent, nodes.list_item ):
1202 if type( self.list_properties[ -1 ] ) == type( () ):
1203 t = self.list_properties[ -1 ]
1204 element = '<' + t[0] + ' '
1205 for k,a in t[1].iteritems():
1206 element += k + '="' + a + '" '
1207 element += '/>'
1208 self.doc_tree.start( t[0], t[1] )
1209 self.doc_tree.end( t[0] )
1210 self.body.append( element )
1211 else:
1212 self.body.append( self.list_properties[ -1 ] )
1213 self.doc_tree.end( 'w:pPr' )
1214 self.body.append( "\n</w:pPr>\n" )
1217 def depart_paragraph(self, node):
1218 self.doc_tree.end( 'w:p' );
1219 self.body.append( "</w:p>\n" )
1222 def visit_problematic(self, node):
1223 pass
1226 def depart_problematic(self, node):
1227 pass
1230 def visit_raw(self, node):
1231 pass
1234 def visit_reference(self, node):
1235 if node.has_key('refid'):
1236 self.doc_tree.start( 'w:hlink', { 'w:bookmark' : node[ 'refid' ] })
1237 self.body.append( '<w:hlink w:bookmark="' + node['refid'] + '" >\n' )
1238 if node.has_key('refuri'):
1239 self.doc_tree.start( 'w:hlink', { 'w:dest' : node['refuri'] })
1240 self.body.append( '<w:hlink w:dest="' + node['refuri'] + '" >\n' )
1241 if not node.has_key('refuri') and not node.has_key('refid'):
1242 raise NotImplementedError('Unknown reference type')
1243 self.text_properties[ 'ref' ] = ( 'w:rStyle', { 'w:val' : 'Hyperlink' })
1244 #~ self.text_properties['ref'] = '<w:rStyle w:val="Hyperlink" />\n'
1247 def depart_reference(self, node):
1248 del self.text_properties[ 'ref' ]
1249 self.doc_tree.end( 'w:hlink' )
1250 self.body.append( '</w:hlink>\n' )
1253 def visit_revision(self, node):
1254 pass
1257 def depart_revision(self, node):
1258 pass
1261 def visit_row(self, node):
1262 self.doc_tree.start( 'w:tr', {} )
1263 self.body.append( '<w:tr>\n' )
1264 while self.check_for_span( self.col, self.row ):
1265 self.col += 1
1267 def depart_row(self, node):
1268 self.row += 1
1269 self.col = 0
1270 self.doc_tree.end( 'w:tr' )
1271 self.body.append( '</w:tr>\n' )
1274 def visit_rubric(self, node):
1275 pass
1278 def depart_rubric(self, node):
1279 pass
1282 def visit_section(self, node):
1283 self.section_level += 1
1284 if self.section_level > 3:
1285 raise NotImplementedError( "Only 3 levels of headings supported." )
1286 if node.has_key( 'ids' ):
1287 for id in node['ids']:
1288 refid = self.gen_id()
1289 self.doc_tree.start( 'aml:annotation', { 'aml:id' : str( refid ), 'w:type' : 'Word.Bookmark.Start', 'w:name' : id })
1290 self.doc_tree.end( 'aml:annotation' )
1291 self.doc_tree.start( 'aml:annotation', { 'aml:id' : str( refid ), 'w:type' : 'Word.Bookmark.End', 'w:name' : id })
1292 self.doc_tree.end( 'aml:annotation' )
1293 self.body.append('<aml:annotation aml:id="' + str( refid ) + '" w:type="Word.Bookmark.Start" w:name="' + id + '" />' )
1294 self.body.append('<aml:annotation aml:id="' + str( refid ) + '" w:type="Word.Bookmark.End" w:name="' + id + '" />' )
1297 def depart_section(self, node):
1298 self.section_level -= 1
1301 def visit_sidebar(self, node):
1302 pass
1305 def depart_sidebar(self, node):
1306 pass
1309 def visit_status(self, node):
1310 self.paragraph_properties[ 'status' ] = ( 'w:pStyle', { 'w:val' : 'BibliographMatter' })
1311 #~ self.paragraph_properties[ 'status' ] = '<w:pStyle w:val="BibliographMatter" />'
1312 self.visit_paragraph( node )
1315 def depart_status(self, node):
1316 del self.paragraph_properties[ 'status' ]
1317 self.depart_paragraph( node )
1320 def visit_strong(self, node):
1321 self.text_properties[ '**' ] = ( 'w:b', {} )
1322 #~ self.text_properties[ '**' ] = '<w:b/>'
1325 def depart_strong(self, node):
1326 del self.text_properties[ '**' ]
1329 def visit_subscript(self, node):
1330 self.text_properties[ 'subscript' ] = ( 'w:vertAlign', { 'w:val' : 'subscript' })
1331 #~ self.text_properties[ 'subscript' ] = '<w:vertAlign w:val="subscript" />'
1334 def depart_subscript(self, node):
1335 del self.text_properties[ 'subscript' ]
1338 def visit_substitution_definition(self, node):
1339 raise nodes.SkipNode
1342 def visit_substitution_reference(self, node):
1343 raise NotImplementedError( "substitution references not implemented" )
1346 def visit_subtitle(self, node):
1347 self.paragraph_properties[ 'subtitle' ] = ( 'w:pStyle', { 'w:val' : self.title_styles[ self.section_level + 1 ] })
1348 #~ self.paragraph_properties[ 'subtitle' ] = '<w:pStyle w:val="' + self.title_styles[ self.section_level + 1 ] + '"/>\n'
1349 self.visit_paragraph( node )
1352 def depart_subtitle(self, node):
1353 del self.paragraph_properties[ 'subtitle' ]
1354 self.depart_paragraph( node )
1357 def visit_superscript(self, node):
1358 self.text_properties[ 'superscript' ] = ( 'w:vertAlign', { 'w:val' : 'superscript' })
1359 #~ self.text_properties[ 'superscript' ] = '<w:vertAlign w:val="superscript" />\n'
1362 def depart_superscript(self, node):
1363 del self.text_properties[ 'superscript' ]
1366 def visit_system_message(self, node):
1367 pass
1370 def depart_system_message(self, node):
1371 pass
1374 def visit_table(self, node):
1375 #include for now the default border around the table with a top vertical alignment
1376 self.in_table = 1
1377 self.colspecs = []
1378 self.spans = {}
1379 self.total_col_width = 0
1380 self.row = 0
1381 self.col = 0
1382 self.doc_tree.start( 'w:tbl', {} )
1383 self.doc_tree.start( 'w:tblPr', {} )
1384 self.doc_tree.start( 'w:tblStyle', { 'w:val' : 'Normal' } )
1385 self.doc_tree.end( 'w:tblStyle' )
1386 self.doc_tree.start( 'w:tblW', { 'w:w' : '5000', 'w:type' : 'pct' })
1387 self.doc_tree.end( 'w:tblW' )
1388 self.doc_tree.start( 'w:tblBorders', {} )
1389 self.doc_tree.start( 'w:top', { 'w:val' : 'single', 'w:sz' : '4', 'wx:bdrwidth' : '10', 'w:space' : '0', 'w:color' : 'auto' })
1390 self.doc_tree.end( 'w:top' )
1391 self.doc_tree.start( 'w:left', { 'w:val' : 'single', 'w:sz' : '4', 'wx:bdrwidth' : '10', 'w:space' : '0', 'w:color' : 'auto' })
1392 self.doc_tree.end( 'w:left' )
1393 self.doc_tree.start( 'w:bottom', { 'w:val' : 'single', 'w:sz' : '4', 'wx:bdrwidth' : '10', 'w:space' : '0', 'w:color' : 'auto' })
1394 self.doc_tree.end( 'w:bottom' )
1395 self.doc_tree.start( 'w:right', { 'w:val' : 'single', 'w:sz' : '4', 'wx:bdrwidth' : '10', 'w:space' : '0', 'w:color' : 'auto' })
1396 self.doc_tree.end( 'w:right' )
1397 self.doc_tree.start( 'w:insideH', { 'w:val' : 'single', 'w:sz' : '6', 'wx:bdrwidth' : '15', 'w:space' : '0', 'w:color' : 'auto' })
1398 self.doc_tree.end( 'w:insideH' )
1399 self.doc_tree.start( 'w:insideV', { 'w:val' : 'single', 'w:sz' : '6', 'wx:bdrwidth' : '15', 'w:space' : '0', 'w:color' : 'auto' })
1400 self.doc_tree.end( 'w:insideV' )
1401 self.doc_tree.end( 'w:tblBorders' )
1402 self.doc_tree.start( 'w:tblLook', { 'w:val' : '000001e0' } )
1403 self.doc_tree.end( 'w:tblLook' )
1404 self.doc_tree.end( 'w:tblPr' )
1405 self.body.append( '<w:tbl>\n'
1406 ' <w:tblPr>\n'
1407 ' <w:tblStyle w:val="Normal" />\n'
1408 ' <w:tblW w:w="5000" w:type="pct" />\n'
1409 ' <w:tblBorders>\n'
1410 ' <w:top w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>\n'
1411 ' <w:left w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>\n'
1412 ' <w:bottom w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>\n'
1413 ' <w:right w:val="single" w:sz="4" wx:bdrwidth="10" w:space="0" w:color="auto"/>\n'
1414 ' <w:insideH w:val="single" w:sz="6" wx:bdrwidth="15" w:space="0" w:color="auto"/>\n'
1415 ' <w:insideV w:val="single" w:sz="6" wx:bdrwidth="15" w:space="0" w:color="auto"/>\n'
1416 ' </w:tblBorders>\n'
1417 ' <w:tblLook w:val="000001e0" />\n'
1418 ' </w:tblPr>\n')
1421 def depart_table(self, node):
1422 self.doc_tree.end( 'w:tbl' )
1423 self.doc_tree.start( 'w:p', {} )
1424 self.doc_tree.end( 'w:p' )
1425 self.body.append( '</w:tbl>\n' )
1426 self.body.append( '<w:p />' ) # add a blank line after the table
1427 self.in_table = 0
1430 def visit_target(self, node):
1431 if node.has_key('refid'):
1432 refid = self.gen_id()
1433 self.doc_tree.start( 'aml:annotation', { 'aml:id' : str(refid), 'w:type' : 'Word.Bookmark.Start', 'w:name' : node['refid'] })
1434 self.doc_tree.end( 'aml:annotation' )
1435 self.doc_tree.start( 'aml:annotation', { 'aml:id' : str(refid), 'w:type' : 'Word.Bookmark.End', 'w:name' : node['refid'] })
1436 self.doc_tree.end( 'aml:annotation' )
1437 self.body.append('<aml:annotation aml:id="' + str( refid ) + '" w:type="Word.Bookmark.Start" w:name="' + node['refid'] + '" />\n' )
1438 self.body.append('<aml:annotation aml:id="' + str( refid ) + '" w:type="Word.Bookmark.End" w:name="' + node['refid'] + '" />\n' )
1441 def depart_target(self, node):
1442 pass
1445 def visit_tbody(self, node):
1446 pass
1448 def depart_tbody(self, node):
1449 pass
1452 def visit_term(self, node):
1453 self.paragraph_properties[ 'term' ] = ( 'w:pStyle', { 'w:val' : 'DefinitionTerm' })
1454 #~ self.paragraph_properties[ 'term' ] = '<w:pStyle w:val="DefinitionTerm" />'
1455 self.visit_paragraph( node )
1458 def depart_term(self, node):
1459 del self.paragraph_properties[ 'term' ]
1460 self.depart_paragraph( node )
1463 def visit_tgroup(self, node):
1464 pass
1467 def depart_tgroup(self, node):
1468 pass
1471 def visit_thead(self, node):
1472 pass
1475 def depart_thead(self, node):
1476 pass
1479 def visit_tip(self, node):
1480 pass
1483 def depart_tip(self, node):
1484 pass
1487 def visit_title(self, node, move_ids=1):
1488 self.paragraph_properties[ 'title' ] = ( 'w:pStyle', { 'w:val' : self.title_styles[ self.section_level ] })
1489 #~ self.paragraph_properties[ 'title' ] = '<w:pStyle w:val="' + self.title_styles[ self.section_level ] + '"/>\n'
1490 self.visit_paragraph( node )
1493 def depart_title(self, node):
1494 del self.paragraph_properties[ 'title' ]
1495 self.depart_paragraph( node )
1498 def visit_title_reference(self, node):
1499 pass
1502 def depart_title_reference(self, node):
1503 pass
1506 def visit_topic(self, node):
1507 self.paragraph_properties[ 'topic' ] = ( 'w:pStyle', { 'w:val' : 'Topic' })
1508 #~ self.paragraph_properties[ 'topic' ] = '<w:pStyle w:val="BibliographMatter" />'
1509 self.visit_paragraph( node )
1512 def depart_topic(self, node):
1513 del self.paragraph_properties[ 'topic' ]
1514 self.depart_paragraph( node )
1517 def visit_transition(self, node):
1518 pass
1521 def depart_transition(self, node):
1522 pass
1525 def visit_version(self, node):
1526 self.paragraph_properties[ 'version' ] = ( 'w:pStyle', { 'w:val' : 'BibliographMatter' })
1527 # self.paragraph_properties[ 'version' ] = '<w:pStyle w:val="BibliographMatter" />'
1528 self.visit_paragraph( node )
1531 def depart_version(self, node):
1532 del self.paragraph_properties[ 'version' ]
1533 self.depart_paragraph( node )
1536 def visit_warning(self, node):
1537 pass
1540 def depart_warning(self, node):
1541 pass
1544 def visit_XMLRegion( self, node ):
1545 self.doc_tree.start( 'w:r', {} )
1546 self.doc_tree.start( 'w:rPr', {} )
1547 for style in node['styles']:
1548 self.doc_tree.start( style[0], style[1] )
1549 self.doc_tree.end( style[0] )
1550 self.doc_tree.end( 'w:rPr' )
1551 for tag in node['xml']:
1552 self.doc_tree.start( tag[0], tag[1] )
1553 self.doc_tree.end( tag[0] )
1556 def depart_XMLRegion( self, node ):
1557 self.doc_tree.end( 'w:r' )
1560 def unimplemented_visit(self, node):
1561 pass