diff options
| -rw-r--r-- | NEWS | 2 | ||||
| -rw-r--r-- | mammoth/docx/body_xml.py | 30 | ||||
| -rw-r--r-- | mammoth/docx/complex_fields.py | 8 | ||||
| -rw-r--r-- | tests/docx/body_xml_tests.py | 27 |
4 files changed, 49 insertions, 18 deletions
@@ -2,6 +2,8 @@ * When extracting raw text, convert tab elements to tab characters. +* Handle internal hyperlinks created with complex fields. + # 1.4.16 * Handle w:num with invalid w:abstractNumId. diff --git a/mammoth/docx/body_xml.py b/mammoth/docx/body_xml.py index 8329bcf..4c66ae8 100644 --- a/mammoth/docx/body_xml.py +++ b/mammoth/docx/body_xml.py @@ -96,11 +96,11 @@ def _create_reader(numbering, content_types, relationships, styles, docx_file, f is_small_caps = read_boolean_element(properties.find_child("w:smallCaps")) def add_complex_field_hyperlink(children): - hyperlink_href = current_hyperlink_href() - if hyperlink_href is None: + hyperlink_kwargs = current_hyperlink_kwargs() + if hyperlink_kwargs is None: return children else: - return [documents.hyperlink(href=hyperlink_href, children=children)] + return [documents.hyperlink(children=children, **hyperlink_kwargs)] return _ReadResult.map_results( _read_run_style(properties), @@ -155,10 +155,10 @@ def _create_reader(numbering, content_types, relationships, styles, docx_file, f current_instr_text = [] complex_field_stack = [] - def current_hyperlink_href(): + def current_hyperlink_kwargs(): for complex_field in reversed(complex_field_stack): if isinstance(complex_field, complex_fields.Hyperlink): - return complex_field.href + return complex_field.kwargs return None @@ -171,21 +171,25 @@ def _create_reader(numbering, content_types, relationships, styles, docx_file, f complex_field_stack.pop() elif fld_char_type == "separate": instr_text = "".join(current_instr_text) - hyperlink_href = parse_hyperlink_field_code(instr_text) - if hyperlink_href is None: + hyperlink_kwargs = parse_hyperlink_field_code(instr_text) + if hyperlink_kwargs is None: complex_field = complex_fields.unknown else: - complex_field = complex_fields.hyperlink(hyperlink_href) + complex_field = complex_fields.hyperlink(hyperlink_kwargs) complex_field_stack.pop() complex_field_stack.append(complex_field) return _empty_result def parse_hyperlink_field_code(instr_text): - result = re.match(r'\s*HYPERLINK "(.*)"', instr_text) - if result is None: - return None - else: - return result.group(1) + external_link_result = re.match(r'\s*HYPERLINK "(.*)"', instr_text) + if external_link_result is not None: + return dict(href=external_link_result.group(1)) + + internal_link_result = re.match(r'\s*HYPERLINK\s+\\l\s+"(.*)"', instr_text) + if internal_link_result is not None: + return dict(anchor=internal_link_result.group(1)) + + return None def read_instr_text(element): current_instr_text.append(_inner_text(element)) diff --git a/mammoth/docx/complex_fields.py b/mammoth/docx/complex_fields.py index d1d95af..75bc05a 100644 --- a/mammoth/docx/complex_fields.py +++ b/mammoth/docx/complex_fields.py @@ -3,9 +3,9 @@ class unknown(object): class Hyperlink(object): - def __init__(self, href): - self.href = href + def __init__(self, kwargs): + self.kwargs = kwargs -def hyperlink(href): - return Hyperlink(href) +def hyperlink(kwargs): + return Hyperlink(kwargs=kwargs) diff --git a/tests/docx/body_xml_tests.py b/tests/docx/body_xml_tests.py index 664b438..4cd54eb 100644 --- a/tests/docx/body_xml_tests.py +++ b/tests/docx/body_xml_tests.py @@ -418,7 +418,7 @@ class ComplexFieldTests(object): return self._is_hyperlinked_run(children=[]) @istest - def runs_in_a_complex_field_for_hyperlinks_are_read_as_hyperlinks(self): + def runs_in_a_complex_field_for_hyperlinks_without_switch_are_read_as_external_hyperlinks(self): element = xml_element("w:p", {}, [ self._BEGIN_COMPLEX_FIELD, self._HYPERLINK_INSTRTEXT, @@ -441,6 +441,31 @@ class ComplexFieldTests(object): ))) @istest + def runs_in_a_complex_field_for_hyperlinks_with_l_switch_are_read_as_internal_hyperlinks(self): + element = xml_element("w:p", {}, [ + self._BEGIN_COMPLEX_FIELD, + xml_element("w:instrText", {}, [ + xml_text(' HYPERLINK \\l "InternalLink"'), + ]), + self._SEPARATE_COMPLEX_FIELD, + _run_element_with_text("this is a hyperlink"), + self._END_COMPLEX_FIELD, + ]) + paragraph = _read_and_get_document_xml_element(element) + + assert_that(paragraph, is_paragraph(children=is_sequence( + is_empty_run, + self._is_empty_hyperlinked_run, + self._is_hyperlinked_run( + anchor="InternalLink", + children=is_sequence( + is_text("this is a hyperlink"), + ), + ), + is_empty_run, + ))) + + @istest def runs_after_a_complex_field_for_hyperlinks_are_not_read_as_hyperlinks(self): element = xml_element("w:p", {}, [ self._BEGIN_COMPLEX_FIELD, |
