diff options
| author | Michael Williamson <mike@zwobble.org> | 2015-06-17 15:05:19 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2015-06-17 15:05:19 +0100 |
| commit | 147fabb2b2e00f7790304b7a1e1f40cdb564cb4f (patch) | |
| tree | fcd72fdbdf3681acd1dff8dd6237143a80914cfa | |
| parent | 35d3dd58400d5310fe05ebe8e070c96c756edac0 (diff) | |
Support underlines in style map
| -rw-r--r-- | mammoth/conversion.py | 55 | ||||
| -rw-r--r-- | mammoth/document_matchers.py | 4 | ||||
| -rw-r--r-- | mammoth/html_generation.py | 18 | ||||
| -rw-r--r-- | mammoth/style_reader/document_matcher_reader.py | 6 | ||||
| -rw-r--r-- | tests/conversion_tests.py | 24 | ||||
| -rw-r--r-- | tests/html_generation_tests.py | 14 | ||||
| -rw-r--r-- | tests/mammoth_tests.py | 7 | ||||
| -rw-r--r-- | tests/style_reader_tests.py | 7 |
8 files changed, 107 insertions, 28 deletions
diff --git a/mammoth/conversion.py b/mammoth/conversion.py index 1569849..fc35efe 100644 --- a/mammoth/conversion.py +++ b/mammoth/conversion.py @@ -6,7 +6,7 @@ import base64 import random from . import documents, results, html_paths, images, writers -from .html_generation import HtmlGenerator, satisfy_html_path +from .html_generation import HtmlGenerator, satisfy_html_path, append_html_path def convert_document_element_to_html(element, @@ -57,7 +57,7 @@ class DocumentConverter(object): documents.NoteReference: self._convert_note_reference, documents.Note: self._convert_note, } - self._convert_underline = convert_underline + self._convert_underline = convert_underline or self._default_convert_underline def convert_element_to_html(self, element, html_generator): @@ -97,12 +97,18 @@ class DocumentConverter(object): run_generator.start("sup") if run.vertical_alignment == documents.VerticalAlignment.subscript: run_generator.start("sub") - if run.is_underline and self._convert_underline is not None: + if run.is_underline: self._convert_underline(run_generator) self._convert_elements_to_html(run.children, run_generator) run_generator.end_all() html_generator.append(run_generator) - + + + def _default_convert_underline(self, run_generator): + style = self._find_style(None, "underline") + if style is not None: + append_html_path(run_generator, style.html_path) + def _convert_text(self, text, html_generator): html_generator.text(text.value) @@ -201,10 +207,9 @@ class DocumentConverter(object): def _find_html_path(self, element, element_type, default): - for style in self._style_map: - document_matcher = style.document_matcher - if _document_matcher_matches(document_matcher, element, element_type): - return style.html_path + style = self._find_style(element, element_type) + if style is not None: + return style.html_path if element.style_id is not None: self.messages.append(results.warning( @@ -213,7 +218,12 @@ class DocumentConverter(object): )) return default - + + def _find_style(self, element, element_type): + for style in self._style_map: + document_matcher = style.document_matcher + if _document_matcher_matches(document_matcher, element, element_type): + return style def _note_html_id(self, note): return self._html_id("{0}-{1}".format(note.note_type, note.note_id)) @@ -226,18 +236,21 @@ class DocumentConverter(object): def _document_matcher_matches(matcher, element, element_type): - return ( - matcher.element_type == element_type and ( - matcher.style_id is None or - matcher.style_id == element.style_id - ) and ( - matcher.style_name is None or - element.style_name is not None and (matcher.style_name.upper() == element.style_name.upper()) - ) and ( - element_type != "paragraph" or - matcher.numbering is None or - matcher.numbering == element.numbering + if matcher.element_type == "underline": + return element_type == "underline" + else: + return ( + matcher.element_type == element_type and ( + matcher.style_id is None or + matcher.style_id == element.style_id + ) and ( + matcher.style_name is None or + element.style_name is not None and (matcher.style_name.upper() == element.style_name.upper()) + ) and ( + element_type != "paragraph" or + matcher.numbering is None or + matcher.numbering == element.numbering + ) ) - ) _up_arrow = "↑" diff --git a/mammoth/document_matchers.py b/mammoth/document_matchers.py index 222ee73..07d5be2 100644 --- a/mammoth/document_matchers.py +++ b/mammoth/document_matchers.py @@ -15,3 +15,7 @@ def run(style_id=None, style_name=None): RunMatcher = collections.namedtuple("RunMatcher", ["style_id", "style_name"]) RunMatcher.element_type = "run" + + +class underline(object): + element_type = "underline" diff --git a/mammoth/html_generation.py b/mammoth/html_generation.py index c7f4f38..e538f6e 100644 --- a/mammoth/html_generation.py +++ b/mammoth/html_generation.py @@ -68,12 +68,22 @@ def satisfy_html_path(generator, path): generator.end() for element in path.elements[first_unsatisfied_index:]: - attributes = {} - if element.class_names: - attributes["class"] = _generate_class_attribute(element) - generator.start(element.names[0], attributes=attributes) + _append_element(generator, element) + + +def append_html_path(generator, path): + for element in path.elements: + _append_element(generator, element) + + +def _append_element(generator, element): + attributes = {} + if element.class_names: + attributes["class"] = _generate_class_attribute(element) + generator.start(element.names[0], attributes=attributes) + def _find_first_unsatisfied_index(generator, path): for index, (generated_element, path_element) in enumerate(zip(generator._stack, path.elements)): if not _is_element_match(generated_element, path_element): diff --git a/mammoth/style_reader/document_matcher_reader.py b/mammoth/style_reader/document_matcher_reader.py index 3dc9892..56c4626 100644 --- a/mammoth/style_reader/document_matcher_reader.py +++ b/mammoth/style_reader/document_matcher_reader.py @@ -14,6 +14,8 @@ def read_document_matcher_node(root_node): return _read_paragraph_node(element_node) elif element_node.expr_name == "run": return _read_run_node(element_node) + elif element_node.expr_name == "underline": + return document_matchers.underline def _read_paragraph_node(paragraph_node): @@ -53,7 +55,9 @@ def _read_list_node(list_node): return None grammar_text = r""" -document_matcher = paragraph / run +document_matcher = paragraph / run / underline + +underline = "u" paragraph = "p" style_id? style_name_specifier? list? diff --git a/tests/conversion_tests.py b/tests/conversion_tests.py index 4b5b461..19df77f 100644 --- a/tests/conversion_tests.py +++ b/tests/conversion_tests.py @@ -172,7 +172,7 @@ def underline_runs_are_ignored_by_default(): @istest -def underline_runs_can_be_wrapped_in_tags(): +def underline_runs_can_be_wrapped_in_tags_using_convert_underline_argument(): result = convert_document_element_to_html( documents.run(children=[documents.text("Hello")], is_underline=True), convert_underline=mammoth.underline.element("u") @@ -181,6 +181,28 @@ def underline_runs_can_be_wrapped_in_tags(): @istest +def underline_runs_can_be_mapped_using_style_mapping(): + result = convert_document_element_to_html( + documents.run(children=[documents.text("Hello")], is_underline=True), + style_map=[ + style_reader.read_style("u => em") + ] + ) + assert_equal("<em>Hello</em>", result.value) + + +@istest +def style_mapping_for_underline_runs_does_not_close_parent_elements(): + result = convert_document_element_to_html( + documents.run(children=[documents.text("Hello")], is_underline=True, is_bold=True), + style_map=[ + style_reader.read_style("u => em") + ] + ) + assert_equal("<strong><em>Hello</em></strong>", result.value) + + +@istest def superscript_runs_are_wrapped_in_sup_tags(): result = convert_document_element_to_html( documents.run( diff --git a/tests/html_generation_tests.py b/tests/html_generation_tests.py index ccb0e7e..2375564 100644 --- a/tests/html_generation_tests.py +++ b/tests/html_generation_tests.py @@ -1,6 +1,6 @@ from nose.tools import istest, assert_equal -from mammoth.html_generation import HtmlGenerator, satisfy_html_path +from mammoth.html_generation import HtmlGenerator, satisfy_html_path, append_html_path from mammoth import html_paths, writers @@ -171,5 +171,17 @@ class SatisfyPathTests(object): assert_equal('<p class="tip">HelpTip', generator.as_string()) +@istest +class AppendPathTests(object): + @istest + def already_opened_elements_are_not_closed(self): + generator = _create_html_generator() + generator.start("strong") + path = html_paths.path([html_paths.element(["em"])]) + append_html_path(generator, path) + generator.text("Hello!") + assert_equal('<strong><em>Hello!', generator.as_string()) + + def _create_html_generator(): return HtmlGenerator(writers.writer) diff --git a/tests/mammoth_tests.py b/tests/mammoth_tests.py index a1b396c..e7e7e64 100644 --- a/tests/mammoth_tests.py +++ b/tests/mammoth_tests.py @@ -124,6 +124,13 @@ def underline_can_be_configured_with_convert_underline_option(): @istest +def underline_can_be_configured_with_style_mapping(): + with open(test_path("underline.docx"), "rb") as fileobj: + result = mammoth.convert_to_html(fileobj=fileobj, style_map="u => em") + assert_equal('<p><strong>The </strong><strong><em>Sunset</em></strong><strong> Tree</strong></p>', result.value) + + +@istest def transform_document_is_applied_to_document_before_conversion(): def transform_document(document): document.children[0].style_id = "Heading1" diff --git a/tests/style_reader_tests.py b/tests/style_reader_tests.py index 464cb4a..501629a 100644 --- a/tests/style_reader_tests.py +++ b/tests/style_reader_tests.py @@ -134,6 +134,13 @@ class ReadDocumentMatcherTests(object): read_document_matcher("r[style-name='Emphasis']") ) + @istest + def reads_underline(self): + assert_equal( + document_matchers.underline, + read_document_matcher("u") + ) + @istest def document_matcher_is_mapped_to_html_path_using_fat_arrow(): |
