RubyでHTMLを自動整形する
HTMLと言うかXMLの自動インデント。1行でべたっと書かれたXMLに、かしこく改行とインデントを付ける。StringScannerが便利。
require 'strscan' src = %[<html><body><h1>chapter</h1><div><dl><dt>hoge</dt><dl>fuga</dl></dl></div><p>pi<img src="piyo.png"/>yo</p></body></html>] no_indent_tag = %w[html head body] # インデントしない要素 indent_str = ' ' # インデントに使う文字(半角スペース2つ) s = StringScanner.new(src) slash = '/'.unpack('C')[0] indent = 0 body = '' while len = s.exist?(/<\/?([^\ >]+)[^>]*>/) if s.matched[1] != slash # 開きタグ if len == s.matched_size body << "\n" body << indent_str * indent else body << s.peek(len - s.matched_size) end body << s.matched unless s.matched[-2] == slash || # 空要素 no_indent_tag.include?(s[1]) # インデントしない要素 indent += 1 end else # 閉じタグ unless no_indent_tag.include?(s[1]) || indent == 0 indent -= 1 end if len == s.matched_size body << "\n" body << indent_str * indent else body << s.peek(len - s.matched_size) end body << s.matched end s.pos += len end body << s.rest body.lstrip! # 先頭に改行が入ってしまうので削除する puts body
↓実行結果
<html> <body> <h1>chapter</h1> <div> <dl> <dt>hoge</dt> <dl>fuga</dl> </dl> </div> <p>pi<img src="piyo.png"/>yo</p> </body> </html>
テキストの中にあるタグ(≒インライン要素)の前後や、子要素がテキストだけの要素には改行が入らないのがポイント。