HTML 剪贴板格式

通过剪贴板传输 HTML 文本的要求会因场景而异。 本文涉及剪切和粘贴 HTML 文档的片段。 可能会有通过剪贴板传输整个 HTML 文档的要求;但是,本文重点介绍传输所选 HTML 文本的片段的要求。 因此,需要将整个 HTML 文档复制到剪贴板的方法被视为工作量庞大。

采用 CF_HTML 剪贴板格式,可将原始 HTML 文本及其上下文(即外部 HTML)片段作为 ASCII 存储在剪贴板上。 这允许应用程序检查 HTML 片段的上下文,该片段由前面所有的周围标记组成,以便可以使用其属性来记录 HTML 片段的周围标记。 尽管由应用程序决定如何解释此类片段,但此处提供了一些基于 IE4/MSHTML 实现的基本准则。

剪贴板的官方名称(RegisterClipboardFormat 使用的字符串)为“HTML Format”。

说明

CF_HTML 是文本剪贴板格式,但始终使用 UTF-8 编码。 请注意,此处使用 UTF-8 是 Windows API 使用 UTF-16 来表示文本字符串(尤其是人类可读(即可本地化)字符串)的一般规则的例外。

可以使用 pseudo-Backus–Naur 形式描述 CF_HTML 剪贴板的常规布局或语法,如下所示:

注意

此语法不规范**

<cf-html>                ::= <description-header> <context>
<context>                ::= [<preceding-context>] <fragment> [<trailing-context>]

<description-header>     ::= "Version:" <version> <br> ( <header-offset-keyword> ":" <header-offset-value> <br> )*
<header-offset-keyword>  ::= "StartHTML" | "EndHTML" | "StartFragment" | "EndFragment" | "StartSelection" | "EndSelection"
<header-offset-value>    ::= { Base 10 (decimal) integer string with optional _multiple_ leading zero digits (see "Offset syntax" below) }
<version>                ::= "0.9" | "1.0"
<fragment>               ::= <fragment-start-comment> <fragment-text> <fragment-end-comment>
<fragment-start-comment> ::= "<!--StartFragment -->"
<fragment-end-comment>   ::= "<!--EndFragment -->"
<preceding-context>      ::= { Arbitrary HTML }
<trailing-context>       ::= { Arbitrary HTML }
<fragment-text>          ::= { Arbitrary HTML }
<br>                     ::= "\r" | "\n" | "\r\n"

描述标头和偏移量

描述标头包括剪贴板版本号和偏移量,指示上下文和片段开始和结束的位置。 描述是 ASCII 文本关键字的列表,后跟一个字符串,并用冒号 (:) 分隔。

  • Version:剪贴板的 vv 版本号。 起始版本为 Version:0.9。 从 Windows 10 20H2 开始,这现在是 Version:1.0
  • StartHTML:从剪贴板开头到上下文(没有上下文时则为 -1)开头的偏移量(以字节为单位)。
  • EndHTML:从剪贴板开头到上下文(没有上下文时则为 -1)结尾的偏移量(以字节为单位)。
  • StartFragment:从剪贴板开头到片段开头的偏移量(以字节为单位)。
  • EndFragment:从剪贴板开头到片段结尾的偏移量(以字节为单位)。
  • StartSelection:可选。 从剪贴板开头到所选内容开头的偏移量(以字节为单位)。
  • EndSelection:可选。 从剪贴板开头到所选内容结尾的偏移量(以字节为单位)。

StartSelectionEndSelection 关键字为可选;如果不希望应用程序生成此信息,则必须同时省略两者。

例如,CF_HTML 剪贴板格式的未来修订可能会扩展标头,因为 HTML 从 StartHTML 偏移量开始,然后可以添加多个 StartFragmentEndFragment 对,以支持片段的不连续选择。

偏移量语法

为了方便程序生成字节偏移量,偏移量值可以选择性地用任意零位数 '0' 进行左填充。 原因是在 HTML 中探查偏移量的程序可能会将十 (10) 个零写入每个关键子的输出缓冲区(例如 StartHTML: 0000000000)。 稍后,当确切 StartHTML 偏移量已知(如 71)时,程序可以在缓冲区中使用“71”覆盖最右边的零(例如,产生 StartHTML: 0000000071)。

剪贴板支持的唯一字符集是 Unicode (UTF-8)。 由于 UTF-8 和 ASCII 的第一个字符匹配,因此描述始终为 ASCII,但上下文的字节(以 StartHTML 开头)可能在使用以 UTF-8 编码的任何其他字符。

剪贴板格式标头(上面的 <br>)中的行结尾可以采用 CRLF (Windows)、LF (Unix) 或单独的 CR(过时)表示。

片段、所选内容及其上下文

元素 描述标头 需要对开始和结束字符位置使用有效的 HTML
上下文 StartHTMLEndHTML
Fragment StartFragmentEndFragment
选择 StartSelectionEndSelection

上下文

上下文是一个有效的完整 HTML 文档,但这并不意味着,将逐字执行包含用户所选内容的整个原始源 HTML 文档;相反,它可以是最小但格式正确的 HTML 文档。

上下文包含片段和前面所有的周围标记(开始和结束标记;这些前面的周围标记表示片段在 HTML 节点之前的所有父节点)。 上面的示例文章包含一个完整的 HTML <head> 元素,允许使用 <base href=""><title> 元素。 例如,可以插入此元素,以获取此附加信息。 将 HTML 片段复制到剪贴板的应用程序可以选择创建一个 <base href=""> 元素,以便将其包含在上下文中(如果此类元素尚不存在)。 这样,就可以解析 HTML 片段中的非绝对 URI。

上下文为可选,因为片段中包含足够的信息,以便进行 HTML 片段的基本粘贴。 如果未存储上下文,则仅存储片段和 StartHTML=EndHTML=-1

Fragment

片段(上面的 <fragment-text>)包含有效的 HTML 片段。

有效 HTML 片段由单个外部 HTML 元素组成。 此元素可能包含子代 HTML 元素,前提是它们嵌套正确。 例如,片段可以是包含 3 个 <p> 元素的单个 <div> 元素。 由包含三个 <p> 元素的 <span> 元素组成的片段无效,因为 <span> 元素(一个元素)不能包含块级元素作为子元素。

因此,片段实际上表示屏幕上更大的区域,用户在其中进行了文本选择(例如复制)。 所选内容包含所选文本以及任何元素的开始标记和属性,这些元素在所选文本中具有结束标记,以及包含的任何开始标记的片段末尾的结束标记。 这是基本粘贴 HTML 片段所需的所有信息。

片段的前面和后面应是 HTML 注释 <!--StartFragment--><!--EndFragment-->,以指示片段开始和结束的位置;必须逐字使用这些 HTML 注释,并且每个注释本身中没有空格字符。 因此,片段的开始和结尾由这些注释以及StartFragmentEndFragment 标头的存在指示。 工具应生成此信息。 这种冗余是有意的行为,引入后能够找到片段的开头(从字节计数),并直接标记片段在 HTML 树中的位置。

选择

所选内容为可选,因为片段中包含足够的信息用于基本粘贴。 如果未存储所选内容,则不会将 StartSelectionEndSelection 都存储在标头中。

如果存在,则所选内容是用户选择的确切文本范围(在片段中);这将通过指示确切的选定文本来向片段添加更多信息,而无需格式正确、平衡的开始和结束标记和结束标记。

请记住,所选内容可以表示文本的运行,可以在任何给定元素中开始,并在任何后续元素或上级元素中结束。 因此,无法使用 HTML 来表示文本选择。

方案

以下方案描述了 IE4/MSHTML HTML 编辑器如何处理 HTML 剪切和粘贴;其他应用程序可能会也可能不会遵循这些方案。 此处所述的剪贴板格式旨在实现应用程序选择如何正常运行方面的灵活性。 (这些方案仅显示良好的 HTML,即没有重叠的标记。)

方案 1 - HTML 的简单片段

假定以下 HTML 文本:

<body>This is normal. <b>This is bold.</b> <i><b>This is bold italic.</b> This is italic.</i></body>

如下所示:

这是一般警报。 This is bold.This is bold italic.This is italic.

当用户将上述 HTML 文本加载到基于 MSHTML 的应用程序(MSHTML, Trident,以前是 Internet Explorer 的引擎)时,MSHTML 将处理复制 HTML 的子字符串,具体如下:

  1. 用户从上面的示例中选择不带任何前导或尾随空格的文本,例如“bold This is bold italic This”。
  2. 若要将文本复制到剪贴板,用户应单击“复制”命令按钮。

MSHTML 会将此 HTML 文本放入 Windows 剪贴板中,具体如下:

Version:1.0
StartHTML:0121
EndHTML:0272
StartFragment:0006
EndFragment:0106
StartSelection:0180
EndSelection:0225
<html><!--StartFragment--><body>This is normal. <b>This is bold.</b> <i><b>This is bold italic.</b> This is italic.</i></body><!--EndFragment--></html>

方案 2 - HTML 中的表片段

假定以下 HTML 文本:

<BODY><TABLE BORDER><TR><TH ROWSPAN=2>Head1</TH><TD>Item 1</TD><TD>Item 2</TD><TD>Item 3</TD><TD>Item 4</TD></TR><TR><TD>Item 5</TD><TD>Item 6</TD><TD>Item 7</TD><TD>Item 8</TD></TR><TR><TH>Head2</TH><TD>Item 9</TD><TD>Item 10</TD><TD>Item 11</TD><TD>Item 12</TD></TR></TABLE></BODY>

如下所示:

头 1 项 1 项 2 项 3 项 4
项 5 项 6 项 7 项 8
头 2 项 9 项目 10 项 11 项 12

MSHTML 如何处理从表复制 HTML 子字符串

当用户使用鼠标选择涵盖表单元格项 6项 7项 10项 11 的文本时。 那么,会将此所选内容复制到剪贴板。

以下是剪贴板上的内容(请注意,这是 IE4/MSHTML 的解释)。 为清楚起见,添加了换行符。

<!DOCTYPE
<HTML>
<BODY>
<TABLE BORDER>
<!--StartFragment-->
  **<TR>
    <TD>Item 6</TD>
    <TD>Item 7</TD>
  </TR>
  <TR>
    <TD>Item 10</TD>
    <TD>Item 11</TD>
  </TR>**
<!--EndFragment-->
</TABLE>
</BODY>
</HTML>

所选内容以粗体显示,按 StartSelectionEndSelection 分隔。

方案 3 - 将有序列表 <ol> 的片段粘贴到纯文本中

假定以下 HTML 文本:

<BODY><OL TYPE="a"><LI>Item 1<LI>Item 2<LI>Item 3<LI>Item 4<LI>Item 5<LI>Item 6</OL></BODY>

如下所示:

  1. 项 1
  2. 项 2
  3. 项 3
  4. 项 4
  5. 项 5
  6. 项 6

MSHTML 如何处理复制 HTML 编号列表项的子字符串

  1. 用户选择从项 3 开始经过项 4 直到项 5 末尾的文本。 用户调用“复制”命令。
  2. 以下 HTML 位于剪贴板(为清楚起见,添加了换行符)- <!--Star/EndFragment --> 注释的精确位置取决于用户如何处理其浏览器的文本选择逻辑:
<html>
<body>
<ol>
<!-- StartFragment-->
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
<!-- EndFragment-->
</ol>
</body>
</html>

如果现在将此片段粘贴到空文档中,将创建以下 HTML:

<body>
<ol>
<li>Item 3</li>
<li>Item 4</li>
<li>Item 5</li>
</ol>
</body>

如下所示:

  1. 项 3
  2. 项 4
  3. 项 5

方案 5 - 粘贴部分选定的区域

假定以下 HTML 文本:

<p>IE4/MSHTML is a WYSIWYG Editor that supports:</p>
<ul><li>Cut<li>Copy<li>Paste</ul>
<p>This is a Great Tool!</p>

如下所示:

IE4/MSHTML 是支持以下项的 WYSIWYG 编辑器:

  • 剪切
  • 复制
  • 粘贴

这是一个很棒的工具!

MSHTML 如何处理复制 HTML 列表项的子字符串

用户使用鼠标拖动选择的文本,例如“WYSIWYG Editor that supports: Cut Cop”。 就像它是纯文本一样,该所选内容将类似于此断开的 HTML 片段:

WYSIWYG Editor, which supports:</p>
<ul>
  <li>Cut</li>
  <li>Cop

当用户按下“复制”命令按钮时,其剪贴板将如下所示(为了清楚起见,添加了换行符;粗体文本表示用户实际选择的内容):

<html>
<body>
<!-- StartFragment-->
<p>WYSIWYG Editor, which supports</p>
<ul>
	<li>Cut</li>
	<li>Cop</li>
</ul>
<!-- EndFragment-->
</body>
</html>

观察以下情况:

  • 删除了“WYSIWYG”之前的文本。
  • 列表项 (<li>Paste</li>) 已被删除,因为该列表项的内容都不在用户的所选内容中。
  • “Copy”中的“y”已被删除。

另请参阅

剪贴板