なんとな~くしあわせ?の日記

「そしてそれゆえ、知識そのものが力である」 (Nam et ipsa scientia potestas est.) 〜 フランシス・ベーコン

libxml2でHTMLを整形する

だいぶ前にlibxml2を使ってHTMLをパースした。

f:id:panzer-jagdironscrap1:20141215220338g:plain


libxmlでHTMLParserを使う - なんとな~くしあわせ?の日記

libxml2のAPIを見ていると、HTMLの整形も出来るらしいのでやってみた。

使用したAPI

htmlDocContentDumpFormatOutput

http://xmlsoft.org/html/libxml-HTMLtree.html#htmlDocContentDumpFormatOutput

void	htmlDocContentDumpFormatOutput	(xmlOutputBufferPtr buf, 
					 xmlDocPtr cur, 
					 const char * encoding, 
					 int format)
Dump an HTML document.
HTMLの文書を出力する

buf:	the HTML buffer output
cur:	the document
encoding:	the encoding string
format:	should formatting spaces been added
htmlReadMemory

http://xmlsoft.org/html/libxml-HTMLparser.html#htmlReadMemory

htmlDocPtr	htmlReadMemory		(const char * buffer, 
					 int size, 
					 const char * URL, 
					 const char * encoding, 
					 int options)
parse an XML in-memory document and build a tree.
XMLをメモリ上でパースしてHTMLのリストを構築する

buffer:	a pointer to a char array
size:	the size of the array
URL:	the base URL to use for the document
encoding:	the document encoding, or NULL
options:	a combination of htmlParserOption(s)
Returns:	the resulting document tree
xmlOutputBufferCreateIO

http://xmlsoft.org/html/libxml-xmlIO.html#xmlOutputBufferCreateIO

xmlOutputBufferPtr	xmlOutputBufferCreateIO	(xmlOutputWriteCallback iowrite, 
						 xmlOutputCloseCallback ioclose, 
						 void * ioctx, 
						 xmlCharEncodingHandlerPtr encoder)
Create a buffered output for the progressive saving to an I/O handler
入出力ハンドラを漸進的に保存するためのバッファされた出力を作る
(うまく訳せないけど一方で読み込んで一方で書き出す入出力ストリームを作る)

iowrite:	an I/O write function
ioclose:	an I/O close function
ioctx:	an I/O handler
encoder:	the charset encoding if known
Returns:	the new parser output or NULL

サンプルコード

難しいのはxmlOutputBufferPtrの構築。
この構造体はコールバックとして書き出しとクローズの関数を持っている。コールバックがどのように文字列を書き出すか設定してやる必要がある。あとはAPIにしたがって関数を使うだけだ。

static int writeToWxString(void* context, const char* buffer, int len) {
     wxString* t = static_cast<wxString*>(context);
     *t += wxString(buffer, wxConvUTF8, len);
     return len;
}

static void closeWxString(void* context) {
     wxString* t = static_cast<wxString*>(context);
     *t += wxString::FromAscii("\n");
}

/**
 * HTML整形
 */
const wxString HtmlFormat(const wxString& html)
{
     htmlDocPtr docPtr = htmlReadMemory(html.mb_str(), html.Len(), "", "utf-8", HTML_PARSE_RECOVER);
     if (docPtr)
     {
	  // libxml2の***Ptrは何かの構造体のポインタ
	  wxString val;
	  xmlOutputBufferPtr buf = xmlOutputBufferCreateIO((xmlOutputWriteCallback)writeToWxString,
							   (xmlOutputCloseCallback)closeWxString,
							   &val, 0);
	  
	  htmlDocContentDumpOutput(buf,
				   docPtr, 
				   "utf-8");

	  return val;
     }
}