非整形HTMLからsimplexmlの生成

Tidyを使う方法はもちろんですが、他にも選択肢はあります。
Tidy使えないときのためにHTMLParserとXML_HTMLSAX3を使う方法を以下においておきます。

用意するもの

  1. HTMLParser-1.2.1
  2. XML_HTMLSAX3(HTMLParserに付属しているはずです)

下ごしらえ

  1. HTMLCleaner.class.phpという空のファイルを用意
  2. 同階層にHTMLParser-1.2.1のディレクトリを置きます
HTMLCleaner.class.php
<?php
//-------------------------------------
// 未整形HTMLの解析
class HTMLCleaner {
	
	protected $htmlparser_lib_dir;
	protected $parser;
	
	//-------------------------------------
	// コンストラクタ
	public function __construct () {
		
		$this->htmlparser_dir =dirname(__FILE__).'/HTMLParser-1.2.1';
		
		define("XML_HTMLSAX3",$this->htmlparser_dir.'/XML/');
		require_once($this->htmlparser_dir.'/HTMLParser.class.php');
		
		$this->parser =new HTMLParser;
		$this->parser->setRuleFile($this->htmlparser_dir.'/xhtml1-transitional_dtd.inc.php');
		$this->parser->setRoot('html',array("lang" =>"ja"));
	}

	//-------------------------------------
	// HTMLの解析修正
	public function clean_html ($html) {
	
		$parser =clone $this->parser;
		$parser->parse($html);
		return $parser->dump();
	}

	//-------------------------------------
	// HTMLからsimplexmlを得る
	public function get_simplexml ($html) {
		
		// UTF-8の文字セット正規化
		$utf_escape_patterns =array(
		
			// 波ダッシュを全角チルダ(〜)へ変換
			'/\xE3\x80\x9C/' =>"\xEF\xBD\x9E",
			
			// 全角マイナス記号(−)の変換
			'/\xE2\x88\x92/' =>"\xEF\xBC\x8D",
			
			// 双柱・平行記号(‖)の変換
			'/\xE2\x80\x96/' =>"\xE2\x88\xA5",
			
			// セント記号(¢)の変換 
			'/\xC2\xA2/' =>"\xEF\xBF\xA0",
			
			// ポンド記号(£)の変換
			'/\xC2\xA3/' =>"\xEF\xBF\xA1",
			
			// 否定記号(¬)の変換
			'/\xC2\xAC/' =>"\xEF\xBF\xA2",
		);
		$html =preg_replace(
				array_keys($utf_escape_patterns),
				array_values($utf_escape_patterns),
				$html);

		$html =preg_replace('!<\!--.*?-->!s','',$html);
		$html =preg_replace(
				'!<\!\[CDATA\s*\[(.*?)\]\]>!se',
				'htmlspecialchars("$1");',
				$html);
		$html =str_replace('&nbsp;',' ',$html);
		$html =$this->clean_html($html);
		$xml =simplexml_load_string($html,null,LIBXML_COMPACT);
		
		if ( ! $xml instanceof SimpleXMLElement) {
		
			print htmlspecialchars($html);
		}
		
		return $xml;
	}
}