diff --git a/pydocx/export/base.py b/pydocx/export/base.py index ecfc487c..349565e6 100644 --- a/pydocx/export/base.py +++ b/pydocx/export/base.py @@ -110,16 +110,24 @@ def export(self): # document (e.g. fields) # In the first pass, discard any generated results self.first_pass = True - for result in self.export_node(document): - pass + self._first_pass_export() - self._convert_complex_fields_into_simple_fields() + self._post_first_pass_processing() # actually render the results self.first_pass = False for result in self.export_node(document): yield result + def _first_pass_export(self): + document = self.main_document_part.document + if document: + for result in self.export_node(document): + pass + + def _post_first_pass_processing(self): + self._convert_complex_fields_into_simple_fields() + def _convert_complex_fields_into_simple_fields(self): if not self.complex_field_runs: return @@ -132,6 +140,13 @@ def _convert_complex_fields_into_simple_fields(self): runs_to_remove_by_field = {} runs_to_remove = set() + # All of the complex field runs need to be wrapped in simple fields, + # and then the runs need to be removed from their original container + # The new simple fields that contain the runs are inserted into the + # structure and the parent links are updated + + # First create all the necessary simple fields and group the runs into + # their simple fields. for run in self.complex_field_runs: for child in run.children: if field is not None and previous_run is not None: @@ -166,6 +181,8 @@ def _convert_complex_fields_into_simple_fields(self): runs_to_remove.add(run) previous_run = run + # Next, remove all of the runs from the run's current parent, and + # inject the field in their place. for field in fields: runs_to_remove = runs_to_remove_by_field.get(field, set()) if not field.children: @@ -180,6 +197,12 @@ def _convert_complex_fields_into_simple_fields(self): previous_parent_new_children.append(child) first_run.parent.children = previous_parent_new_children + # If we don't do this, the field's parent will be None. That will + # break the hierarchy. + field.parent = first_run.parent + + # Update the run parent links to point to the field, since the + # field is now the run's new parent. for run in field.children: run.parent = field diff --git a/tests/export/html/test_field_code.py b/tests/export/html/test_field_code.py index 273f2fdb..cc7c8c31 100644 --- a/tests/export/html/test_field_code.py +++ b/tests/export/html/test_field_code.py @@ -7,11 +7,58 @@ ) -from pydocx.openxml.packaging import MainDocumentPart +from pydocx.openxml.packaging import MainDocumentPart, StyleDefinitionsPart from pydocx.test import DocumentGeneratorTestCase from pydocx.test.utils import WordprocessingDocumentFactory +class HeadingTestCase(DocumentGeneratorTestCase): + def test_styles_are_ignored(self): + style_xml = ''' + + ''' + + document_xml = ''' +

+ + + + + + + + FOOBAR baz + + + + + + AAA + + + + +

+ ''' + document = WordprocessingDocumentFactory() + document.add(StyleDefinitionsPart, style_xml) + document.add(MainDocumentPart, document_xml) + + expected_html = ''' +

AAA

+ ''' + self.assert_document_generates_html(document, expected_html) + + class FieldCodeTestCase(DocumentGeneratorTestCase): def test_unsupported_instr_content_is_not_ignored(self): document_xml = ''' @@ -92,7 +139,7 @@ def test_multiple_instr_with_same_paragraph_parent(self): self.assert_document_generates_html(document, expected_html) -class HyperlinkFieldCodeTestCase(DocumentGeneratorTestCase): +class HyperlinkTestCase(DocumentGeneratorTestCase): def test_spanning_single_paragraph(self): document_xml = '''

diff --git a/tests/export/html/test_simple_field.py b/tests/export/html/test_simple_field.py index 75125e3b..b1ee947c 100644 --- a/tests/export/html/test_simple_field.py +++ b/tests/export/html/test_simple_field.py @@ -9,13 +9,50 @@ from unittest import TestCase -from pydocx.openxml.packaging import MainDocumentPart +from pydocx.openxml.packaging import MainDocumentPart, StyleDefinitionsPart from pydocx.openxml.wordprocessing.simple_field import SimpleField from pydocx.test import DocumentGeneratorTestCase from pydocx.test.utils import WordprocessingDocumentFactory -class HyperlinkSimpleFieldTestCase(DocumentGeneratorTestCase): +class HeadingTestCase(DocumentGeneratorTestCase): + def test_styles_are_ignored(self): + style_xml = ''' + + ''' + + document_xml = ''' +

+ + + + + + AAA + + +

+ ''' + document = WordprocessingDocumentFactory() + document.add(StyleDefinitionsPart, style_xml) + document.add(MainDocumentPart, document_xml) + + expected_html = ''' +

AAA

+ ''' + self.assert_document_generates_html(document, expected_html) + + +class HyperlinkTestCase(DocumentGeneratorTestCase): def test_single_run(self): document_xml = '''