vba Word:为什么Word 可以在创建书签时使用特殊字符,而我不能?
vba Word: Why can Word use special chars in bookmark creation, and I cant?
这里是 head-splitter:
我正在尝试以编程方式为文档中的现有标题创建隐藏书签,以便我可以在文档中的其他地方创建指向这些书签的超链接。 (我想使用超链接而不是 cross-references,因此我可以为链接指定我自己的 'Display Text',而使用 cross-refs 是不可能的)。
我希望我的书签以它们相关的标题命名,并带有自定义前缀。
示例:
- 样式:标题 1
- 标题文字:入口和走廊
- 书签名称:_Hd1_Entrance_&_Hallway
我正在指定一个自定义前缀,使每个书签的样式都独一无二,这样我就可以在文档中有 2 个匹配的标题,只要它们采用不同的标题样式即可。 (示例:_Hd1_Entrance_&_Hallway 和 _Hd3_Entrance_&_Hallway)
要注意的是:如果我的标题包含特殊字符,如“&”,我会收到 'Bad Bookmark Name' 错误,这是我理解的,并且在网络上有记录。我只能使用有限的字符集。
那么,如果我使用 Word 自己的对话框手动创建超链接,selecting 'Place In This Document'(例如 "Entrance & Hallway" 之类的标题),Word 管理起来没问题怎么办?创建 Hlink 后,我现在可以在 Word 的 'Bookmarks' 对话框中看到与此 Hlink 相关联的隐藏书签 - 并且它的名字很高兴地命名为“_Entrance _&_Hallway”。这让我很困惑!
有人解释一下吗?我真的很想能够利用同样的功能,但无法理解如何。任何帮助都非常有价值!
谢谢,
Sub ScratchPad_Bookmarks()
Dim doc As Document
Dim rng As Range
Dim sHdName As String
Dim sBmName As String
Set doc = ActiveDocument
'Insert a heading at start of document
sHdName = "Entrance & Hallway"
doc.Range.InsertBefore sHdName & vbCr
doc.Paragraphs(1).Range.Style = doc.Styles("Heading 1")
'Find the above heading in the active document
Set rng = doc.Range
With rng.Find
.ClearFormatting
.Text = sHdName
.Style = "Heading 1"
If Not .Execute Then
'Heading not found, so quit
Exit Sub
End If
End With
'rng has collapsed to the found heading, so create a bookmark
'rng.Select 'debug
sBmName = Replace(rng.Text, " ", "_")
rng.Collapse wdCollapseStart
rng.Bookmarks.Add sBmName
'sBmName contains '&' so this throws a Runtime error:
'5828: Bad Bookmark Name (as expected)
End Sub
以上方法无效。然而,自己测试手动操作很容易。只需创建一个包含“&”字符的标题,将其样式设置为 标题 1。
在下一段中,使用 Word 自带的对话框插入超链接。 Select 在本文档中放置 和 select 您刚刚创建的标题。应该不是问题。
现在打开 Word 的书签对话框,启用 隐藏书签 视图,瞧:带有“&”字符的隐藏书签。 (Wd 2010)说什么?!
IMO Word 是 "cheating",要么打破了它自己的书签名称规则,要么拒绝提供规范允许的所有名称范围。
如果您回到 .docx 的早期 ECMA 标准,书签的名称被定义为 ST_String,这是 xsd:string 的限制,最大长度为 255 个字符。我认为自从标准的任何 ECMA 或 ISO 版本以来,这都没有改变。
但是,Microsoft 的实施说明 [MS-OE376].pdf 与规范的 ECMA 版本相关,而 [MS-OI29500].pdf 与 2012 ISO 版本相关,指定名称可以不超过40个字符,但不描述任何其他限制。
我(以前)的理解是书签名称限制在 40 个字符以内,必须由 "letters"、"digits" 和 "underscores" 组成,并且必须以下划线开头(例如隐藏的书签)或一封信。 (不确定,例如“_1”)。而且我相信 VBA 仍然强制执行这些规则,尽管我从未检查过它对 "letter" 或 "digit" 的理解是什么 - 是否允许非拉丁语 letters/digits?
但是,如果您将文档另存为 .xml 或在 .docx 中编辑 document.xml,您可以修改书签名称,使其包含,例如“&”。此外,Word 将重新保存此类字符。但是当你打开时它会将名字截断为 40 个字符,并且当你重新保存时它不会保留原来的名字。我认为使用首字母“_”来表示 "hidden" 也不符合标准。
因此,根据规范,我会说 Word "cheating" 不允许您使用所有可能的名称,而不是 "cheating" 允许超链接目标包含“& ".
您可以在 VBA 的 Windows 版 Word 中插入带“&”的书签,方法是使用 InsertXML 插入一块带有预配置书签的 XML name (请参阅下面的一些简单示例代码),但我怀疑您必须更加努力地工作才能移动书签。你可能不得不提取你想要 "cover" 的东西的现有 XML,然后用 bookmarkStart 和 bookmarkEnd 标签包围它,这对我来说听起来像是一个非常讨厌的练习。
作为最后的观察,AFAICR 您可以为旧表单字段指定的书签名称有 20 个字符的长度限制。
该代码:
Sub insertbm()
Dim x As String
x = ""
x = x & "<?xml version='1.0' encoding='utf-8' standalone='yes'?>"
x = x & "<pkg:package xmlns:pkg='http://schemas.microsoft.com/office/2006/xmlPackage'>"
x = x & " <pkg:part pkg:name='/_rels/.rels' pkg:contentType='application/vnd.openxmlformats-package.relationships+xml'>"
x = x & " <pkg:xmlData>"
x = x & " <Relationships xmlns='http://schemas.openxmlformats.org/package/2006/relationships'>"
x = x & " <Relationship Id='rId1' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument' Target='word/document.xml' />"
x = x & " </Relationships>"
x = x & " </pkg:xmlData>"
x = x & " </pkg:part>"
x = x & " <pkg:part pkg:name='/word/document.xml' pkg:contentType='application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml'>"
x = x & " <pkg:xmlData>"
x = x & " <w:document xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>"
x = x & " <w:body>"
x = x & " <w:p>"
x = x & " <w:bookmarkStart w:id='0' w:name='bookmark&name' />"
x = x & " <w:r>"
x = x & " <w:t>"
x = x & "bookmarkedtext</w:t>"
x = x & " </w:r>"
x = x & " <w:bookmarkEnd w:id='0' />"
x = x & " </w:p>"
x = x & " </w:body>"
x = x & " </w:document>"
x = x & " </pkg:xmlData>"
x = x & " </pkg:part>"
x = x & "</pkg:package>"
Selection.InsertXML x
End Sub
这里是 head-splitter: 我正在尝试以编程方式为文档中的现有标题创建隐藏书签,以便我可以在文档中的其他地方创建指向这些书签的超链接。 (我想使用超链接而不是 cross-references,因此我可以为链接指定我自己的 'Display Text',而使用 cross-refs 是不可能的)。
我希望我的书签以它们相关的标题命名,并带有自定义前缀。 示例:
- 样式:标题 1
- 标题文字:入口和走廊
- 书签名称:_Hd1_Entrance_&_Hallway
我正在指定一个自定义前缀,使每个书签的样式都独一无二,这样我就可以在文档中有 2 个匹配的标题,只要它们采用不同的标题样式即可。 (示例:_Hd1_Entrance_&_Hallway 和 _Hd3_Entrance_&_Hallway)
要注意的是:如果我的标题包含特殊字符,如“&”,我会收到 'Bad Bookmark Name' 错误,这是我理解的,并且在网络上有记录。我只能使用有限的字符集。
那么,如果我使用 Word 自己的对话框手动创建超链接,selecting 'Place In This Document'(例如 "Entrance & Hallway" 之类的标题),Word 管理起来没问题怎么办?创建 Hlink 后,我现在可以在 Word 的 'Bookmarks' 对话框中看到与此 Hlink 相关联的隐藏书签 - 并且它的名字很高兴地命名为“_Entrance _&_Hallway”。这让我很困惑!
有人解释一下吗?我真的很想能够利用同样的功能,但无法理解如何。任何帮助都非常有价值! 谢谢,
Sub ScratchPad_Bookmarks()
Dim doc As Document
Dim rng As Range
Dim sHdName As String
Dim sBmName As String
Set doc = ActiveDocument
'Insert a heading at start of document
sHdName = "Entrance & Hallway"
doc.Range.InsertBefore sHdName & vbCr
doc.Paragraphs(1).Range.Style = doc.Styles("Heading 1")
'Find the above heading in the active document
Set rng = doc.Range
With rng.Find
.ClearFormatting
.Text = sHdName
.Style = "Heading 1"
If Not .Execute Then
'Heading not found, so quit
Exit Sub
End If
End With
'rng has collapsed to the found heading, so create a bookmark
'rng.Select 'debug
sBmName = Replace(rng.Text, " ", "_")
rng.Collapse wdCollapseStart
rng.Bookmarks.Add sBmName
'sBmName contains '&' so this throws a Runtime error:
'5828: Bad Bookmark Name (as expected)
End Sub
以上方法无效。然而,自己测试手动操作很容易。只需创建一个包含“&”字符的标题,将其样式设置为 标题 1。 在下一段中,使用 Word 自带的对话框插入超链接。 Select 在本文档中放置 和 select 您刚刚创建的标题。应该不是问题。 现在打开 Word 的书签对话框,启用 隐藏书签 视图,瞧:带有“&”字符的隐藏书签。 (Wd 2010)说什么?!
IMO Word 是 "cheating",要么打破了它自己的书签名称规则,要么拒绝提供规范允许的所有名称范围。
如果您回到 .docx 的早期 ECMA 标准,书签的名称被定义为 ST_String,这是 xsd:string 的限制,最大长度为 255 个字符。我认为自从标准的任何 ECMA 或 ISO 版本以来,这都没有改变。
但是,Microsoft 的实施说明 [MS-OE376].pdf 与规范的 ECMA 版本相关,而 [MS-OI29500].pdf 与 2012 ISO 版本相关,指定名称可以不超过40个字符,但不描述任何其他限制。
我(以前)的理解是书签名称限制在 40 个字符以内,必须由 "letters"、"digits" 和 "underscores" 组成,并且必须以下划线开头(例如隐藏的书签)或一封信。 (不确定,例如“_1”)。而且我相信 VBA 仍然强制执行这些规则,尽管我从未检查过它对 "letter" 或 "digit" 的理解是什么 - 是否允许非拉丁语 letters/digits?
但是,如果您将文档另存为 .xml 或在 .docx 中编辑 document.xml,您可以修改书签名称,使其包含,例如“&”。此外,Word 将重新保存此类字符。但是当你打开时它会将名字截断为 40 个字符,并且当你重新保存时它不会保留原来的名字。我认为使用首字母“_”来表示 "hidden" 也不符合标准。
因此,根据规范,我会说 Word "cheating" 不允许您使用所有可能的名称,而不是 "cheating" 允许超链接目标包含“& ".
您可以在 VBA 的 Windows 版 Word 中插入带“&”的书签,方法是使用 InsertXML 插入一块带有预配置书签的 XML name (请参阅下面的一些简单示例代码),但我怀疑您必须更加努力地工作才能移动书签。你可能不得不提取你想要 "cover" 的东西的现有 XML,然后用 bookmarkStart 和 bookmarkEnd 标签包围它,这对我来说听起来像是一个非常讨厌的练习。
作为最后的观察,AFAICR 您可以为旧表单字段指定的书签名称有 20 个字符的长度限制。
该代码:
Sub insertbm()
Dim x As String
x = ""
x = x & "<?xml version='1.0' encoding='utf-8' standalone='yes'?>"
x = x & "<pkg:package xmlns:pkg='http://schemas.microsoft.com/office/2006/xmlPackage'>"
x = x & " <pkg:part pkg:name='/_rels/.rels' pkg:contentType='application/vnd.openxmlformats-package.relationships+xml'>"
x = x & " <pkg:xmlData>"
x = x & " <Relationships xmlns='http://schemas.openxmlformats.org/package/2006/relationships'>"
x = x & " <Relationship Id='rId1' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument' Target='word/document.xml' />"
x = x & " </Relationships>"
x = x & " </pkg:xmlData>"
x = x & " </pkg:part>"
x = x & " <pkg:part pkg:name='/word/document.xml' pkg:contentType='application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml'>"
x = x & " <pkg:xmlData>"
x = x & " <w:document xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>"
x = x & " <w:body>"
x = x & " <w:p>"
x = x & " <w:bookmarkStart w:id='0' w:name='bookmark&name' />"
x = x & " <w:r>"
x = x & " <w:t>"
x = x & "bookmarkedtext</w:t>"
x = x & " </w:r>"
x = x & " <w:bookmarkEnd w:id='0' />"
x = x & " </w:p>"
x = x & " </w:body>"
x = x & " </w:document>"
x = x & " </pkg:xmlData>"
x = x & " </pkg:part>"
x = x & "</pkg:package>"
Selection.InsertXML x
End Sub