您可以使用include指令将其他文件的内容包含到当前的AsciiDoc文档中。包含的内容可以是AsciiDoc格式,也可以是任何其他文本格式。包含内容的位置决定了它将如何被处理。

include指令是什么?

一个[.term]*include 指令*用于从另一个文件或URL导入内容到当前文档中。当处理当前文档时,include 指令语法会被包含文件的内容所替换。可以把include指令想象成一个文件扩展器。include指令是一个预处理指令,这意味着它不会意识到周围的上下文。

include指令什么时候有用?

当你想要:Include指令是有用的。

  • 将一个大文档分割成更小的文件以便更好地组织,并使重构更加简单。脚注:[除非您的目的是将包含文件中的内容紧接着放一起使其成为连续的,否则总是通过一个空行来分隔连续的include指令。]

  • 从外部文件中插入源代码,该代码在此处得到维护。

  • 使用其他程序输出的数据,例如CSV数据,来填充表格。

  • 通过结合include指令和条件预处理指令来创建文档变体。

  • 在同一文档中多次重复使用内容片段和样板内容,如术语定义、免责声明等。

  • 定义一组通用属性,用于多个文件中(通常包含在文档头部)。

包含指令语法

include指令必须单独放在一行上,使用以下语法:

include::target[leveloffset=offset,lines=ranges,tag(s)=name(s),indent=depth,encoding=encoding,opts=optional]

目标是必需的。目标可以是绝对路径、相对于当前文档的路径,或者一个URL。由于include指令是基于行的表达式,因此目标可以包含空格字符。然而,目标不得以空格字符开头(因为那样会把它变成描述列表项)。如果安全模式为不安全,则只有在目标位于最外层文档目录之外的绝对或相对路径才会被接受。只有当处理器的安全设置允许时(例如,allow-uri-read),URL目标才会被解析。参见include-uri.html

leveloffset、lines、tag(s)、indent、encoding 和 opts 属性是可选的,因此将最简单的情况简化为以下内容:

include::partial.adoc[]

如果包含的文件不是用UTF-8编码的,那么指定编码是必要的。这个属性的值必须是Ruby能够识别的编码(例如,utf-8、iso-8859-1、windows-1252等),并且大小写不敏感。如果包含的文件已经是用UTF-8编码的(或者包含一个字节顺序标记),那么这个属性就没有必要了。

当连续使用include指令时,除非你的目的是将include文件的内容拼接起来使其连续,否则你应该总是用一个空行将它们分开。

例如,如果您使用include指令来包含各个章节,那么这些include指令应该通过一个空行来相互分隔。这种策略避免了依赖于从include文件导入的空行来保持章节分隔。章节的分隔应该在父文档中进行编码。

include::chapter01.adoc[]

include::chapter02.adoc[]

include::chapter03.adoc[]

另一方面,如果您使用 include 指令来布置连续的行,例如常见的文档属性条目,则应将 include 指令放在相邻行上,以避免插入空行。

= 文档标题
Author Name \include::attributes-settings.adoc[] \include::attributes-urls.adoc[] :url-example: https://example.org

文档正文。

无论哪种情况,都不要依赖包含文件边界处的空行。并注意包含文件中空行的使用位置。

包括处理

尽管include指令看起来像是一个块宏,但它*不是宏,因此不会像宏那样处理*。它是一个预处理指令;理解这种区别非常重要。

Unresolved directive in include.adoc - include::partial$preprocessor.adoc[] include指令是一个预处理指令,它总是添加行。

理解include指令的最佳方式是想象它被从include文件中的行所取代(即,被导入的行)。只有在include指令的目标行被添加到当前文档之后,解析器才会读取并解释那些行。

Important
当Asciidoctor在安全模式下运行时,include指令会被禁用。在安全模式中,include指令在输出文档中会被转换为链接。请参阅asciidoctor::safe-modes.html以了解更多信息。

逃避包含指令

如果你不想让include指令被处理,你必须使用反斜杠来转义它。

include::just-an-example.ext[]

即使出现在逐字块中,转义指令也是必需的,因为它不知道周围的文档结构。

文件包含解析

include指令中使用的路径可以是相对的或绝对的。

如果路径是相对的,处理器将根据以下规则解析路径:

  • 如果在主文档(顶级文档)中使用了include指令,那么相对路径会根据基础目录解析。(基础目录默认为主文档的目录,并且可以通过命令行接口或应用程序接口进行更改)。

  • 如果在一个已经被包含的文件中使用include指令,那么路径会相对于包含(即当前)文件来解析。

这些默认设置使得推理出包含文件路径如何解析变得容易。

如果处理器找不到文件(也许是因为您输错了路径),您仍然可以转换文档。但是,在转换过程中,您会收到以下警告消息:

asciidoctor: WARNING: my-document.adoc: line 3: include file not found: /…​/content.adoc

以下信息也将被插入到输出中:

Unresolved directive in my-document.adoc - include::content.adoc[]

为了解决这个问题,请编辑文件路径并再次运行转换器。如果你不希望AsciiDoc处理器发出警告,而是希望省略掉找不到的包含文件,可以在include指令中添加`opts=optional`属性。

如果你在不同层次的嵌套文件夹中存储AsciiDoc文件,相对文件路径可能很快就会变得尴尬和不灵活。这里的一个常见模式是在头部定义路径属性,然后用这些属性之一的引用作为前缀,添加到所有包含路径中:

:includedir: _includes
:sourcedir: ../src/main/java

include::{includedir}/fragment1.adoc[]

[source,java]
----
include::{sourcedir}/org/asciidoctor/Asciidoctor.java[]
----

请记住,无论Asciidoctor如何解析文件的路径,访问该文件的权限都受到Asciidoctor运行的安全模式设置的限制。如果路径违反了安全限制,它可能会被截断。

AsciiDoc 与非 AsciiDoc 文件

include指令执行一个简单的文件合并操作,因此它适用于任何文本文件。 所有包含内容的内容都会经过某种形式的标准化。

每个包含文件的内容都被编码成UTF-8。如果在include指令上指定了编码属性,则内容将从该编码重新编码成UTF-8。如果没有指定编码属性,处理器将检查字节顺序标记(BOM)的存在,并相应地将内容从该编码重新编码为UTF-8。如果这两个条件都不满足,编码将被强制设为UTF-8。

如果文件被识别为AsciiDoc文件(即,它具有以下扩展名之一:.asciidoc.adoc.ad.asc`或.txt`),那么将执行额外的规范化和处理。首先,将从每行移除所有尾随空格和换行符,并替换为Unix换行符。这种规范化对于AsciiDoc处理器的工作方式非常重要。接下来,AsciiDoc处理器运行预处理器对行进行处理,查找并解释以下指令:

  • 包含

  • 预处理器条件指令(例如,ifdef

在包含的内容上运行预处理器允许嵌套包含,因此在使用单一主文档和一些命令行属性构造根本不同的文档时提供了很大的灵活性。

包括非AsciiDoc文件通常是为了合并其他程序的输出或填充表格数据:

.2016 Sales Results
,===
include::sales/2016/results.csv[]
,===

在这种情况下,include 指令不会处理任何 AsciiDoc 指令。内容将在规范化后按原样插入。