Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions src/python_docx_replace/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"]

Expand All @@ -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:
Expand Down Expand Up @@ -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))
11 changes: 11 additions & 0 deletions src/python_docx_replace/paragraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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)
2 changes: 1 addition & 1 deletion test/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
Binary file modified test/hello.docx
Binary file not shown.