超链接¶
Word允许将超链接放置在文档中可以出现段落的任何位置。实际的超链接元素是的对等元素 Run
。
该链接可以是到诸如网站的外部资源的链接,也可以是到文档中另一位置的内部链接。该链接也可以是 mailto: URI或对可访问本地或网络文件系统上的文件的引用。
超链接的可见文本保存在一个或多个运行中。从技术上讲,一个超链接可以有零运行,但这只会在人为设计的情况下发生(否则就没有什么可点击的)。像往常一样,每次运行都可以有自己不同的文本格式(字体),例如,超链接中的一个单词可以是粗体等。默认情况下,Word应用内置的 Hyperlink 字符样式添加到新插入的超链接。与其他文本一样,由于在不同的“修订-保存”编辑会话中(在“保存”命令之间)进行编辑,超链接文本通常可能被分成多个运行。
请注意,呈现的分页符可能出现在超链接的中间。
A Hyperlink
是一位 Paragraph
,同龄人 Run
。
TODO:URL编码/解码(如%20)行为(如果有的话)怎么办?
候选方案¶
外部超链接有一个地址和一个可选的锚。内部超链接只有一个锚点。锚点更准确地称为 URI fragment 在Web URL中,并跟在散列标记(“#”)之后。片段分隔符散列字符不存储在XML中。
请注意,锚和地址存储在两个不同的属性中,因此需要连接 .address 和 .anchor 喜欢 f"{address}#{anchor}" 如果你想要整件事。
还请注意,Word不会严格分隔Web URI中的片段,因此它可能会作为地址的一部分出现,或者单独出现在锚属性中,这取决于超链接是如何创作的。根据我有限的经验,使用对话框插入的超链接似乎将其分开,而直接输入到文档中的地址则不会。
Access hyperlinks in a paragraph **
>>> hyperlinks = paragraph.hyperlinks
[<docx.text.hyperlink.Hyperlink at 0x7f...>]
Access hyperlinks in a paragraph in document order with runs **
>>> list(paragraph.iter_inner_content())
[
<docx.text.run.Run at 0x7f...>
<docx.text.hyperlink.Hyperlink at 0x7f...>
<docx.text.run.Run at 0x7f...>
]
Access hyperlink address **
>>> hyperlink.address
'https://google.com/'
Access hyperlink fragment **
>>> hyperlink.fragment
'introduction'
Access hyperlink history (visited or not, True means not visited yet) **
>>> hyperlink.history
True
Access hyperlinks runs **
>>> hyperlink.runs
[
<docx.text.run.Run at 0x7f...>
<docx.text.run.Run at 0x7f...>
<docx.text.run.Run at 0x7f...>
]
Access hyperlink URL **
>>> hyperlink.url
'https://us.com#introduction'
Determine whether a hyperlink contains a rendered page-break **
>>> hyperlink.contains_page_break
False
Access visible text of a hyperlink **
>>> hyperlink.text
'an excellent Wikipedia article on ferrets'
Add an external hyperlink (尚未实施)::
>>> hyperlink = paragraph.add_hyperlink(
... 'About', address='http://us.com', fragment='about'
... )
>>> hyperlink
<docx.text.hyperlink.Hyperlink at 0x7f...>
>>> hyperlink.text
'About'
>>> hyperlink.address
'http://us.com'
>>> hyperlink.fragment
'about'
>>> hyperlink.url
'http://us.com#about'
Add an internal hyperlink (to a bookmark) **
>>> hyperlink = paragraph.add_hyperlink('Section 1', fragment='Section_1')
>>> hyperlink.text
'Section 1'
>>> hyperlink.fragment
'Section_1'
>>> hyperlink.address
''
Modify hyperlink properties **
>>> hyperlink.text = 'Froogle'
>>> hyperlink.text
'Froogle'
>>> hyperlink.address = 'mailto:info@froogle.com?subject=sup dawg?'
>>> hyperlink.address
'mailto:info@froogle.com?subject=sup%20dawg%3F'
>>> hyperlink.anchor = None
>>> hyperlink.anchor
None
Add additional runs to a hyperlink **
>>> hyperlink.text = 'A '
>>> # .insert_run inserts a new run at idx, defaults to idx=-1
>>> hyperlink.insert_run(' link').bold = True
>>> hyperlink.insert_run('formatted', idx=1).bold = True
>>> hyperlink.text
'A formatted link'
>>> [r for r in hyperlink.iter_runs()]
[<docx.text.run.Run at 0x7fa...>,
<docx.text.run.Run at 0x7fb...>,
<docx.text.run.Run at 0x7fc...>]
Iterate over the run-level items a paragraph contains **
>>> paragraph = document.add_paragraph('A paragraph having a link to: ')
>>> paragraph.add_hyperlink(text='github', address='http://github.com')
>>> [item for item in paragraph.iter_run_level_items()]:
[<docx.text.paragraph.Run at 0x7fd...>, <docx.text.paragraph.Hyperlink at 0x7fe...>]
Paragraph.text now includes text contained in a hyperlink **
>>> paragraph.text
'A paragraph having a link to: github'
言语行为¶
W:HYPERLINK上w:HISTORY属性的语义是什么?我怀疑这表明链接应该显示为蓝色(未访问)或紫色(已访问)。我倾向于认为我们需要它作为超链接的读/写属性。我们应该看看MS API在这方面做了什么。
我们可能需要对w:锚实施一些字符集限制。例如,单词似乎不喜欢空格或连字符。简单类型ST_STRING看起来并不能解决这个问题。
我们需要测试Hyperlink.Address中特殊字符(如空格和问号)的URL转义。
加载包含具有与现有书签不匹配的锚定值的内部超链接的文档时,Word会执行什么操作?我们会想知道,因为我们肯定会收到那些不匹配的人的支持询问,并想知道为什么他们会得到修复错误或其他什么。
XML样本¶
外部链接¶
外部超链接的地址(URL)存储在Document.xml.rels文件中,以w:HYPERLINK@r:ID属性::
<w:p>
<w:r>
<w:t xml:space="preserve">This is an external link to </w:t>
</w:r>
<w:hyperlink r:id="rId4">
<w:r>
<w:rPr>
<w:rStyle w:val="Hyperlink"/>
</w:rPr>
<w:t>Google</w:t>
</w:r>
</w:hyperlink>
</w:p>
..。映射到Docent.xml.rels中的关系::
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
<Relationship Id="rId4" Mode="External" Type="http://..." Target="http://google.com/"/>
</Relationships>
超链接可以包含多个文本串(以及大量其他内容,至少在架构指示的范围内):
<w:p>
<w:hyperlink r:id="rId2">
<w:r>
<w:rPr>
<w:rStyle w:val="Hyperlink"/>
</w:rPr>
<w:t xml:space="preserve">A hyperlink containing an </w:t>
</w:r>
<w:r>
<w:rPr>
<w:rStyle w:val="Hyperlink"/>
<w:i/>
</w:rPr>
<w:t>italicized</w:t>
</w:r>
<w:r>
<w:rPr>
<w:rStyle w:val="Hyperlink"/>
</w:rPr>
<w:t xml:space="preserve"> word</w:t>
</w:r>
</w:hyperlink>
</w:p>
内部链接¶
内部链接在Word UI中提供了“跳转到另一个文档位置”的行为。内部链接的区别在于没有r:id属性。在本例中,w:锚属性是必需的。锚属性的值是文档中书签的名称。
示例::
<w:p>
<w:r>
<w:t xml:space="preserve">See </w:t>
</w:r>
<w:hyperlink w:anchor="Section_4">
<w:r>
<w:rPr>
<w:rStyle w:val="Hyperlink"/>
</w:rPr>
<w:t>Section 4</w:t>
</w:r>
</w:hyperlink>
<w:r>
<w:t xml:space="preserve"> for more details.</w:t>
</w:r>
</w:p>
..。在文档的其他地方引用此书签::
<w:p>
<w:bookmarkStart w:id="0" w:name="Section_4"/>
<w:r>
<w:t>Section 4</w:t>
</w:r>
<w:bookmarkEnd w:id="0"/>
</w:p>
架构摘要¶
<xsd:complexType name="CT_P">
<xsd:sequence>
<xsd:element name="pPr" type="CT_PPr" minOccurs="0"/>
<xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="rsidRPr" type="ST_LongHexNumber"/>
<xsd:attribute name="rsidR" type="ST_LongHexNumber"/>
<xsd:attribute name="rsidDel" type="ST_LongHexNumber"/>
<xsd:attribute name="rsidP" type="ST_LongHexNumber"/>
<xsd:attribute name="rsidRDefault" type="ST_LongHexNumber"/>
</xsd:complexType>
<xsd:group name="EG_PContent"> <!-- denormalized -->
<xsd:choice>
<xsd:element name="r" type="CT_R"/>
<xsd:element name="hyperlink" type="CT_Hyperlink"/>
<xsd:element name="fldSimple" type="CT_SimpleField"/>
<xsd:element name="sdt" type="CT_SdtRun"/>
<xsd:element name="customXml" type="CT_CustomXmlRun"/>
<xsd:element name="smartTag" type="CT_SmartTagRun"/>
<xsd:element name="dir" type="CT_DirContentRun"/>
<xsd:element name="bdo" type="CT_BdoContentRun"/>
<xsd:element name="subDoc" type="CT_Rel"/>
<xsd:group ref="EG_RunLevelElts"/>
</xsd:choice>
</xsd:group>
<xsd:complexType name="CT_Hyperlink">
<xsd:group ref="EG_PContent" minOccurs="0" maxOccurs="unbounded"/>
<xsd:attribute name="tgtFrame" type="s:ST_String"/>
<xsd:attribute name="tooltip" type="s:ST_String"/>
<xsd:attribute name="docLocation" type="s:ST_String"/>
<xsd:attribute name="history" type="s:ST_OnOff"/>
<xsd:attribute name="anchor" type="s:ST_String"/>
<xsd:attribute ref="r:id"/>
</xsd:complexType>
<xsd:group name="EG_RunLevelElts">
<xsd:choice>
<xsd:element name="proofErr" type="CT_ProofErr"/>
<xsd:element name="permStart" type="CT_PermStart"/>
<xsd:element name="permEnd" type="CT_Perm"/>
<xsd:element name="bookmarkStart" type="CT_Bookmark"/>
<xsd:element name="bookmarkEnd" type="CT_MarkupRange"/>
<xsd:element name="moveFromRangeStart" type="CT_MoveBookmark"/>
<xsd:element name="moveFromRangeEnd" type="CT_MarkupRange"/>
<xsd:element name="moveToRangeStart" type="CT_MoveBookmark"/>
<xsd:element name="moveToRangeEnd" type="CT_MarkupRange"/>
<xsd:element name="commentRangeStart" type="CT_MarkupRange"/>
<xsd:element name="commentRangeEnd" type="CT_MarkupRange"/>
<xsd:element name="customXmlInsRangeStart" type="CT_TrackChange"/>
<xsd:element name="customXmlInsRangeEnd" type="CT_Markup"/>
<xsd:element name="customXmlDelRangeStart" type="CT_TrackChange"/>
<xsd:element name="customXmlDelRangeEnd" type="CT_Markup"/>
<xsd:element name="customXmlMoveFromRangeStart" type="CT_TrackChange"/>
<xsd:element name="customXmlMoveFromRangeEnd" type="CT_Markup"/>
<xsd:element name="customXmlMoveToRangeStart" type="CT_TrackChange"/>
<xsd:element name="customXmlMoveToRangeEnd" type="CT_Markup"/>
<xsd:element name="ins" type="CT_RunTrackChange"/>
<xsd:element name="del" type="CT_RunTrackChange"/>
<xsd:element name="moveFrom" type="CT_RunTrackChange"/>
<xsd:element name="moveTo" type="CT_RunTrackChange"/>
<xsd:group ref="EG_MathContent" minOccurs="0" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:group>
<xsd:complexType name="CT_R">
<xsd:sequence>
<xsd:group ref="EG_RPr" minOccurs="0"/>
<xsd:group ref="EG_RunInnerContent" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="rsidRPr" type="ST_LongHexNumber"/>
<xsd:attribute name="rsidDel" type="ST_LongHexNumber"/>
<xsd:attribute name="rsidR" type="ST_LongHexNumber"/>
</xsd:complexType>
<xsd:simpleType name="ST_OnOff">
<xsd:union memberTypes="xsd:boolean ST_OnOff1"/>
</xsd:simpleType>
<xsd:simpleType name="ST_OnOff1">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="on"/>
<xsd:enumeration value="off"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="ST_RelationshipId">
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>
<xsd:simpleType name="ST_String">
<xsd:restriction base="xsd:string"/>
</xsd:simpleType>