aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS2
-rw-r--r--mammoth/docx/body_xml.py18
-rw-r--r--tests/docx/body_xml_tests.py56
3 files changed, 67 insertions, 9 deletions
diff --git a/NEWS b/NEWS
index 1f91b2d..8de02f5 100644
--- a/NEWS
+++ b/NEWS
@@ -2,6 +2,8 @@
* Handle hyperlinked wp:anchor and wp:inline elements.
+* Handle hyperlink complex fields with unquoted hrefs.
+
# 1.11.0
* Ignore style definitions using a style ID that has already been used.
diff --git a/mammoth/docx/body_xml.py b/mammoth/docx/body_xml.py
index 581c9e2..2a1ffaf 100644
--- a/mammoth/docx/body_xml.py
+++ b/mammoth/docx/body_xml.py
@@ -228,13 +228,19 @@ def _create_reader(numbering, content_types, relationships, styles, docx_file, f
return parse_instr_text(instr_text, fld_char=fld_char)
def parse_instr_text(instr_text, *, fld_char):
- external_link_result = re.match(r'\s*HYPERLINK "(.*)"', instr_text)
- if external_link_result is not None:
- return complex_fields.hyperlink(dict(href=external_link_result.group(1)))
+ link_result = re.match(r'^\s*HYPERLINK\s+(\\l\s+)?(?:"(.*)"|([^\\]\S*))', instr_text)
+ if link_result is not None:
+ if link_result.group(2) is None:
+ location = link_result.group(3)
+ else:
+ location = link_result.group(2)
+
+ if link_result.group(1) is None:
+ hyperlink_args = dict(href=location)
+ else:
+ hyperlink_args = dict(anchor=location)
- internal_link_result = re.match(r'\s*HYPERLINK\s+\\l\s+"(.*)"', instr_text)
- if internal_link_result is not None:
- return complex_fields.hyperlink(dict(anchor=internal_link_result.group(1)))
+ return complex_fields.hyperlink(hyperlink_args)
checkbox_result = re.match(r'\s*FORMCHECKBOX\s*', instr_text)
if checkbox_result is not None:
diff --git a/tests/docx/body_xml_tests.py b/tests/docx/body_xml_tests.py
index 3b62944..664fb5a 100644
--- a/tests/docx/body_xml_tests.py
+++ b/tests/docx/body_xml_tests.py
@@ -451,10 +451,12 @@ class ComplexFieldTests(object):
def _is_empty_hyperlinked_run(self):
return self._is_hyperlinked_run(children=[])
- def test_runs_in_a_complex_field_for_hyperlinks_without_switch_are_read_as_external_hyperlinks(self):
+ def test_runs_in_a_complex_field_for_hyperlinks_without_switch_with_quoted_location_are_read_as_external_hyperlinks(self):
element = xml_element("w:p", {}, [
self._BEGIN_COMPLEX_FIELD,
- self._HYPERLINK_INSTRTEXT,
+ xml_element("w:instrText", {}, [
+ xml_text(' HYPERLINK "http://example.com"')
+ ]),
self._SEPARATE_COMPLEX_FIELD,
_run_element_with_text("this is a hyperlink"),
self._END_COMPLEX_FIELD,
@@ -473,7 +475,31 @@ class ComplexFieldTests(object):
is_empty_run,
)))
- def test_runs_in_a_complex_field_for_hyperlinks_with_l_switch_are_read_as_internal_hyperlinks(self):
+ def test_runs_in_a_complex_field_for_hyperlinks_without_switch_with_unquoted_location_are_read_as_external_hyperlinks(self):
+ element = xml_element("w:p", {}, [
+ self._BEGIN_COMPLEX_FIELD,
+ xml_element("w:instrText", {}, [
+ xml_text(' HYPERLINK http://example.com')
+ ]),
+ 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(
+ href=self._URI,
+ children=is_sequence(
+ is_text("this is a hyperlink"),
+ ),
+ ),
+ is_empty_run,
+ )))
+
+ def test_runs_in_a_complex_field_for_hyperlinks_with_l_switch_with_quoted_location_are_read_as_internal_hyperlinks(self):
element = xml_element("w:p", {}, [
self._BEGIN_COMPLEX_FIELD,
xml_element("w:instrText", {}, [
@@ -497,6 +523,30 @@ class ComplexFieldTests(object):
is_empty_run,
)))
+ def test_runs_in_a_complex_field_for_hyperlinks_with_l_switch_with_unquoted_location_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,
+ )))
+
def test_runs_after_a_complex_field_for_hyperlinks_are_not_read_as_hyperlinks(self):
element = xml_element("w:p", {}, [
self._BEGIN_COMPLEX_FIELD,