2
2
Hyperlink
3
3
=========
4
4
5
- Word allows hyperlinks to be placed in a document wherever paragraphs can appear.
5
+ Word allows a hyperlink to be placed in a document wherever a paragraph can appear. The
6
+ actual hyperlink element is a peer of |Run |.
6
7
7
- The target (URL) of a hyperlink may be external, such as a web site, or internal, to
8
- another location in the document.
8
+ The link may be to an external resource such as a web site, or internal, to another
9
+ location in the document. The link may also be a `mailto: ` URI or a reference to a file
10
+ on an accessible local or network filesystem.
9
11
10
12
The visible text of a hyperlink is held in one or more runs. Technically a hyperlink can
11
13
have zero runs, but this occurs only in contrived cases (otherwise there would be
12
14
nothing to click on). As usual, each run can have its own distinct text formatting
13
15
(font), so for example one word in the hyperlink can be bold, etc. By default, Word
14
- applies the built-in `Hyperlink ` character style to a newly inserted hyperlink.
16
+ applies the built-in `Hyperlink ` character style to a newly inserted hyperlink. Like
17
+ other text, the hyperlink text may often be broken into multiple runs as a result of
18
+ edits in different "revision-save" editing sessions (between "Save" commands).
15
19
16
20
Note that rendered page-breaks can occur in the middle of a hyperlink.
17
21
18
22
A |Hyperlink | is a child of |Paragraph |, a peer of |Run |.
19
23
20
24
25
+ TODO: What about URL-encoding/decoding (like %20) behaviors, if any?
26
+
27
+
21
28
Candidate protocol
22
29
------------------
23
30
24
31
An external hyperlink has an address and an optional anchor. An internal hyperlink has
25
- only an anchor. An anchor is also known as a *URI fragment * and follows a hash mark
26
- ("#").
32
+ only an anchor. An anchor is more precisely known as a *URI fragment * in a web URL and
33
+ follows a hash mark ("#"). The fragment-separator hash character is not stored in the
34
+ XML.
35
+
36
+ Note that the anchor and address are stored in two distinct attributes, so you need to
37
+ concatenate `.address ` and `.anchor ` like `f"{address}#{anchor}" ` if you want the whole
38
+ thing.
27
39
28
- Note that the anchor and URL are stored in two distinct attributes, so you need to
29
- concatenate `.address ` and `.anchor ` if you want the whole thing.
40
+ Also note that Word does not rigorously separate a fragment in a web URI so it may
41
+ appear as part of the address or separately in the anchor attribute, depending on how
42
+ the hyperlink was authored. Hyperlinks inserted using the dialog-box seem to separate it
43
+ and addresses typed into the document directly don't, based on my limited experience.
30
44
31
45
.. highlight :: python
32
46
@@ -49,6 +63,16 @@ concatenate `.address` and `.anchor` if you want the whole thing.
49
63
>>> hyperlink.address
50
64
'https://google.com/'
51
65
66
+ **Access hyperlink fragment **::
67
+
68
+ >>> hyperlink.fragment
69
+ 'introduction'
70
+
71
+ **Access hyperlink history (visited or not, True means not visited yet) **::
72
+
73
+ >>> hyperlink.history
74
+ True
75
+
52
76
**Access hyperlinks runs **::
53
77
54
78
>>> hyperlink.runs
@@ -58,6 +82,11 @@ concatenate `.address` and `.anchor` if you want the whole thing.
58
82
<docx.text.run.Run at 0x7f...>
59
83
]
60
84
85
+ **Access hyperlink URL **::
86
+
87
+ >>> hyperlink.url
88
+ 'https://us.com#introduction'
89
+
61
90
**Determine whether a hyperlink contains a rendered page-break **::
62
91
63
92
>>> hyperlink.contains_page_break
@@ -68,29 +97,31 @@ concatenate `.address` and `.anchor` if you want the whole thing.
68
97
>>> hyperlink.text
69
98
'an excellent Wikipedia article on ferrets'
70
99
71
- **Add an external hyperlink **::
100
+ **Add an external hyperlink ** (not yet implemented) ::
72
101
73
102
>>> hyperlink = paragraph.add_hyperlink(
74
- 'About', address='http://us.com', anchor ='about'
75
- )
103
+ ... 'About', address='http://us.com', fragment ='about'
104
+ ... )
76
105
>>> hyperlink
77
106
<docx.text.hyperlink.Hyperlink at 0x7f...>
78
107
>>> hyperlink.text
79
108
'About'
80
109
>>> hyperlink.address
81
110
'http://us.com'
82
- >>> hyperlink.anchor
111
+ >>> hyperlink.fragment
83
112
'about'
113
+ >>> hyperlink.url
114
+ 'http://us.com#about'
84
115
85
116
**Add an internal hyperlink (to a bookmark) **::
86
117
87
- >>> hyperlink = paragraph.add_hyperlink('Section 1', anchor ='Section_1')
118
+ >>> hyperlink = paragraph.add_hyperlink('Section 1', fragment ='Section_1')
88
119
>>> hyperlink.text
89
120
'Section 1'
90
- >>> hyperlink.anchor
121
+ >>> hyperlink.fragment
91
122
'Section_1'
92
123
>>> hyperlink.address
93
- None
124
+ ''
94
125
95
126
**Modify hyperlink properties **::
96
127
@@ -183,8 +214,8 @@ file, keyed by the w:hyperlink@r:id attribute::
183
214
<Relationship Id="rId4" Mode="External" Type="http://..." Target="http://google.com/"/>
184
215
</Relationships>
185
216
186
- A hyperlink can contain multiple runs of text (and a whole lot of other
187
- stuff, including nested hyperlinks, at least as far as the schema indicates)::
217
+ A hyperlink can contain multiple runs of text (and a whole lot of other stuff, at least
218
+ as far as the schema indicates)::
188
219
189
220
<w:p>
190
221
<w:hyperlink r:id="rId2">
@@ -256,97 +287,97 @@ Schema excerpt
256
287
257
288
::
258
289
259
- <xsd:complexType name="CT_P">
260
- <xsd:sequence>
261
- <xsd:element name="pPr" type="CT_PPr" minOccurs="0"/>
262
- <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/>
263
- </xsd:sequence>
264
- <xsd:attribute name="rsidRPr" type="ST_LongHexNumber"/>
265
- <xsd:attribute name="rsidR" type="ST_LongHexNumber"/>
266
- <xsd:attribute name="rsidDel" type="ST_LongHexNumber"/>
267
- <xsd:attribute name="rsidP" type="ST_LongHexNumber"/>
268
- <xsd:attribute name="rsidRDefault" type="ST_LongHexNumber"/>
269
- </xsd:complexType>
270
-
271
- <xsd:group name="EG_PContent"> <!-- denormalized -->
272
- <xsd:choice>
273
- <xsd:element name="r" type="CT_R"/>
274
- <xsd:element name="hyperlink" type="CT_Hyperlink"/>
275
- <xsd:element name="fldSimple" type="CT_SimpleField"/>
276
- <xsd:element name="sdt" type="CT_SdtRun"/>
277
- <xsd:element name="customXml" type="CT_CustomXmlRun"/>
278
- <xsd:element name="smartTag" type="CT_SmartTagRun"/>
279
- <xsd:element name="dir" type="CT_DirContentRun"/>
280
- <xsd:element name="bdo" type="CT_BdoContentRun"/>
281
- <xsd:element name="subDoc" type="CT_Rel"/>
282
- <xsd:group ref="EG_RunLevelElts"/>
283
- </xsd:choice>
284
- </xsd:group>
285
-
286
- <xsd:complexType name="CT_Hyperlink">
287
- <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/>
288
- <xsd:attribute name="tgtFrame" type="s:ST_String"/>
289
- <xsd:attribute name="tooltip" type="s:ST_String"/>
290
- <xsd:attribute name="docLocation" type="s:ST_String"/>
291
- <xsd:attribute name="history" type="s:ST_OnOff"/>
292
- <xsd:attribute name="anchor" type="s:ST_String"/>
293
- <xsd:attribute ref="r:id"/>
294
- </xsd:complexType>
295
-
296
- <xsd:group name="EG_RunLevelElts">
297
- <xsd:choice>
298
- <xsd:element name="proofErr" type="CT_ProofErr"/>
299
- <xsd:element name="permStart" type="CT_PermStart"/>
300
- <xsd:element name="permEnd" type="CT_Perm"/>
301
- <xsd:element name="bookmarkStart" type="CT_Bookmark"/>
302
- <xsd:element name="bookmarkEnd" type="CT_MarkupRange"/>
303
- <xsd:element name="moveFromRangeStart" type="CT_MoveBookmark"/>
304
- <xsd:element name="moveFromRangeEnd" type="CT_MarkupRange"/>
305
- <xsd:element name="moveToRangeStart" type="CT_MoveBookmark"/>
306
- <xsd:element name="moveToRangeEnd" type="CT_MarkupRange"/>
307
- <xsd:element name="commentRangeStart" type="CT_MarkupRange"/>
308
- <xsd:element name="commentRangeEnd" type="CT_MarkupRange"/>
309
- <xsd:element name="customXmlInsRangeStart" type="CT_TrackChange"/>
310
- <xsd:element name="customXmlInsRangeEnd" type="CT_Markup"/>
311
- <xsd:element name="customXmlDelRangeStart" type="CT_TrackChange"/>
312
- <xsd:element name="customXmlDelRangeEnd" type="CT_Markup"/>
313
- <xsd:element name="customXmlMoveFromRangeStart" type="CT_TrackChange"/>
314
- <xsd:element name="customXmlMoveFromRangeEnd" type="CT_Markup"/>
315
- <xsd:element name="customXmlMoveToRangeStart" type="CT_TrackChange"/>
316
- <xsd:element name="customXmlMoveToRangeEnd" type="CT_Markup"/>
317
- <xsd:element name="ins" type="CT_RunTrackChange"/>
318
- <xsd:element name="del" type="CT_RunTrackChange"/>
319
- <xsd:element name="moveFrom" type="CT_RunTrackChange"/>
320
- <xsd:element name="moveTo" type="CT_RunTrackChange"/>
321
- <xsd:group ref="EG_MathContent" minOccurs="0" maxOccurs="unbounded"/>
322
- </xsd:choice>
323
- </xsd:group>
324
-
325
- <xsd:complexType name="CT_R">
326
- <xsd:sequence>
327
- <xsd:group ref="EG_RPr" minOccurs="0"/>
328
- <xsd:group ref="EG_RunInnerContent" minOccurs="0" maxOccurs="unbounded"/>
329
- </xsd:sequence>
330
- <xsd:attribute name="rsidRPr" type="ST_LongHexNumber"/>
331
- <xsd:attribute name="rsidDel" type="ST_LongHexNumber"/>
332
- <xsd:attribute name="rsidR" type="ST_LongHexNumber"/>
333
- </xsd:complexType>
334
-
335
- <xsd:simpleType name="ST_OnOff">
336
- <xsd:union memberTypes="xsd:boolean ST_OnOff1"/>
337
- </xsd:simpleType>
338
-
339
- <xsd:simpleType name="ST_OnOff1">
340
- <xsd:restriction base="xsd:string">
341
- <xsd:enumeration value="on"/>
342
- <xsd:enumeration value="off"/>
343
- </xsd:restriction>
344
- </xsd:simpleType>
345
-
346
- <xsd:simpleType name="ST_RelationshipId">
347
- <xsd:restriction base="xsd:string"/>
348
- </xsd:simpleType>
349
-
350
- <xsd:simpleType name="ST_String">
351
- <xsd:restriction base="xsd:string"/>
352
- </xsd:simpleType>
290
+ <xsd:complexType name="CT_P">
291
+ <xsd:sequence>
292
+ <xsd:element name="pPr" type="CT_PPr" minOccurs="0"/>
293
+ <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/>
294
+ </xsd:sequence>
295
+ <xsd:attribute name="rsidRPr" type="ST_LongHexNumber"/>
296
+ <xsd:attribute name="rsidR" type="ST_LongHexNumber"/>
297
+ <xsd:attribute name="rsidDel" type="ST_LongHexNumber"/>
298
+ <xsd:attribute name="rsidP" type="ST_LongHexNumber"/>
299
+ <xsd:attribute name="rsidRDefault" type="ST_LongHexNumber"/>
300
+ </xsd:complexType>
301
+
302
+ <xsd:group name="EG_PContent"> <!-- denormalized -->
303
+ <xsd:choice>
304
+ <xsd:element name="r" type="CT_R"/>
305
+ <xsd:element name="hyperlink" type="CT_Hyperlink"/>
306
+ <xsd:element name="fldSimple" type="CT_SimpleField"/>
307
+ <xsd:element name="sdt" type="CT_SdtRun"/>
308
+ <xsd:element name="customXml" type="CT_CustomXmlRun"/>
309
+ <xsd:element name="smartTag" type="CT_SmartTagRun"/>
310
+ <xsd:element name="dir" type="CT_DirContentRun"/>
311
+ <xsd:element name="bdo" type="CT_BdoContentRun"/>
312
+ <xsd:element name="subDoc" type="CT_Rel"/>
313
+ <xsd:group ref="EG_RunLevelElts"/>
314
+ </xsd:choice>
315
+ </xsd:group>
316
+
317
+ <xsd:complexType name="CT_Hyperlink">
318
+ <xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/>
319
+ <xsd:attribute name="tgtFrame" type="s:ST_String"/>
320
+ <xsd:attribute name="tooltip" type="s:ST_String"/>
321
+ <xsd:attribute name="docLocation" type="s:ST_String"/>
322
+ <xsd:attribute name="history" type="s:ST_OnOff"/>
323
+ <xsd:attribute name="anchor" type="s:ST_String"/>
324
+ <xsd:attribute ref="r:id"/>
325
+ </xsd:complexType>
326
+
327
+ <xsd:group name="EG_RunLevelElts">
328
+ <xsd:choice>
329
+ <xsd:element name="proofErr" type="CT_ProofErr"/>
330
+ <xsd:element name="permStart" type="CT_PermStart"/>
331
+ <xsd:element name="permEnd" type="CT_Perm"/>
332
+ <xsd:element name="bookmarkStart" type="CT_Bookmark"/>
333
+ <xsd:element name="bookmarkEnd" type="CT_MarkupRange"/>
334
+ <xsd:element name="moveFromRangeStart" type="CT_MoveBookmark"/>
335
+ <xsd:element name="moveFromRangeEnd" type="CT_MarkupRange"/>
336
+ <xsd:element name="moveToRangeStart" type="CT_MoveBookmark"/>
337
+ <xsd:element name="moveToRangeEnd" type="CT_MarkupRange"/>
338
+ <xsd:element name="commentRangeStart" type="CT_MarkupRange"/>
339
+ <xsd:element name="commentRangeEnd" type="CT_MarkupRange"/>
340
+ <xsd:element name="customXmlInsRangeStart" type="CT_TrackChange"/>
341
+ <xsd:element name="customXmlInsRangeEnd" type="CT_Markup"/>
342
+ <xsd:element name="customXmlDelRangeStart" type="CT_TrackChange"/>
343
+ <xsd:element name="customXmlDelRangeEnd" type="CT_Markup"/>
344
+ <xsd:element name="customXmlMoveFromRangeStart" type="CT_TrackChange"/>
345
+ <xsd:element name="customXmlMoveFromRangeEnd" type="CT_Markup"/>
346
+ <xsd:element name="customXmlMoveToRangeStart" type="CT_TrackChange"/>
347
+ <xsd:element name="customXmlMoveToRangeEnd" type="CT_Markup"/>
348
+ <xsd:element name="ins" type="CT_RunTrackChange"/>
349
+ <xsd:element name="del" type="CT_RunTrackChange"/>
350
+ <xsd:element name="moveFrom" type="CT_RunTrackChange"/>
351
+ <xsd:element name="moveTo" type="CT_RunTrackChange"/>
352
+ <xsd:group ref="EG_MathContent" minOccurs="0" maxOccurs="unbounded"/>
353
+ </xsd:choice>
354
+ </xsd:group>
355
+
356
+ <xsd:complexType name="CT_R">
357
+ <xsd:sequence>
358
+ <xsd:group ref="EG_RPr" minOccurs="0"/>
359
+ <xsd:group ref="EG_RunInnerContent" minOccurs="0" maxOccurs="unbounded"/>
360
+ </xsd:sequence>
361
+ <xsd:attribute name="rsidRPr" type="ST_LongHexNumber"/>
362
+ <xsd:attribute name="rsidDel" type="ST_LongHexNumber"/>
363
+ <xsd:attribute name="rsidR" type="ST_LongHexNumber"/>
364
+ </xsd:complexType>
365
+
366
+ <xsd:simpleType name="ST_OnOff">
367
+ <xsd:union memberTypes="xsd:boolean ST_OnOff1"/>
368
+ </xsd:simpleType>
369
+
370
+ <xsd:simpleType name="ST_OnOff1">
371
+ <xsd:restriction base="xsd:string">
372
+ <xsd:enumeration value="on"/>
373
+ <xsd:enumeration value="off"/>
374
+ </xsd:restriction>
375
+ </xsd:simpleType>
376
+
377
+ <xsd:simpleType name="ST_RelationshipId">
378
+ <xsd:restriction base="xsd:string"/>
379
+ </xsd:simpleType>
380
+
381
+ <xsd:simpleType name="ST_String">
382
+ <xsd:restriction base="xsd:string"/>
383
+ </xsd:simpleType>
0 commit comments