© 本文档使用了https://arc42.de[arc42架构模板]的材料,该模板可以在https://github.com/arc42[https://github.com/arc42]上免费获取。
本材料是开源的,采用知识共享署名-相同方式共享 4.0 许可协议提供。它*不附带任何保证*。请自行承担风险。 arc42及其结构由Peter Hruschka博士和Gernot Starke博士提供。 AsciiDoc版本由Markus Schärtel和Jürgen Krey发起,由Ralf Müller和Gernot Starke完成和维护。
Note
|
在下文中,“HTML审查器”将缩写为kbd:[HtmlSC] |
文档目标
此文档是https://github.com/arc42[arc42]文档的一个示例。
您可以为自己的项目复制此文档或其部分内容。 在这种情况下,您必须包含https://github.com/arc42[arc42]或https://github.com/aim42[aim42]的链接或引用(我们认为这是*合理使用*)。
对于实际项目,代码与文档之间的关系是过大的。
免责声明
我们绝对*不提供任何保证*,无论是对于本文档的准确性还是所描述软件的任何属性或功能。
请勿在关键情况或项目中使用此软件。
```asciidoc :numbered: :linkattrs: :experimental:
1. 介绍与目标
kbd:[HtmlSC] 应支持作者创建数字格式,包括超链接和图片等资源的集成。
1.1. 需求概述
kbd:[HtmlSC] 的总体目标是创建整洁清晰的报告,展示 HTML 文件中的错误 - 如附图所示。
1.1.1. 基本用法
-
用户配置一个或多个 HTML 文件的位置(目录和文件名),
-
以及相应的图像目录。
-
kbd:[HtmlSC] 对 HTML 进行各种检查,并
-
将其结果报告给控制台或作为 HTML 报告。
kbd:[HtmlSC] 可以从命令行或作为 Gradle 插件运行。
除了纯语法错误外,HTML 中可能出现许多问题,特别是与超链接、锚点和 ID 相关的问题 - 因为这些通常是手动维护的。
问题的主要来源是不良链接(技术术语:URI)。有关更多信息,请参阅 URI 背景信息。
检查和报告这些错误和缺陷是 kbd:[HtmlSC] 的中心 业务需求。
HTML 精神检查的重要术语(领域术语)记录在一个(小)领域模型中。
1.1.3. 通用功能
1.1.4. 精神检查的类型
1.1.5. 报告和输出要求
1.2. 质量目标
1.3. 利益相关者
1.4. URI 背景信息
统一资源标识符的通用结构包括以下部分: [type][://][subdomain][domain][port][path][file][query][hash]
一个示例,可视化:

java.net.URL 类包含对 URL 和 URI 的通用解析器。 请参阅以下片段,摘自单元测试类 URLUtilTest.groovy:
通用 URI 结构
URI 用于 引用 其他资源。 对于 kbd:[HtmlSC],区分内部(== 本地)和外部引用是有用的:
-
内部引用,又称交叉引用
-
外部引用
1.4.1. 文档内 URI
文件… ref 可以是内部链接,也可以是没有协议的 URI…
1.4.2. 关于 URI 和 HTML 语法的参考资料
以上是您提供的 AsciiDoc 文档的翻译。希望对您有所帮助!
```asciidoc :jbake-menu: arc42 :jbake-order: 20 :jbake-rightColumnHtml: <a href="../../pdf/arc42/hsc_arc42.pdf"><i class="fa fa-file fa-fw"></i> 下载PDF</a> :numbered: :linkattrs: :experimental:
2. 约束
kbd:[HtmlSC] 应当:
-
是跨平台的,能在主要操作系统(Windows™、Linux 和 Mac-OS™)上运行
-
与 Gradle 构建工具集成
-
可从命令行运行
-
是在自由开源许可下开发的 ```
这是 Constraints 部分的中文翻译,保留了 AsciiDoc 的格式。希望这对您有所帮助!
3. 上下文
3.1. 业务上下文

邻居 | 描述 |
---|---|
用户 |
使用生成 HTML 的工具链为软件编写文档。希望确保这些 HTML 中的链接是有效的。 |
构建系统 |
|
本地 HTML 文件 |
kbd:[HtmlSC] 读取并解析本地 HTML 文件,并在其中执行健全性检查。 |
本地图像文件 |
kbd:[HtmlSC] 检查链接的图像是否存在作为(本地)文件。 |
外部网络资源 |
kbd:[HtmlSC] 可以配置为选择性地检查外部网络资源的存在。由于 Web 系统的特性,这种检查可能需要大量时间,并且可能由于网络和延迟问题导致无效结果。 |
3.2. 部署上下文

节点 / 构件 | 描述 |
---|---|
kbd:[HtmlSC] 开发所在地 |
|
kbd:[HtmlSC] 的已编译和打包版本,包括所需的依赖关系。 |
|
全球公共 云 构件仓库,类似于 mavenCentral。 kbd:[HtmlSC] 的二进制文件被上传到该服务器。 |
|
用于任意文档编写,以 HTML 作为输出格式。 |
|
Gradle 构建脚本配置(包括其他内容)kbd:[HtmlSC] 插件执行 HTML 检查。 |
详细信息请参阅 部署视图。
4. 解决策略
-
使用 Groovy 和 Java 在最小化外部依赖的情况下实现 kbd:[HtmlSC]。将此实现封装为 Gradle 插件,以便在自动化构建中使用。详情请参阅 Gradle 插件概念。
-
5. 构建块视图
5.1. 白盒 HtmlSanityChecker
@startuml skinparam componentStyle uml2 skinparam component { backgroundColor<<planned>> Khaki backgroundColor White } skinparam handwritten true left footer <font color=blue>HtmlSanityCheck</font> https://github.com/aim42/htmlSanityCheck endfooter interface "local file system" as files interface "external Websites" as web rectangle "HtmlSanityCheck (Level 1)" as HSC { [HSC Core] as core #YellowGreen [HSC Gradle Plugin] -down-> core [HSC Graphical UI] <<planned>> as ui [HSC Maven Plugin] <<planned>> as mavenplugin [FileUtil] as futil [NetUtil] as netutil mavenplugin .down-> core ui .down-> core core -> futil core -> netutil futil -down-> files netutil -down-> web } :docu-author: -down-> ui [Build System] as bs bs -down-> [HSC Gradle Plugin] bs .down.> mavenplugin core -down-> files core -down-> web @enduml
- 原理
-
我们使用了 功能分解 来分离责任:
-
CheckerCore 应封装检查逻辑和 HTML 解析/处理。
-
所有类型的输出(控制台、HTML 文件、图形)应在单独的组件(Reporter)中处理。
-
Gradle 特定功能的实现应封装在一起。
-
- 包含的黑盒
hsc 核心:HTML 解析和健全性检查、配置、报告。 |
|
HSC Gradle 插件 |
将 Gradle 构建工具与 kbd:[HtmlSC] 集成,使任意 Gradle 构建可以使用 kbd:[HtmlSC] 功能。 |
HSC Maven 插件 |
(计划中,尚未实现) |
HSC 图形界面 |
(计划中,尚未实现) |
- 接口
接口 | 描述 |
---|---|
通过 shell 使用 |
arc42 用户 通过命令行 shell 调用 kbd:[HtmlSC] |
构建系统 |
当前限定为 Gradle:构建系统使用 kbd:[HtmlSC],并在构建脚本中进行配置。 |
本地文件系统 |
kbd:[HtmlSC] 需要访问多个本地文件,特别是要检查的 HTML 页面和对应的图像目录。 |
外部网站 |
为了检查外部链接,kbd:[HtmlSC] 需要通过 http HEAD 或 GET 请求访问外部站点。 |
5.1.1. HSC 核心(黑盒)
- 意图/责任
-
HSC 核心包含执行各种健全性检查的核心功能。它将 HTML 文件解析为类似 DOM 的内存表示形式,然后用于执行实际的检查。
- 接口
接口(从 - 到) | 描述 |
---|---|
命令行接口 → 检查器 |
使用 #AllChecksRunner 类。 |
Gradle 插件 → 检查器 |
通过标准 Gradle 插件公开 kbd:[HtmlSC],如 Gradle 用户指南中所述。 |
- 文件
-
-
org.aim42.htmlsanitycheck.AllChecksRunner
-
org.aim42.htmlsanitycheck.HtmlSanityCheckGradlePlugin
-
5.2. 构建块 - Level 2
5.2.1. HSC 核心(白盒)

- 原理
-
该结构遵循严格的功能分解:
-
解析和处理 HTML 输入
-
检查
-
收集检查结果
-
- 包含的黑盒
检查器 |
抽象类,以模板模式形式使用。应为所有检查算法创建子类。 |
AllChecksRunner |
不同 Checker 实例的外观。提供(基于参数的)命令行接口。 |
收集所有检查结果。其接口 Results 包含在 白盒描述 中 |
Reporter |
将检查结果报告给控制台或 HTML 文件。 |
HtmlParser |
封装 HTML 解析,提供在(解析的)HTML 中搜索的方法。 |
Suggester |
在检查出问题时,通过比较有问题的元素与 HTML 文件中的元素来提供替代建议(当前尚未实现)。 |
5.2.2. Checker 和 xyzChecker 子类
抽象 Checker 提供了不同检查算法的统一接口(public void check())。它基于 可扩展检查算法的概念。
5.3. 构建块 - Level 3
5.3.1. ResultsCollector(白盒)

- 原理
-
此结构遵循检查层次结构 - 即管理以下检查结果:
-
多个页面/文档,每个页面包含:
-
单个页面,每个页面包含许多
-
页面内的单个检查
-
- 包含的黑盒
每次运行的结果 |
可能包含多个 HTML 页面/文档的结果。 |
单个页面的结果 |
单个页面的结果 |
单个检查的结果 |
单个类型检查的结果(例如,缺少图像检查) |
发现 |
单个发现(例如,“图像 logo.png 缺失”)。可以包含建议和(计划中的未来版本)负责的 HTML 元素。 |
接口 Results
Result 接口被所有客户端(特别是 Reporter 子类、图形和命令行客户端)用于访问检查结果。它由三个不同的 API 组成,用于整体 RunResults、单个页面结果 PageResults 和单个检查结果 CheckResults。请参阅下面来自 Groovy 源代码的接口定义:
```groovy .Interface RunResults
6. 运行时视图
注意:由于实现非常简单,对于该系统来说并不合适。
7. 部署视图

节点 / 构件 | 描述 |
---|---|
hsc 插件二进制 |
kbd:[HtmlSC] 的编译版本,包含所需的依赖项。 |
hsc-development |
kbd:[HtmlSC] 的开发所在地 |
构件仓库 (Bintray) |
用于存储二进制构件的全球公共“云”仓库,类似于 mavenCentral。 kbd:[HtmlSC] 的二进制文件会上传到此服务器。 |
hsc 用户计算机 |
任意文档的编写地,输出格式为 HTML。 |
build.gradle |
Gradle 构建脚本,配置 kbd:[HtmlSC] 插件来检查 一些文档。 |
图[img-deployment]中显示的三个节点(计算机)通过互联网连接。
检查程序将:
-
被捆绑为一个单独的 JAR 文件,
-
被上传到 Bintray 仓库,
-
可在 Gradle 构建文件中引用,
-
提供一个带参数和选项的 main 方法,以便可以从命令行调用所有检查。
8. 技术和横切概念
8.1. HTML 检查领域模型

术语 | 描述 |
---|---|
Anchor |
用于创建链接的 HTML 元素。包含形式为 <a href="link-target"> 的链接目标。 |
Cross Reference |
文档中一部分到同一文档内另一部分的链接。是 →Internal Link 的一种特殊形式,具有同一文档中的 →Link Target。 |
External Link |
到另一个页面或另一个域的资源的链接。 |
Finding |
由 →Checker 在 →Html Page 中发现的问题描述。 |
Html Element |
HTML 页面(文档)由 HTML 元素组成,例如 <a href="link target">、<img src="image.png"> 等。参见 W3-Consortium |
Html Page |
单个 HTML 块,通常被视为单个文件。应符合标准的 HTML 语法。最低要求:我们的 HTML 解析器可以成功解析此页面。包含 →Html Elements。也称为 Html Document。 |
id |
文档中特定部分的标识符,例如 <h2 id="#someHeader">。通常用于描述 →Link Targets。 |
Internal Link |
指向同一页的另一部分或同一域的另一页的链接。也称为 Local Link。 |
Link |
→Html Page 中任何引用,可以显示或激活此文档的另一部分(→Internal Link)或另一个文档、图像或资源(可以是 →Internal(本地)或 →External Link)。每个链接从 Link Source 导向 Link Target |
Link Target |
任何 →Link 的目标,例如标题或 →Html Document 的任何部分、任何内部或外部资源(通过 URI 标识)。由 →id 表示。 |
Local Resource |
本地文件,可以是其他 Html 文件或其他类型(例如 pdf、docx) |
Run Result |
对多个页面(至少一页)进行检查的整体结果。 |
Single Page Result |
单个 →Html Page 的所有检查的集合。 |
URI |
统一资源标识符。在 RFC-2396 中定义。关于链接语法和语义的最终权威来源。 |
8.2. Gradle 插件概念和开发
你绝对应该阅读原始的 Gradle 用户指南,了解自定义插件开发。
为了实现 所需的 Gradle 集成,我们实现了一个简洁的包装,就像 Gradle 用户指南中所描述的那样。
class HtmlSanityCheckPlugin implements Plugin<Project> { void apply(Project project) { project.task('htmlSanityCheck', type: HtmlSanityCheckTask, group: 'Check') } }
8.2.1. 目录结构和所需文件
|-htmlSanityCheck | |-src | | |-main | | | |-org | | | | |-aim42 | | | | | |-htmlsanitycheck | | | | | | | ... | | | | | | |-HtmlSanityCheckPlugin.groovy // <1> | | | | | | |-HtmlSanityCheckTask.groovy | | | |-resources | | | | |-META-INF // <2> | | | | | |-gradle-plugins | | | | | | |-htmlSanityCheck.properties // <3> | | |-test | | | |-org | | | | |-aim42 | | | | | |-htmlsanitycheck | | | | | | | ... | | | | | | |-HtmlSanityCheckPluginTest |
-
实际插件代码:HtmlSanityCheckPlugin.groovy 和 HtmlSanityCheckTask.groovy groovy 文件
-
Gradle 期望在 META-INF 中找到插件属性
-
包含实际实现类名称的属性文件:implementation-class=org.aim42.htmlsanitycheck.HtmlSanityCheckPlugin
8.2.2. 从构建文件传递参数到插件
待完成
8.2.3. 构建插件
插件代码本身使用 gradle 构建。
8.2.4. 上传到公共存档
8.2.5. 有关创建 Gradle 插件的更多信息
尽管在 Gradle 用户指南中描述了编写插件,但在 Code4Reference 教程中提供了一个清晰解释的示例。
8.3. 灵活的检查算法
kbd:[HtmlSC] 使用模板方法模式来实现灵活的检查算法:
我们通过在一个操作中定义检查算法的骨架,将具体的检查算法步骤推迟到子类中来实现这一点。
不变的步骤是在抽象基类中实现的,而变体检查算法必须由子类提供。

组件 | 描述 |
---|---|
Checker |
_抽象_基类,包含模板方法 check() 和公共方法 performCheck() |
检查引用的本地图像文件是否存在 |
|
检查是否存在没有 alt 属性的图像标签 |
|
检查页面内引用的交叉引用(链接)是否存在 |
|
检查任何 ID 是否有多个定义 |
|
检查引用的其他资源是否存在 |
|
检查外部链接是否有效 |
|
检查链接是否违反了 HTML 链接语法 |
8.3.1. MissingImageFilesChecker
满足需求 R-1.
检查在 <img src="someFile.jpg"> 中引用的图像文件是否真的存在于本地文件系统中。
检查图像的一个小问题是它们的路径:考虑以下 HTML 片段(来自文件 testme.html):
<img src="./images/one-image.jpg">
这个图像文件("one-image.jpg")必须相对于包含相应 HTML 文件的目录。
因此,"one-image.jpg" 的预期绝对路径必须从测试的 HTML 文件的绝对路径中确定。
我们使用通常的 Java API 检查文件是否存在,但必须进行一些 目录运算 以获取 absolutePathToImageFile:
File f = new File( absolutePathToImageFile ); if(f.exists() && !f.isDirectory())
8.3.3. BrokenCrossReferencesChecker
满足需求 R-2.
交叉引用是文档内部链接,在 HTML 锚标签的 href="link-target" 中没有像 http、https、ftp、telnet、mailto、file 等前缀。
只有以 # 开头的链接应该被考虑,例如 <a href="#internalLink">。
8.3.4. DuplicateIdChecker
满足需求 R-4.
章节,特别是标题,可以通过添加 id="#xyz" 元素作为链接目标,产生如下示例的 HTML 标题。
如果相同的链接目标被多次定义,就会出现问题(如下所示)。
<h2 id="seealso">First Heading</h2> <h2 id="seealso">Second Heading</h2> <a href="#seealso">重复定义 - 现在我该去哪里?</a>
8.3.5. MissingLocalResourcesChecker
满足需求 R-3.
当前限制:
不进行引用带锚点的深度检查,形式如下:
<a href="api/Artifact.html#target">GroupInit</a>
包含本地(文件)引用和内部锚点 #target
请参阅问题 #252(误报)和 #253(应该检查深度链接)。
8.3.7. IllegalLinkChecker
满足需求 R-5.
此检查器已计划,但目前尚未实现。 :jbake-menu: - :numbered: :linkattrs: :experimental:
8.5. 灵活的报告
kbd:[HtmlSC] 允许不同的输出格式:
-
格式(HTML 和文本)和
-
目标(文件和控制台)
报告子系统使用模板方法模式来允许不同的输出格式(例如控制台和 HTML)。报告的总体结构始终相同:
图形客户端可以使用报告子系统的 API 以任意格式显示报告。
(通用和抽象的)报告在抽象的 Reporter 类中实现如下:
/** * 报告的主要入口点 - 当请求报告时调用 * 使用模板方法将具体实现委托给子类 */ public void reportFindings() { initReport() // <1> reportOverallSummary() // <2> reportAllPages() // <3> closeReport() // <4> } // private void reportAllPages() { pageResults.each { pageResult -> reportPageSummary( pageResult ) // <5> pageResult.singleCheckResults.each { resultForOneCheck -> reportSingleCheckSummary( resultForOneCheck ) // <6> reportSingleCheckDetails( resultForOneCheck ) // <7> reportPageFooter() // <8> } }
-
初始化报告,例如创建并打开文件,复制 css、javascript 和图像文件。
-
创建总体概要,包括总体成功百分比和所有已检查页面的列表及其成功率。
-
遍历所有页面
-
写入报告页脚 - 在 HTML 报告中还创建回到顶部链接
-
对于单个页面,报告检查和问题的数量以及成功率
-
对于该页面上的每个单个检查,报告摘要和
-
单个检查的所有详细结果。
-
对于每个已检查的页面,创建页脚、分页符或类似的内容以在视觉上区分页面。
8.5.1. 美化报告输出
-
HtmlReporter 显式地生成 css 类,并与 html 元素一起使用,基于从 Gradle JUnit 插件中重用的 css 样式。
-
样式表、jQuery JavaScript 库的缩小版本以及一些图标在报告生成时从 jar 文件复制到报告输出目录。
-
对返回顶部箭头/按钮进行样式设置是通过 JavaScript 与一些 css 样式的组合完成的,详见 https://www.webtipblog.com/adding-scroll-top-button-website/。
8.5.3. 归属
9. 设计决策
9.1. 推迟对外部链接的检查
这些检查被推迟到以后的版本中。
9.2. 使用 jsoup 进行 HTML 解析
为了检查 HTML,我们将其解析为内部(类似 DOM 的)表示形式。 为此任务,我们使用了 jsoup HTML 解析器,这是一个没有外部依赖的开源解析器。
从 jsoup 网站引用:
- 决策目标
-
通过使用提供对文件的 DOM 树的访问和查找方法的现有 API,以编程方式检查 HTML。
- 决策标准
-
-
尽量减少依赖,使 kbd:[HtmlSC] 二进制文件尽可能小。
-
提供访问器和查找器方法,在 DOM 树中查找图像、链接和链接目标。
-
- 备选方案
-
-
HTTPUnit:用于 Web 应用程序和网站的测试框架。它的主要焦点是 Web 测试,并且受到大量依赖的影响。
-
jsoup:一个纯粹的 HTML 解析器,没有任何依赖项,并且具有丰富的 API,以类似 DOM 的语法访问所有 HTML 元素。
-
查看 kbd:[HtmlSC] 如何实现 HTML 解析的详细信息,请参阅 HTML 封装概念。
9.3. 使用 Jaro-Winkler 距离进行字符串相似性检查
小型的 java-string-similarity 库(由 Ralph Allen Rice 制作)包含了几种相似性计算算法的实现。由于它*不可用*作为公共二进制文件, 我们使用了源码,主要是:
net.ricecode.similarity.JaroWinklerStrategyTest net.ricecode.similarity.JaroWinklerStrategy
Note
|
相似性比较的实际实现已被推迟到 kbd:[HtmlSC] 的后续发布。 |
10. 术语表
有关重要术语的解释,请参阅domain model。