Goのgolang.org/x/net/htmlパッケージでBOM付きUTF-8にやられた話
複数のhtmlファイルに対して、特定のhtml要素を差し込んで保存するのにgolang.org/x/net/html使ってDOM操作すればいける!と思って実装していると、一部htmlでDOMをRenderした結果がおかしくなった。
具体的にはこんなコードで
package main
import (
"os"
"golang.org/x/net/html"
)
func main() {
f, _ := os.Open("./index.html")
defer f.Close()
doc, _ := html.Parse(f)
html.Render(os.Stdout, doc)
}
こんなhtmlを
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>こんなhtml</title>
</head>
<body>
It Works.
</body>
</html>
ParseしてRenderした結果が
<html lang="ja"><head></head><body>
<meta charset="utf-8"/>
<title>こんなhtml</title>
It works.
</body></html>
こんなん。head要素にあったものが全てbody内に入ってしまう、という状態。
ググってもそもそもgolang.org/x/net/html
の事例が少ないし、オリジナルのhtmlから少しずつ行を削除して試してを繰り返すも状況変わらないし、途方にくれているところでふとfile
コマンドを実行してみると
$ file index.html
index.html: HTML document text, UTF-8 Unicode (with BOM) text, with very long lines, with CRLF line terminators
タイトル通りですが、BOMのせいでした。以下のような関数を用意して、あらかじめBOMを除去した上でパースすればOKでした。
func stripBOM(b []byte) []byte {
stripped := bytes.Trim(b, "\xef\xbb\xbf")
return stripped
}
参考
- Go言語では、BOMは謎の概念なのでライブラリの実装にBOM関連の処理を組み込む事はない、と
encoding/csv
に関するイシューで言及あり。納得感ある話。