HTML Tidyをlintとして使う

[HTML Tidy](https://www.html-tidy.org/)は HTML/XML を整形するツールですが、副次的に HTML/XML の文法チェックも行います。そのままでは少々使い勝手が悪かったので、出力をカスタマイズして lint として使えるようにしてみました。

使用した HTML Tidy のバージョンは 5.7.28 です。

```shell
$ tidy5 --version
HTML Tidy for FreeBSD version 5.7.28
```

## テストデータ

OK用とNG用で二つの HTML ファイルを用意しました。

```html:test_ok.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>テストOK</title>
</head>
<body>
本文
</body>
</html>
```

```html:test_ng.html
<!DOCTYPE html>
<html>
<head>
<meta charset=utf-8>
<title>テストNG
</head>
<body>
本文
</body>
</html>
```

## まず使ってみる

HTML Tidy で文法チェックのみを行うには `-e` オプションを指定します。

```shell
$ tidy5 -e test_ok.html test_ng.html
Info: Document content looks like HTML5
No warnings or errors were found.

line 4 column 1 - Info: value for attribute "charset" missing quote marks
line 5 column 1 - Warning: missing </title> before </head>
Info: Document content looks like HTML5
Tidy found 1 warning and 0 errors!


About HTML Tidy: https://github.com/htacg/tidy-html5
Bug reports and comments: https://github.com/htacg/tidy-html5/issues
Official mailing list: https://lists.w3.org/Archives/Public/public-htacg/
Latest HTML specification: http://dev.w3.org/html5/spec-author-view/
Validate your HTML documents: http://validator.w3.org/nu/
Lobby your company to join the W3C: http://www.w3.org/Consortium

Do you speak a language other than English, or a different variant of
English? Consider helping us to localize HTML Tidy. For details please see
https://github.com/htacg/tidy-html5/blob/master/README/LOCALIZE.md
```

`test_ok.html` に対しては `No warnings or errors were found.`、 `test_ng.html` に対しては `Tidy found 1 warning and 0 errors!` という結果が返ってきました。

ただ、この出力結果では少々使い勝手が悪いですので、以後はラッパスクリプトを作って出力結果をいじっていきます。

```shell:mytidy.sh
#!/bin/sh

for arg; do
    tidy5 -e $arg
done
```

```shell
$ ./mytidy.sh test_ok.html test_ng.html
Info: Document content looks like HTML5
No warnings or errors were found.

(以下省略)
```

## 出力のカスタマイズ

ラッパスクリプトで以下の点で出力をカスタマイズしました。

* `About HTML Tidy: ～` 以降のメッセージは冗長なので、空行以降をカット。`-q` オプションでも抑制できるが、info レベルの出力もカットされてしまう。
* 警告がある際にのみメッセージを出力する。`$?` は info レベルの出力のみの時は 0 になってしまうので、`^line` を含むかどうかで判定。
* メッセージ出力時、対象のファイル名を先に出力。

```shell:mytidy.sh
#!/bin/sh

for arg; do
        result=`tidy5 -e $arg 2>&1 | awk '/^$/ {nooutput=1} { if(!nooutput) print $0 }'`
        status=`echo "$result" | grep '^line'`
        if [ "${status}" != "" ] ; then
                echo "${arg}:"
                echo "${result}"
                echo
        fi
done
```

```shell:mytidy.sh
> ./mytidy.sh test_ok.html test_ng.html
test_ng.html:
line 4 column 1 - Info: value for attribute "charset" missing quote marks
line 5 column 1 - Warning: missing </title> before </head>
Info: Document content looks like HTML5
Tidy found 1 warning and 0 errors!
```

最終的には、以下のように全 HTML ファイルに対して lint をかけています。

```shell
$ find . -name "*.html" | xargs mytidy.sh
```

## 経緯

冒頭に HTML の文法チェックをしようと思った経緯を書こうとしたのですが、少々長くなってしまったので末尾にもってきました。

私は[あおやぎのさいと](https://www.saoyagi2.net/)という個人サイトを20年以上やっているのですが、令和の今になっても HTML 手打ちで作ってます。CMS を使っていた時期もあるのですが、これだけサイト運営が長くなってくると、CMS の寿命の方が先に尽きてしまい、都度 CMS の移行となってしまいます。ならば HTML 手打ちで作ってった方が楽かなというのが今のところの結論です。

とはいえ全てを HTML 手打ちだけで作っていると大変ですので、補助的にツールを使ったりスクリプト書いたりして対応しています。その一環で lint として HTML Tidy を使ってみたわけです。

手打ちに限りませんが、HTML を書いているときには文法チェックが必要です。閉じタグ忘れてたり、タグの対応が違ってたりとかですね。多少の文法エラーはブラウザが勝手に推測して補正してくれるのですが、すべてのブラウザが同じように補正してくれるとは限りませんし、何よりも文法エラーは無い状態に保ちたいものです。

HTML 文法チェックを行うウェブサービスはいくつもあるのですが、これらはフォーム上に HTML を張り付けるか URL を指定して単独の HTML ファイルを検証するタイプです。既に数百ページのストックのある歴史あるサイト全体を文法チェックしたいという用途には向きません。ということでローカル環境でコマンドラインで使えるようなツールを探すことになります。

これまでは文法チェックには、[Another HTML-lint](http://openlab.ring.gr.jp/k16/htmllint/index.html)というツールを使ってきました。しかしこちらは HTML 4.01 までしか対応していません。独自に拡張して HTML5 に対応している[Another HTML-lint 5](http://www.htmllint.net/html-lint/index.html)というのもあるのですが、ウェブサービスとしてのみの提供ですので私の要望には合いませんでした。なんとか HTML5 に対応したツールがないものかと探したところ、今回見つけたのが HTML Tidy だったというわけです。