<?xml version="1.0" encoding="UTF-8" ?>
<entry
	xmlns="http://www.w3.org/2005/Atom"
	xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
	xml:lang="ja-JP"
>
	<title>ひどいHTMLをSAXパーサに読ませる</title>
	<id>tag:txqz.net,2007-08-10:blog/2007/08/10/1200</id>
	<link rel="self" href="http://txqz.net/blog/2007/08/10/1200.atom"/>
	<link rel="alternate" type="application/rss+xml" href="http://txqz.net/blog/2007/08/10/1200.rdf"/>
	<link rel="alternate" type="application/xhtml+xml" href="http://txqz.net/blog/2007/08/10/1200.xhtml"/>
	<link rel="alternate" type="text/html" href="http://txqz.net/blog/2007/08/10/1200.html"/>
	<link rel="contents" href="http://txqz.net/blog/2007/08/10/.atom" title="2007年8月10日"/>
	<link rel="first" href="http://txqz.net/blog/2001/08/04/0001.atom" title="地球空冷化"/>
	<link rel="prev" href="http://txqz.net/blog/2007/08/09/1957.atom" title="RubyというかRails勉強会"/>
	<link rel="next" href="http://txqz.net/blog/2007/08/10/1343.atom" title="ISTのブログパーツに2007年度最優秀ブログパーツ賞を授与すべき"/>
	<link rel="last" href="http://txqz.net/blog/2008/12/19/2152.atom" title="浜松市街地を通り抜けて、ムーンライトながら～の思い出"/>
	<author>
		<name>陽坂智佐</name>
		<email>spambasket@txqz.net</email>
	</author>
	<content type="xhtml">
		<div xmlns="http://www.w3.org/1999/xhtml">
<p><a href="http://txqz.net/blog/2007/03/11/0711" title="なぜ人はこんなにひどいHTMLを書くのだろう">先日取り上げたexblogのひどいHTML</a>を、HTML向けSAXパーサに読ませるとどうなるかの実験。startElement()やendElement()がどうコールされるかによって、パーサごとの性格が現れる。</p>
<h2>コールバックメソッド</h2>
<p><var>level</var>はネストの深さを表すインスタンス変数。</p>
<pre><code class="java">public void startElement(String uri, String localName, String qName, Attributes attrs){
    for(int i = 0; i &lt; level; i++) System.out.print(" ");
    System.out.print("&lt;"+localName);
    for(int i = 0; i &lt; attrs.getLength(); i++)
        System.out.print(" "+attrs.getQName(i)+"=\""+attrs.getValue(i)+"\"");
    System.out.println("&gt;");
    level++;
}
public void endElement(String uri, String localName, String qName){
    level--;
    for(int i = 0; i &lt; level; i++) System.out.print(" ");
    System.out.println("&lt;/"+localName+"&gt;");
}
public void characters(char[] ch, int offset, int length){
    for(int i = 0; i &lt; level; i++) System.out.print(" ");
    System.out.println(StringUtils.substring(new String(ch,offset,length).trim(),0,20));
}</code></pre>
<h2>対象となるHTML (1)</h2>
<p>例によって見やすいように改行とインデントを加えています。</p>
<pre><code class="html">&lt;DIV CLASS=MNBODY&gt;
 &lt;TABLE WIDTH=150 BORDER=0 CELLSPACING=0 CELLPADDING=0 ALIGN=CENTER&gt;
  &lt;TR&gt;
   &lt;TD COLSPAN=3&gt;
    &lt;FORM NAME=finder METHOD=GET ACTION=http://www.exblog.jp/search/&gt;
     &lt;INPUT TYPE=HIDDEN NAME=blogid VALUE=970055211&gt;
   &lt;/TD&gt;
  &lt;/TR&gt;
  &lt;INPUT TYPE=HIDDEN NAME=t VALUE=0&gt;
  &lt;TR&gt;
   &lt;TD WIDTH=105 ALIGN=LEFT&gt;
    &lt;INPUT TYPE=TEXT NAME=q SIZE=15  CLASS=TXTFLD&gt;
   &lt;/TD&gt;
   &lt;TD WIDTH=5&gt;&lt;/TD&gt;
   &lt;TD WIDTH=40 ALIGN=LEFT&gt;
    &lt;INPUT TYPE=SUBMIT VALUE="検索" STYLE="WIDTH:40;HEIGHT:20;"&gt;
   &lt;/TD&gt;
  &lt;/TR&gt;
  &lt;TR&gt;
   &lt;TD COLSPAN=3&gt;
    &lt;/FORM&gt;
   &lt;/TD&gt;
  &lt;/TR&gt;
 &lt;/TABLE&gt;
&lt;/DIV&gt;</code></pre>
<h3><a href="http://people.apache.org/~andyc/neko/doc/html/" title="NekoHTML">CyberNeko HTML Parser</a>の場合</h3>
<pre><samp>&lt;DIV class="MNBODY"&gt;
 &lt;TABLE width="150" border="0" cellspacing="0" cellpadding="0" align="CENTER"&gt;
  &lt;TR&gt;
   &lt;TD colspan="3"&gt;
    &lt;FORM name="finder" method="GET" action="http://www.exblog.jp/search/"&gt;
     &lt;INPUT type="HIDDEN" name="blogid" value="970055211"&gt;
     &lt;/INPUT&gt;
    <em>&lt;/FORM&gt;</em>
   &lt;/TD&gt;
  &lt;/TR&gt;
  &lt;INPUT type="HIDDEN" name="t" value="0"&gt;
  &lt;/INPUT&gt;
  &lt;TR&gt;
   &lt;TD width="105" align="LEFT"&gt;
    &lt;INPUT type="TEXT" name="q" size="15" class="TXTFLD"&gt;
    &lt;/INPUT&gt;
   &lt;/TD&gt;
   
   &lt;TD width="5"&gt;
   &lt;/TD&gt;
   
   &lt;TD width="40" align="LEFT"&gt;
    &lt;INPUT type="SUBMIT" value="検索" style="WIDTH:40;HEIGHT:20;"&gt;
    &lt;/INPUT&gt;
   &lt;/TD&gt;
  &lt;/TR&gt;
  &lt;TR&gt;
   &lt;TD colspan="3"&gt;
   &lt;/TD&gt;
  &lt;/TR&gt;
 &lt;/TABLE&gt;
&lt;/DIV&gt;</samp></pre>
<p>td要素の終了を優先し、td要素内のform要素に終了タグを補完した。table直下にinputが残っている。</p>
<ins class="ps" datetime="2008-06-19T15:19:58+09:00" id="PS1213856398">
<p><a href="http://lobobrowser.org/cobra.jsp" title="Cobra: Pure Java HTML Renderer &amp; Parser (Open Source)">Cobra 0.98.2</a>でも同様の結果になった。</p>
</ins>
<h3><a href="http://home.ccil.org/~cowan/XML/tagsoup/" title="TagSoup home page">TagSoup</a>の場合</h3>
<p>Tag Soupの場合、URIを指定して直接読ませたりInputStreamを読ませたりすると日本語が文字化けするので、いったんStringに落としたものをSAXParserに読ませた。</p>
<pre><samp>&lt;div class="MNBODY"&gt;
 &lt;table align="CENTER" width="150" border="0" cellspacing="0" cellpadding="0"&gt;
  &lt;tr&gt;
   &lt;td colspan="3" rowspan="1"&gt;
    &lt;form enctype="application/x-www-form-urlencoded" method="GET" name="finder" action="http://www.exblog.jp/search/"&gt;
     &lt;input type="HIDDEN" name="blogid" value="970055211"&gt;
     &lt;/input&gt;
     <em>&lt;input type="HIDDEN" name="t" value="0"&gt;
     &lt;/input&gt;</em>
     &lt;tr&gt;
      &lt;td align="LEFT" colspan="1" rowspan="1" width="105"&gt;
       &lt;input type="TEXT" class="TXTFLD" name="q" size="15"&gt;
       &lt;/input&gt;
      &lt;/td&gt;
      &lt;td colspan="1" rowspan="1" width="5"&gt;
      &lt;/td&gt;
      &lt;td align="LEFT" colspan="1" rowspan="1" width="40"&gt;
       &lt;input type="SUBMIT" value="検索" style="WIDTH:40;HEIGHT:20;"&gt;
       &lt;/input&gt;
      &lt;/td&gt;
     &lt;/tr&gt;
     &lt;tr&gt;
      &lt;td colspan="3" rowspan="1"&gt;
      &lt;/td&gt;
     &lt;/tr&gt;
    &lt;/form&gt;
   &lt;/td&gt;
  &lt;/tr&gt;
 &lt;/table&gt;
&lt;/div&gt;</samp></pre>
<p>form要素の連続性を優先したが、結果としてform要素の直下にtr要素が出現してしまった。</p>
<h3><a href="https://java.sun.com/j2se/1.5.0/ja/docs/ja/api/javax/swing/text/html/HTMLEditorKit.ParserCallback.html" title="HTMLEditorKit.ParserCallback (Java 2 Platform SE 5.0)">HTMLEditorKit.ParserCallback</a>の場合</h3>
<p>これはHTML3.2のパーサで、XHTMLを読ませると具合が悪い。でもついでなのでやってみた。ソースは:</p>
<pre><code class="java">public void handleStartTag(HTML.Tag tag, MutableAttributeSet attrs, int pos){
    for(int i = 0; i &lt; level; i++) System.out.print(" ");
    System.out.print("&lt;"+tag);
    Enumeration e = attrs.getAttributeNames();
    while(e.hasMoreElements()){
        Object o = e.nextElement();
        System.out.print(" "+o+"=\""+attrs.getAttribute(o)+"\"");
    }
    System.out.println("&gt;");
    level++;
}
public void handleSimpleTag(HTML.Tag tag, MutableAttributeSet attrs, int pos){
    for(int i = 0; i &lt; level; i++) System.out.print(" ");
    System.out.print("&lt;"+tag);
    Enumeration e = attrs.getAttributeNames();
    while(e.hasMoreElements()){
        Object o = e.nextElement();
        System.out.print(" "+o+"=\""+attrs.getAttribute(o)+"\"");
    }
    System.out.println(" /&gt;");
}
public void handleEndTag(HTML.Tag tag, int pos){
    level--;
    for(int i = 0; i &lt; level; i++) System.out.print(" ");
    System.out.println("&lt;/"+tag+"&gt;");
}
public void handleText(char[] data, int pos){
    for(int i = 0; i &lt; level; i++) System.out.print(" ");
    System.out.println(StringUtils.substring(new String(data).trim(),0,20));
}</code></pre>
<p>結果は</p>
<pre><samp>&lt;div class="mnbody"&gt;
 &lt;table cellspacing="0" align="center" border="0" width="150" cellpadding="0"&gt;
  &lt;tr&gt;
   &lt;td colspan="3"&gt;
    &lt;form name="finder" action="http://www.exblog.jp/search/" method="get"&gt;
     &lt;input value="970055211" name="blogid" type="hidden" /&gt;
    &lt;/form&gt;
   &lt;/td&gt;
  &lt;/tr&gt;
  <em>&lt;tr _implied_="true"&gt;
   &lt;td _implied_="true"&gt;</em>
    &lt;input value="0" name="t" type="hidden" /&gt;
   &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;td align="left" width="105"&gt;
    &lt;input name="q" size="15" type="text" class="txtfld" /&gt;
   &lt;/td&gt;
   &lt;td width="5"&gt;
   &lt;/td&gt;
   &lt;td align="left" width="40"&gt;
    &lt;input style="WIDTH:40;HEIGHT:20;" value="検索" type="submit" /&gt;
   &lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
   &lt;td colspan="3"&gt;
   &lt;/td&gt;
  &lt;/tr&gt;
 &lt;/table&gt;
&lt;/div&gt;</samp></pre>
<p>table直下のinput要素をtrとtdでラップした。3つの中では結構成功に近い結果を出したのではないだろうか。ただ、このパーサはXHTMLにまったく対応していないのが残念。バージョンアップしないのかな。</p>
<ins class="ps" datetime="2008-06-19T13:56:31+09:00" id="PS1213851391">
<h3><a href="http://mozillaparser.sourceforge.net/" title="Mozilla Java Html Parser">Mozilla Java Html Parser</a>の場合</h3>
<p>これはSAXパーサではないので、DOMをプリントする必要があるが、その結果以下のようになった:</p>
<pre><samp>&lt;div class="MNBODY"&gt;
 &lt;table width="150" border="0" cellspacing="0" cellpadding="0" align="CENTER"&gt;
  &lt;tbody&gt;
   &lt;tr&gt;
    &lt;td colspan="3"&gt;
     &lt;form name="finder" method="GET" action="http://www.exblog.jp/search/"&gt;
      &lt;input type="HIDDEN" name="blogid" value="970055211"&gt;&lt;/input&gt;
     &lt;/form&gt;
    &lt;/td&gt;
    &lt;input type="HIDDEN" name="t" value="0"&gt;&lt;/input&gt;
    &lt;tr&gt;
     &lt;td width="105" align="LEFT"&gt;
      &lt;input type="TEXT" name="q" size="15" class="TXTFLD"&gt;&lt;/input&gt;
     &lt;/td&gt;
     &lt;td width="5"&gt;&lt;/td&gt;
     &lt;td width="40" align="LEFT"&gt;
      &lt;input type="SUBMIT" value="検索" style="WIDTH:40;HEIGHT:20;"&gt;&lt;/input&gt;
     &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
     &lt;td colspan="3"&gt;
     &lt;/td&gt;
    &lt;/tr&gt;
   &lt;/tr&gt;
  &lt;/tbody&gt;
 &lt;/table&gt;
&lt;/div&gt;</samp></pre>
<p>tbodyが補完されているのがいかにもMozillaのパーサという感じだが、tr直下にinputやtrが来てしまっている点が惜しい。とはいえ、これ以上どう修正すればいいのだろう。</p>
</ins>
<ins class="ps" datetime="2008-06-19T14:52:35+09:00" id="PS1213854755">
<h3><a href="http://htmlcleaner.sourceforge.net/" title="HtmlCleaner Project Home Page">HTMLCleaner</a>の場合</h3>
<pre><samp>&lt;div class="MNBODY"&gt;
 &lt;input name="t" type="HIDDEN" value="0"&gt;&lt;/input&gt;
 &lt;table align="CENTER" border="0" cellpadding="0" cellspacing="0" width="150"&gt;
  &lt;tbody&gt;
   &lt;tr&gt;
    &lt;td colspan="3"&gt;
     &lt;form action="http://www.exblog.jp/search/" method="GET" name="finder"&gt;
      &lt;input name="blogid" type="HIDDEN" value="970055211"&gt;&lt;/input&gt;
     &lt;/form&gt;
    &lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
    &lt;td align="LEFT" width="105"&gt;
     &lt;input class="TXTFLD" name="q" size="15" type="TEXT"&gt;&lt;/input&gt;
    &lt;/td&gt;
    &lt;td width="5"&gt;&lt;/td&gt;
    &lt;td align="LEFT" width="40"&gt;
     &lt;input style="WIDTH:40;HEIGHT:20;" type="SUBMIT" value="検索"&gt;&lt;/input&gt;
    &lt;/td&gt;
   &lt;/tr&gt;
   &lt;tr&gt;
    &lt;td colspan="3"&gt;&lt;/td&gt;
   &lt;/tr&gt;
  &lt;/tbody&gt;
 &lt;/table&gt;
&lt;/div&gt;</samp></pre>
<p>実はMozillaParserより頭が良かったりして。</p>
</ins>
<h2>対象となるHTML (2)</h2>
<p>もう1つ例を挙げる。p要素下にdiv要素があり、さらにその子供にp要素があるケース。具体的に言うと<a href="http://business.nikkeibp.co.jp/article/topics/20070806/131744/" title="自民大敗、本当の理由 (ニュースを斬る)：NBonline(日経ビジネス オンライン)">自民大敗、本当の理由 (ニュースを斬る)：NBonline(日経ビジネス オンライン)</a>。("(中略)"以外のコメントは元からあったもの)</p>
<pre><code class="html">&lt;td valign="top" rowspan="2" class="main_part"&gt;
 &lt;div id="articlecontent"&gt;
  &lt;h1 class="articleheader"&gt;自民大敗、本当の理由&lt;/h1&gt;
  &lt;h2 class="articleheader"&gt;小泉改革路線に逆行する安倍自民を国民が拒絶&lt;/h2&gt;
  &lt;ul class="articledata"&gt;
   &lt;li&gt;2007年8月7日　火曜日&lt;/li&gt;
   &lt;li&gt;&lt;a href="/bns/author.jsp?ID=131744&amp;OFFSET=0"&gt;谷川　博&lt;/a&gt;&lt;/li&gt;
  &lt;/ul&gt;
  &lt;div class="articlekeyword_wrapper"&gt;
   &lt;div class="articlekeyword"&gt;
    &lt;a href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%CF%C0%C5%C0"&gt;論点&lt;/a&gt;　
    &lt;a href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%BB%B2%B1%A1%C1%AA"&gt;参院選&lt;/a&gt;　
    &lt;a href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%B0%C2%C7%DC%C0%AF%B8%A2"&gt;安倍政権&lt;/a&gt;　
    &lt;a href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%BE%AE%C0%F4%B2%FE%B3%D7"&gt;小泉改革&lt;/a&gt;　
   &lt;/div&gt;
  &lt;/div&gt;
  &lt;p&gt;
   &lt;!--囲み --&gt;
   &lt;div class="kakomi"&gt;
    &lt;p&gt;参院選での自民党大敗については、既に年金問題、政治とカネ、閣僚の失言などいくつもの原因が挙げられている。だが、河野太郎・衆議院議員は根底にある本質的な敗因は、小泉改革の継承者であるはずの安倍政権と自民党が継承者としての責務を果たさず、むしろ逆行していることだと断ずる。「昔の自民党」に戻るなら、次の選挙も危うい。（聞き手は、日経ビジネス オンライン＝谷川 博）&lt;/p&gt;
   &lt;/div&gt;
   &lt;!--//囲み//  --&gt;
  &lt;/p&gt;
  &lt;p&gt;
   &lt;!--画像 --&gt;
   &lt;div class="figure" style="width:250px;"&gt;
    &lt;img src="250px1.jpg"&gt;
    &lt;p&gt;河野太郎・衆議院議員&lt;/p&gt;
   &lt;/div&gt;
   &lt;!--//画像// --&gt;
  &lt;/p&gt;
  &lt;p&gt;&lt;strong&gt;NBO&lt;/strong&gt;　参院選は自民党の「歴史的大敗」となりました。年金の記録漏れ問題や「政治とカネ」の問題、閣僚の失言など様々な問題が重なり、自民党に激しい逆風が吹いた結果だと言われています。&lt;/p&gt;
  <em>&lt;!--(中略)--&gt;</em>
  &lt;div class="blocktitle_l"&gt;
   &lt;iframe width="528" height="100" marginwidth="0" marginheight="0" hspace="0" vspace="0" frameborder="0" scrolling="no" bordercolor="#000000" src="http://bizad.nikkeibp.co.jp/NBP_AD/nbonline/ad/nbo_thisweek.shtml"&gt;
   &lt;/iframe&gt;
  &lt;/div&gt;
 &lt;/div&gt;
&lt;/td&gt;</code></pre>
<p>インタビュー本文のある段落をCSSセレクタ風に書くと、<code>td.main_part &gt; div#articlecontent &gt; p</code>となる。</p>
<h3><a href="http://people.apache.org/~andyc/neko/doc/html/" title="NekoHTML">CyberNeko HTML Parser</a>の場合</h3>
<p>長くなるので、一部改行とインデントを削除した。</p>
<pre><samp>&lt;TD valign="top" rowspan="2" class="main_part"&gt;
 &lt;DIV id="articlecontent"&gt;
  &lt;H1 class="articleheader"&gt;自民大敗、本当の理由&lt;/H1&gt;
  &lt;H2 class="articleheader"&gt;
   小泉改革路線に逆行する安倍自民を国民が拒
  &lt;/H2&gt;
  &lt;UL class="articledata"&gt;
   &lt;LI&gt;2007年8月7日　火曜日&lt;/LI&gt;
   &lt;LI&gt;&lt;A href="/bns/author.jsp?ID=131744&amp;OFFSET=0"&gt;谷川　博&lt;/A&gt;&lt;/LI&gt;
  &lt;/UL&gt;
  &lt;DIV class="articlekeyword_wrapper"&gt;
   &lt;DIV class="articlekeyword"&gt;
    &lt;A href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%CF%C0%C5%C0"&gt;論点&lt;/A&gt;　
    &lt;A href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%BB%B2%B1%A1%C1%AA"&gt;参院選&lt;/A&gt;　
    &lt;A href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%B0%C2%C7%DC%C0%AF%B8%A2"&gt;安倍政権&lt;/A&gt;　
    &lt;A href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%BE%AE%C0%F4%B2%FE%B3%D7"&gt;小泉改革&lt;/A&gt;　
   &lt;/DIV&gt;
  &lt;/DIV&gt;
  <em>&lt;P&gt;
   &lt;DIV class="kakomi"&gt;
   &lt;/DIV&gt;
  &lt;/P&gt;
  &lt;P&gt;
   参院選での自民党大敗については、既に年金
   の選挙も危うい。（聞き手は、日経ビジネス
  &lt;/P&gt;</em>
 &lt;/DIV&gt;
 &lt;P&gt;
 &lt;/P&gt;
 &lt;P&gt;
  &lt;DIV class="figure" style="width:250px;"&gt;
   &lt;IMG src="250px1.jpg"&gt;
   &lt;/IMG&gt;
  &lt;/DIV&gt;
 &lt;/P&gt;
 &lt;P&gt;河野太郎・衆議院議員&lt;/P&gt;
 &lt;P&gt;
 &lt;/P&gt;
 &lt;P&gt;
  &lt;STRONG&gt;NBO&lt;/STRONG&gt;　参院選は自民党の「歴史的大敗」となりま
 &lt;/P&gt;
 &lt;!--中略--&gt;
 &lt;DIV class="blocktitle_l"&gt;
  &lt;IFRAME width="528" height="100" marginwidth="0" marginheight="0" hspace="0" vspace="0" frameborder="0" scrolling="no" bordercolor="#000000" src="http://bizad.nikkeibp.co.jp/NBP_AD/nbonline/ad/nbo_thisweek.shtml"&gt;
  &lt;/IFRAME&gt;
 &lt;/DIV&gt;
&lt;/TD&gt;</samp></pre>
<p><q cite="http://business.nikkeibp.co.jp/article/topics/20070806/131744/" title="自民大敗、本当の理由 (ニュースを斬る)：NBonline(日経ビジネス オンライン)">参院選での自民党大敗</q>～の段落が<code>div.kakomi</code>から外に出てしまっている。そのあおりで、インタビュー本文のある段落の場所も<code>td.main_part &gt; p</code>となってしまった。なので、NekoHTMLのDOMパーサで<code>div.kakomi</code>や<code>div#articlecontent</code>を取得しようと思ってもうまくいかない。前者は空白のみで、後者は<q cite="http://business.nikkeibp.co.jp/article/topics/20070806/131744/" title="自民大敗、本当の理由 (ニュースを斬る)：NBonline(日経ビジネス オンライン)">自民大敗、本当の理由</q>から<q cite="http://business.nikkeibp.co.jp/article/topics/20070806/131744/" title="自民大敗、本当の理由 (ニュースを斬る)：NBonline(日経ビジネス オンライン)">（聞き手は、日経ビジネス オンライン＝谷川 博）</q>までしか取得できない。</p>
<h3><a href="http://home.ccil.org/~cowan/XML/tagsoup/" title="TagSoup home page">TagSoup</a>の場合</h3>
<p>上と同じように、一部改行と空白を削除したところがある。</p>
<pre><samp>&lt;td colspan="1" rowspan="2" valign="top" class="main_part"&gt;
 &lt;div id="articlecontent"&gt;
  &lt;h1 class="articleheader"&gt;自民大敗、本当の理由&lt;/h1&gt;
  &lt;h2 class="articleheader"&gt;
    小泉改革路線に逆行する安倍自民を国民が拒&lt;/h2&gt;
  &lt;ul class="articledata"&gt;
   &lt;li&gt;2007年8月7日　火曜日&lt;/li&gt;
   &lt;li&gt;
    &lt;a shape="rect" href="/bns/author.jsp?ID=131744&amp;OFFSET=0"&gt;谷川　博&lt;/a&gt;
   &lt;/li&gt;
  &lt;/ul&gt;
  &lt;div class="articlekeyword_wrapper"&gt;
   &lt;div class="articlekeyword"&gt;
    &lt;a shape="rect" href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%CF%C0%C5%C0"&gt;論点&lt;/a&gt;　
    &lt;a shape="rect" href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%BB%B2%B1%A1%C1%AA"&gt;参院選&lt;/a&gt;　
    &lt;a shape="rect" href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%B0%C2%C7%DC%C0%AF%B8%A2"&gt;安倍政権&lt;/a&gt;　
    &lt;a shape="rect" href="/bns/bnsearch.jsp?BID=1006&amp;OFFSET=0&amp;SEARCH_TEXT=%BE%AE%C0%F4%B2%FE%B3%D7"&gt;小泉改革&lt;/a&gt;　
   &lt;/div&gt;
  &lt;/div&gt;
  <em>&lt;p&gt;&lt;/p&gt;
  &lt;div class="kakomi"&gt;
   &lt;p&gt;
    参院選での自民党大敗については、既に年金
   &lt;/p&gt;
  &lt;/div&gt;
  &lt;p&gt;&lt;/p&gt;</em>
  &lt;div class="figure" style="width:250px;"&gt;
   &lt;img src="250px1.jpg"&gt;&lt;/img&gt;
   &lt;p&gt;河野太郎・衆議院議員&lt;/p&gt;
  &lt;/div&gt;
  &lt;p&gt;
   &lt;strong&gt;NBO&lt;/strong&gt;　参院選は自民党の「歴史的大敗」となりま
  &lt;/p&gt;
  &lt;!--中略--&gt;
  &lt;div class="blocktitle_l"&gt;
   &lt;iframe frameborder="0" scrolling="no" width="528" height="100" marginwidth="0" marginheight="0" hspace="0" vspace="0" bordercolor="#000000" src="http://bizad.nikkeibp.co.jp/NBP_AD/nbonline/ad/nbo_thisweek.shtml"&gt;
   &lt;/iframe&gt;
  &lt;/div&gt;
 &lt;/div&gt;
&lt;/td&gt;</samp></pre>
<p>こちらは、p要素下にdiv要素が来ることを防いだ。<code>div#articlecontent</code>がちゃんと直親td要素の終了直前まで続いているので、<code class="xpath">//div[@id='articlecontent']</code>というXPATH式で本文部分全体を取得できる。</p>
<h3><a href="https://java.sun.com/j2se/1.5.0/ja/docs/ja/api/javax/swing/text/html/HTMLEditorKit.ParserCallback.html" title="HTMLEditorKit.ParserCallback (Java 2 Platform SE 5.0)">HTMLEditorKit.ParserCallback</a>の場合</h3>
<p>このパーサは想定外の要素に弱いみたいで、処理中にArrayIndexOutOfBoundsExceptionが発生した。原因は84行目をはじめ随所に現れるcomment要素で、これらを削除したところ例外を出さずに処理を終えることができ、TagSoupと似た結果になった。</p>
<p>これら結果を見る限り、HTMLの文法を最も理解しているのはHTMLEditorKit.ParserCallbackのように思える。しかし、このパーサはSAX標準のインタフェースに則っておらず、イリーガルな要素が現れると例外が出てしまうというのが痛い。HTML4.01/XHTML1.0に準じるようなバージョンアップをしてくれないかなー。TagSoupは<a href="http://www-06.ibm.com/jp/developerworks/xml/060602/j_x-tiptagsoup.shtml" title="IBM dW : XML : ヒント: ひどいHTMLをTagSoupで修正する - Japan">評判</a>どおり中々優秀だが、InputStreamの日本語を正しく理解してくれないのが難点。<a href="http://homepage.mac.com/yuji_okamura/DotMac/t/archives/2005/12/entry_75.html" title="Thingamablog メモ : tagsoup カスタム版">日本語の問題を解決したカスタム版</a>があるっぽい? でもこれは実体参照されてしまう問題を解決するためのものだから違うか。1回Stringにすれば問題ないので使えないわけではない。</p>
<h3><a href="http://sourceforge.net/projects/shanidom/" title="SourceForge.net: ShaniXmlParser">ShaniXmlParser</a>の場合</h3>
<p>ShaniXMLParserは、HTMLのエラー訂正をDOM層でやっているぽい (DocumentBuilderFactoryでDTDを読むかどうかの指定ができるが、SAXParserFactoryにはない) のでちょっと特殊 (<code class="html">&lt;img ～ &gt;</code>となっているとendElement()がコールされない。<code class="html">&lt;img ～ /&gt;</code>だとコールされる) だ。</p>
<ins class="ps" datetime="2008-06-19T14:01:38+09:00" id="PS1213851698">
<h3><a href="http://mozillaparser.sourceforge.net/" title="Mozilla Java Html Parser">Mozilla Java Html Parser</a>の場合</h3>
<p>空のp要素ノードが2つ多く生成されたことを除けば、TagSoupの出力結果と同じになった。</p>
</ins>
<p>にしてもブラウザ付属のDOMパーサは凄いなあと思う。MozillaのDOMパーサってどうなっているんだろう。</p>
		</div>
	</content>
	<category term="HTML"/>
	<category term="Java"/>
	<category term="NekoHTML"/>
	<category term="SAX"/>
	<category term="TagSoup"/>
	<category term="ひどいHTML"/>
	<category term="パーサ"/>
	<category term="ライブラリ"/>
	<trackback:ping>http://txqz.net/blog/2007/08/10/1200/tb</trackback:ping>
	<published>2007-08-10T12:00:15+09:00</published>
	<updated>2008-09-19T14:17:47+09:00</updated>
	<rights>Attribution-Noncommercial-Share Alike 3.0 Unported</rights>
</entry>