Tidy.NETでHTMLを清書する
下記のページによれば、汚いHTMLをXHTMLに清書できる(はず)。
- http://bytes.com/groups/net-c/576661-tidy-net
- http://www.developmentnow.com/g/36_2006_12_0_0_864791/Tidy-Net.htm
- http://refactormycode.com/codes/333-sanitize-html
- http://blog.levo.us/index.php/2008/04/18/quickly-fixing-crappy-invalid-html-using-c/
こんな感じ↓
string cleanupHtml(string text) { Tidy doc = new Tidy(); TidyMessageCollection messages = new TidyMessageCollection(); MemoryStream input = new MemoryStream(); MemoryStream output = new MemoryStream(); byte[] array = Encoding.UTF8.GetBytes(text); input.Write(array, 0, array.Length); input.Position = 0; doc.Options.DocType = DocType.Strict; doc.Options.Xhtml = true; doc.Options.LogicalEmphasis = true; doc.Options.MakeClean = false; doc.Options.SmartIndent = false; doc.Options.IndentContent = false; doc.Options.TidyMark = false; doc.Options.DropFontTags = false; doc.Options.QuoteAmpersand = true; doc.Options.DropEmptyParas = true; doc.Options.CharEncoding = CharEncoding.UTF8; doc.Parse(input, output, messages); string result = Encoding.UTF8.GetString(output.ToArray()); return result; }
日本語通るかやってみたが、ダメだった。orz
ソースコードをちらっと見てみたけど大丈夫そうなんだけどなー。
↑ウソ:これが原因。
しょうがないので、こっちでやります。
ネイティブバイナリのtidy.dllでHTMLを清書する
が失敗しました。orz
やはり、日本語が文字化けします。何か間違ってるんだろうか・・・
↑ウソ:これが原因
using System; using System.Text; using System.Runtime.InteropServices; namespace TMGBCReserver { public class Tidy32 { [StructLayout(LayoutKind.Sequential)] public struct TidyBuffer { public IntPtr bp; /**< Pointer to bytes */ public uint size; /**< # bytes currently in use */ public uint allocated; /**< # bytes allocated */ public uint next; /**< Offset of current input position */ }; [DllImport("tidy.dll")] public static extern int tidyBufAlloc(ref TidyBuffer tidyBuffer, int allocSize); [DllImport("tidy.dll")] public static extern int tidyBufFree(ref TidyBuffer tidyBuffer); [DllImport("tidy.dll")] public static extern IntPtr tidyCreate(); [DllImport("tidy.dll")] public static extern int tidyParseFile(IntPtr tidyPointer, [MarshalAs(UnmanagedType.LPStr)]string fileName); [DllImport("tidy.dll")] public static extern int tidyParseBuffer(IntPtr tidyPointer, [MarshalAs(UnmanagedType.Struct)] ref TidyBuffer tidyBuffer); [DllImport("tidy.dll")] public static extern int tidyCleanAndRepair(IntPtr tidyPointer); [DllImport("tidy.dll")] public static extern int tidySaveFile(IntPtr tidyPointer, [MarshalAs(UnmanagedType.LPStr)]string outFileName); [DllImport("tidy.dll")] public static extern int tidySaveBuffer(IntPtr tidyPointer, [MarshalAs(UnmanagedType.Struct)] ref TidyBuffer tidyBuffer); [DllImport("tidy.dll")] public static extern int tidyRelease(IntPtr tidyPointer); [DllImport("tidy.dll")] public static extern int tidySetCharEncoding(IntPtr tidyPointer, [MarshalAs(UnmanagedType.LPStr)]string encoding); [DllImport("tidy.dll")] public static extern int tidyOptSetBool(IntPtr tidyPointer, int value, int Bool); public static string CleanFile(string inputHtml) { string result; byte[] inputArray = Encoding.UTF8.GetBytes(inputHtml); TidyBuffer tidyBuffer2; tidyBuffer2.size = 0; tidyBuffer2.allocated = 0; tidyBuffer2.next = 0; tidyBuffer2.bp = (IntPtr)0; tidyBufAlloc(ref tidyBuffer2, 1024 * 1024); IntPtr tidyPointer = tidyCreate(); try { // We want the resulting file to be UTF8 encoded tidySetCharEncoding(tidyPointer, "utf8"); TidyBuffer tidyBuffer1; tidyBuffer1.size = (uint)inputArray.Length; tidyBuffer1.allocated = (uint)inputArray.Length; tidyBuffer1.next = 0; GCHandle pinHandle = GCHandle.Alloc(inputArray, GCHandleType.Pinned); try { tidyBuffer1.bp = Marshal.UnsafeAddrOfPinnedArrayElement(inputArray, 0); if (tidyParseBuffer(tidyPointer, ref tidyBuffer1) >= 0) { tidyOptSetBool(tidyPointer, 29, 1); tidyOptSetBool(tidyPointer, 23, 1); if (tidyCleanAndRepair(tidyPointer) >= 0) { int rc = tidySaveBuffer(tidyPointer, ref tidyBuffer2); } } } finally { pinHandle.Free(); } byte[] outputArray = new byte[tidyBuffer2.size]; Marshal.Copy(tidyBuffer2.bp, outputArray, 0, outputArray.Length); result = Encoding.UTF8.GetString(outputArray, 0, outputArray.Length); } finally { tidyBufFree(ref tidyBuffer2); tidyRelease(tidyPointer); } return result; } } }
WebBrowserコントロールのDocumentTextプロパティの罠
WebBrowserコントロールで表示しているHTMLをXHTMLに清書しようと
webBrowser1.DocumentText
を入力としてTidy.NETやtidy.dllやHTML2XHTMLを使うと不思議と文字化けします。エンコーディングにUTF-8を指定してもダメ。
で、原因がわかりました。HTMLがShift-JISで書かれている場合にDocumentTextプロパティの値が文字化けするようです。ヘッダでエンコーディングが指定されてないのが原因かも。
webBrowser1.Document.Body.OuterHtml
などは正常なので、気づきにくい罠です。
こうやって文字化けを直してあげると、Tidy.NETで正常にXHTMLへ変換できました。
MemoryStream reader = (MemoryStream)this.window.DocumentStream; byte[] bytes = reader.ToArray(); string html = Encoding.GetEncoding("shift_jis").GetString(bytes);