diff --git a/src/python_docx_replace/__init__.py b/src/python_docx_replace/__init__.py index f958e52..40aff4f 100644 --- a/src/python_docx_replace/__init__.py +++ b/src/python_docx_replace/__init__.py @@ -2,6 +2,8 @@ from python_docx_replace.exceptions import EndTagNotFound, InitialTagNotFound, TableIndexNotFound from python_docx_replace.paragraph import Paragraph +from docx.opc.constants import RELATIONSHIP_TYPE +import urllib.parse __all__ = ["docx_replace", "docx_blocks", "docx_remove_table"] @@ -26,6 +28,7 @@ def docx_replace(doc, **kwargs: str) -> None: for p in Paragraph.get_all(doc): paragraph = Paragraph(p) paragraph.replace_key(key, str(value)) + _replace_in_links(doc, key, str(value)) def docx_blocks(doc: Any, **kwargs: bool) -> None: @@ -145,3 +148,19 @@ def _search_for_lost_end_tag(doc: Any, initial: str, end: str) -> None: paragraph = Paragraph(p) if paragraph.contains(end): raise InitialTagNotFound(initial, end) + +def _replace_in_links(doc: Any, key: str, value: str): + # Make replacements in hyperlink targets + rel_dicts = [] + rel_dicts.append(doc.part.rels) + + for section in doc.sections: + rel_dicts.append(section.header.part.rels) + rel_dicts.append(section.footer.part.rels) + + for rels in rel_dicts: + for rel_id, rel in rels.items(): + if rel.reltype == RELATIONSHIP_TYPE.HYPERLINK: + target = urllib.parse.unquote(rel._target) + if key in target: + rel._target = urllib.parse.quote(target.replace(key, value)) diff --git a/src/python_docx_replace/paragraph.py b/src/python_docx_replace/paragraph.py index bd88772..98efc00 100644 --- a/src/python_docx_replace/paragraph.py +++ b/src/python_docx_replace/paragraph.py @@ -49,6 +49,7 @@ def replace_key(self, key, value) -> None: self._simple_replace_key(key, value) if key in self.p.text: self._complex_replace_key(key, value) + self._replace_hyperlinks(key, value) def replace_block(self, initial, end, keep_block) -> None: block_handler = BlockHandler(self.p) @@ -74,3 +75,13 @@ def _complex_replace_key(self, key, value) -> None: # if the key appears more than once in the paragraph, it will replaced all key_changer = KeyChanger(self.p, key, value) key_changer.replace() + + def _replace_hyperlinks(self, key, value) -> None: + # Make replacements in hyperlink texts + for link in self.p._element.xpath(".//w:hyperlink"): + try: + inner_run = link.xpath("w:r", namespaces=link.nsmap)[0] + except IndexError: + continue + if key in inner_run.text: + inner_run.text = inner_run.text.replace(key, value) diff --git a/test/app.py b/test/app.py index eeac831..6c7232f 100644 --- a/test/app.py +++ b/test/app.py @@ -5,7 +5,7 @@ def manual_test(): doc = Document("test/hello.docx") - docx_replace(doc, name="Ivan Bicalho") + docx_replace(doc, name="Ivan Bicalho", github_name="ivanbicalho") docx_blocks(doc, block=True) docx_remove_table(doc, 0) diff --git a/test/hello.docx b/test/hello.docx index b870cc0..2cc09f5 100644 Binary files a/test/hello.docx and b/test/hello.docx differ