Skip to content

Commit 9b71461

Browse files
author
yunshi
committed
_wip_: implement hyperlink
1 parent 6086f5c commit 9b71461

File tree

5 files changed

+124
-1
lines changed

5 files changed

+124
-1
lines changed

docx/oxml/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ def OxmlElement(nsptag_str, attrs=None, nsdecls=None):
181181
from .text.paragraph import CT_P
182182
register_element_cls('w:p', CT_P)
183183

184+
from .text.hyperlink import CT_Hyperlink
185+
register_element_cls('w:hyperlink', CT_Hyperlink)
186+
184187
from .text.parfmt import CT_Ind, CT_Jc, CT_PPr, CT_Spacing
185188
register_element_cls('w:ind', CT_Ind)
186189
register_element_cls('w:jc', CT_Jc)

docx/oxml/text/hyperlink.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# encoding: utf-8
2+
3+
"""
4+
Custom element classes related to hyperlinks (CT_Hyperlink).
5+
"""
6+
7+
from ..ns import qn
8+
from ..simpletypes import ST_String, ST_RelationshipId
9+
from ..xmlchemy import (
10+
BaseOxmlElement, OptionalAttribute, ZeroOrMore
11+
)
12+
13+
14+
class CT_Hyperlink(BaseOxmlElement):
15+
"""
16+
``<w:hyperlink>`` element, containing the properties and text for a external hyperlink.
17+
"""
18+
r = ZeroOrMore('w:r')
19+
rid = OptionalAttribute('r:id', ST_RelationshipId)
20+
anchor = OptionalAttribute('w:anchor', ST_String)
21+
22+
@property
23+
def relationship(self):
24+
"""
25+
String contained in ``r:id`` attribute of <w:hyperlink>. It should
26+
point to a URL in the document's relationships.
27+
"""
28+
val = self.get(qn('r:id'))
29+
return val
30+
31+
@relationship.setter
32+
def relationship(self, rId):
33+
self.set(qn('r:id'), rId)
34+
35+
def clear_content(self):
36+
"""
37+
Remove all child elements.
38+
"""
39+
for child in self[:]:
40+
self.remove(child)

docx/oxml/text/paragraph.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class CT_P(BaseOxmlElement):
1414
"""
1515
pPr = ZeroOrOne('w:pPr')
1616
r = ZeroOrMore('w:r')
17+
hyperlink = ZeroOrMore('w:hyperlink')
1718

1819
def _insert_pPr(self, pPr):
1920
self.insert(0, pPr)

docx/text/hyperlink.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# encoding: utf-8
2+
3+
"""
4+
Hyperlink proxy objects.
5+
"""
6+
7+
from __future__ import (
8+
absolute_import, division, print_function, unicode_literals
9+
)
10+
11+
from ..opc.constants import RELATIONSHIP_TYPE as RT
12+
from ..shared import Parented
13+
from .run import Run
14+
15+
16+
class Hyperlink(Parented):
17+
"""
18+
Proxy object wrapping ``<w:hyperlink>`` element.
19+
"""
20+
def __init__(self, hyperlink, parent):
21+
super(Hyperlink, self).__init__(parent)
22+
self._hyperlink = self.element = hyperlink
23+
24+
@property
25+
def address(self):
26+
rId = self._hyperlink.relationship
27+
return self.part.target_ref(rId) if rId else None
28+
29+
@address.setter
30+
def address(self, url):
31+
rId = self.part.relate_to(url, RT.HYPERLINK, is_external=True)
32+
self._hyperlink.relationship = rId
33+
34+
@property
35+
def anchor(self):
36+
return self._hyperlink.anchor
37+
38+
@anchor.setter
39+
def anchor(self, anchor):
40+
self._hyperlink.anchor = anchor
41+
42+
def iter_runs(self):
43+
return [Run(r, self) for r in self._hyperlink.r_lst]
44+
45+
def insert_run(self, text, style=None):
46+
_r = self._hyperlink.add_r()
47+
run = Run(_r, self)
48+
run.text = text
49+
if style:
50+
run.style = style
51+
return run
52+
53+
@property
54+
def text(self):
55+
return ''.join([run.text for run in self.iter_runs()])
56+
57+
@text.setter
58+
def text(self, text):
59+
self._hyperlink.clear_content()
60+
self.insert_run(text)

docx/text/paragraph.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
)
1010

1111
from ..enum.style import WD_STYLE_TYPE
12+
from ..shared import Parented
13+
from .hyperlink import Hyperlink
1214
from .parfmt import ParagraphFormat
1315
from .run import Run
14-
from ..shared import Parented
1516

1617

1718
class Paragraph(Parented):
@@ -22,6 +23,24 @@ def __init__(self, p, parent):
2223
super(Paragraph, self).__init__(parent)
2324
self._p = self._element = p
2425

26+
def add_hyperlink(self, text, address=None, anchor=None, style=None):
27+
28+
_h = self._p.add_hyperlink()
29+
_r = _h.add_r()
30+
hyperlink = Hyperlink(_h, self)
31+
run = Run(_r, hyperlink)
32+
33+
run.text = text
34+
if style:
35+
run.style = style
36+
37+
if address:
38+
hyperlink.address = address
39+
if anchor:
40+
hyperlink.anchor = anchor
41+
42+
return hyperlink
43+
2544
def add_run(self, text=None, style=None):
2645
"""
2746
Append a run to this paragraph containing *text* and having character

0 commit comments

Comments
 (0)