<?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>OperaのXMLパーサってすごかったのね</title>
	<id>tag:txqz.net,2007-07-07:blog/2007/07/07/2106</id>
	<link rel="self" href="http://txqz.net/blog/2007/07/07/2106.atom"/>
	<link rel="alternate" type="application/rss+xml" href="http://txqz.net/blog/2007/07/07/2106.rdf"/>
	<link rel="alternate" type="application/xhtml+xml" href="http://txqz.net/blog/2007/07/07/2106.xhtml"/>
	<link rel="alternate" type="text/html" href="http://txqz.net/blog/2007/07/07/2106.html"/>
	<link rel="contents" href="http://txqz.net/blog/2007/07/07/.atom" title="2007年7月7日"/>
	<link rel="first" href="http://txqz.net/blog/2001/08/04/0001.atom" title="地球空冷化"/>
	<link rel="prev" href="http://txqz.net/blog/2007/07/06/0038.atom" title="参院選の予測市場を作りました"/>
	<link rel="next" href="http://txqz.net/blog/2007/07/07/2244.atom" title="QZ99買った"/>
	<link rel="last" href="http://txqz.net/blog/2010/02/14/1221.atom" title="VIASO/K-power追悼"/>
	<author>
		<name>陽坂智佐</name>
		<email>spambasket@txqz.net</email>
	</author>
	<content type="xhtml">
		<div xmlns="http://www.w3.org/1999/xhtml">
<p>OperaにXMLファイルを読ませるとベタテキストが出てくる。フィードだと「新規購読」というダイアログが出るけれども、画面に表示されるのは容赦ないベタテキストだ。IEやFirefoxにスタイル情報のないXMLを渡せばドキュメントツリーを表示してくれるのと対照的で、どうもOperaはXMLにやる気がないのかと勝手に思っていた。</p>
<p>だが、整形式でないXMLを投げた場合、Operaのエラー表示が圧倒的に見やすいことに最近気づいた。たとえば、以下のようなXMLをブラウザに表示させてみる:</p>
<pre><code class="xml">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;root&gt;
    &lt;hoge&gt;あああ&lt;/hoge&gt;
    &lt;hoge&gt;いいい
    &lt;hoge&gt;ううう&lt;/hoge&gt;
&lt;/root&gt;</code></pre>
<p>Firefoxだと:</p>
<div><img src="/figure/2007/07/07/firefox" alt="" /></div>
<pre><samp>XML パースエラー: タグの対応が間違っています。終了タグが必要です: &lt;/hoge&gt;
URL: file:///D:/test.xml
行番号: 6, 列番号: 3:

&lt;/root&gt;
--^</samp></pre>
<p>IEだと:</p>
<div><img src="/figure/2007/07/07/ie" alt="" /></div>
<pre><samp>XML ページを表示できません 
XSL スタイル シートを使用した XML 入力は表示できません。エラーを訂正してください。 [更新] ボタンをクリックするか、または後でやり直してください。 


--------------------------------------------------------------------------------

終了タグ 'root' が開始タグ 'hoge' と一致していません。リソース 'file:///D:/test.xml' の実行エラーです。ライン 6、位置 3

&lt;/root&gt;
--^</samp></pre>
<p>どちらも、6行目に問題があると言ってくる。だが、では<code class="xml">&lt;/hoge&gt;</code>を追加しようとしても、いったい何行目のhoge要素が閉じられていないのか分からないのだ。でもOperaは違う。</p>
<div><img src="/figure/2007/07/07/opera" alt="" /></div>
<pre><samp>エラー!
XML の解析に失敗しました

XML の解析に失敗しました: 構文エラー (行: 6, 文字: 0)

HTML ドキュメントとして再解析する
エラーmismatched end-tag
仕様http://www.w3.org/TR/REC-xml/
  1: &lt;?xml version="1.0" encoding="UTF-8"?&gt;
  2: &lt;root&gt;
  3:     &lt;hoge&gt;あああ&lt;/hoge&gt;
  4:     <em>&lt;hoge&gt;</em>いいい
  5:     &lt;hoge&gt;ううう&lt;/hoge&gt;
  6: <em>&lt;/root&gt;</em></samp></pre>
<p>と、何行目のhoge要素のせいで6行目のエラーが発生したのかを強調表示で教えてくれる。これは6行しかないから目視で分かるけど、インデントなしで千何行もあったら人間の仕事じゃなくなるわけで、Operaのこの挙動は大変ありがたい。</p>
<p>Xercesも</p>
<pre><samp>[Fatal Error] :6:3: The element type "hoge" must be terminated by the matching end-tag "&lt;/hoge&gt;".</samp></pre>
<p>にとどまる。何行目のせいで整形式になっていないのかをちゃんと教えてくれるパーサってOperaくらいなのかなー。</p>
<p>ちなみに、不正なXMLにも対応しているパーサでこういうXMLを読ませると、以下のようになる。</p>
<p><a href="http://people.apache.org/~andyc/neko/doc/html/" title="NekoHTML">CyberNeko HTML Parser</a>の場合は (以下mainメソッドが例外をスローしてたりXMLをStringから読んでいたりしてやる気のないソースなので注意):</p>
<pre><code class="java">package net.txqz.test.xml;

import java.io.IOException;
import java.io.StringReader;

import org.cyberneko.html.parsers.DOMParser;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class NekoTest {
    public static void main(String[] args) throws SAXException, IOException {
        String xml = "&lt;?xml version='1.0' encoding='utf-8'?&gt;\n&lt;root&gt;\n&lt;hoge&gt;あああ&lt;/hoge&gt;\n&lt;hoge&gt;いいい\n&lt;hoge&gt;ううう&lt;/hoge&gt;\n&lt;/root&gt;";
        DOMParser parser = new DOMParser();
        parser.parse(new InputSource(new StringReader(xml)));
        Document document = parser.getDocument();
        NodeList nodes = document.getElementsByTagName("hoge");
        for(int i = 0; i &lt; nodes.getLength(); i++){
            Node node = nodes.item(i);
            System.out.println(node.getNodeName()+":"+node.getTextContent());
        }
    }
}</code></pre>
<p>出力結果は:</p>
<pre><samp>HOGE:あああ
HOGE:いいい
ううう

HOGE:ううう
</samp></pre>
<p><a href="http://sourceforge.net/projects/shanidom/" title="SourceForge.net: ShaniXmlParser">ShaniXmlParser</a>の場合は:</p>
<pre><code class="java">package net.txqz.test.xml;

import java.io.IOException;
import java.io.StringReader;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class ShaniTest {
    public static void main(String[] args) throws SAXException, IOException, ParserConfigurationException{
        String xml = "&lt;?xml version='1.0' encoding='utf-8'?&gt;\n&lt;root&gt;\n&lt;hoge&gt;あああ&lt;/hoge&gt;\n&lt;hoge&gt;いいい\n&lt;hoge&gt;ううう&lt;/hoge&gt;\n&lt;/root&gt;";
        System.setProperty("javax.xml.parsers.DocumentBuilderFactory","org.allcolor.xml.parser.CDocumentBuilderFactory");
        System.setProperty("javax.xml.parsers.SAXParserFactory","org.allcolor.xml.parser.CSaxParserFactory");
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();

        Document document = builder.parse(new InputSource(new StringReader(xml)));
        NodeList nodes = document.getElementsByTagName("hoge");
        for(int i = 0; i &lt; nodes.getLength(); i++){
            Node node = nodes.item(i);
            System.out.println(node.getNodeName()+":"+node.getTextContent());
        }
    }
}</code></pre>
<p>出力結果は:</p>
<pre><samp>hoge:あああ
hoge:いいい
ううう
hoge:ううう
</samp></pre>
<p><a href="http://jerichohtml.sourceforge.net/doc/index.html" title="Jericho HTML Parser">Jericho HTML Parser</a>の場合は:</p>
<pre><code class="java">package net.txqz.test.xml;

import java.io.IOException;
import java.io.StringReader;
import java.util.List;

import au.id.jericho.lib.html.Element;
import au.id.jericho.lib.html.Source;

public class JerichoTest {
    public static void main(String[] args) throws IOException {
        String xml = "&lt;?xml version='1.0' encoding='utf-8'?&gt;\n&lt;root&gt;\n&lt;hoge&gt;あああ&lt;/hoge&gt;\n&lt;hoge&gt;いいい\n&lt;hoge&gt;ううう&lt;/hoge&gt;\n&lt;/root&gt;";
        Source src = new Source(new StringReader(xml));
        List&lt;Element&gt; list = src.findAllElements("hoge");
        for(Element element : list){
            System.out.println(element.getName()+":"+element.extractText());
        }
    }
}</code></pre>
<p>出力結果は:</p>
<pre><samp>hoge:あああ
hoge:
hoge:ううう
</samp></pre>
<p>Jericho HTML Parserは w3c DOMを使わずに独自の形式でHTMLやXMLをパースするのだけれども、不正なXMLもパースできるのがウリなのにこの方法で「いいい」を抽出できなかった。やりかたが悪い? いやまぁ整形式でないのが一番悪いのですが。ほかのパーサも「いいい」だけ抽出するのは不可能で、「いいい」と「ううう」がセットになる。それは、パーサがこの適当なXMLのDTDを知らないから当然の処理。HTMLで<code class="html">&lt;ul&gt;&lt;li&gt;あああ&lt;li&gt;いいい&lt;li&gt;ううう&lt;/ul&gt;</code>とかなっている場合は、HTMLパーサと名乗っている以上li要素の暗黙の終了タグをちゃんと補完してくれることでしょう。</p>
<p>あと、いま知ったのだけれども、XML宣言ってversionを必ず最初に指定しないといけないのね。encodingを先に指定したら<samp>[Fatal Error] :1:23: The version is required in the XML declaration.</samp>とXercesに怒られた。Xerces厳しすぎワロタと思ったら<cite><a href="http://www.w3.org/TR/REC-xml/" title="Extensible Markup Language (XML) 1.0 (Fourth Edition)">仕様</a></cite>に<q cite="http://www.w3.org/TR/REC-xml/" title="Extensible Markup Language (XML) 1.0 (Fourth Edition)">[23] XMLDecl ::= '&lt;?xml' VersionInfo EncodingDecl? SDDecl? S? '?&gt;'</q>って書いてあった。ふつうXMLの属性は登場順序に意味がないので、宣言もそうだと思い込んでいた。いまさらー。</p>
<ins class="ps" datetime="2007-07-13T16:58:36+09:00" id="PS20070713165836">
<blockquote title="livedoor クリップ - OperaのXMLパーサってすごかったのね" cite="http://clip.livedoor.com/page/http://txqz.net/blog/2007/07/07/2106">
<p>XMLはツリー表示されることを規定しないのでOperaはCSS初期値で表示してる(cf. <a href="http://kuruman.org/old_diary/200608#D19-01">http://kuruman.org/old_diary/200608#D19-01</a> )。パースエラーの開始箇所候補を挙げてくれるのはありがたいよね。</p>
</blockquote>
<p>なるほど。やっぱりはOperaすばらしいですね。</p>
</ins>
		</div>
	</content>
	<category term="Firefox"/>
	<category term="IE"/>
	<category term="Java"/>
	<category term="JerichoHTMLParser"/>
	<category term="NekoHTML"/>
	<category term="Opera"/>
	<category term="ShaniXMLParser"/>
	<category term="UA"/>
	<category term="XML"/>
	<category term="パーサ"/>
	<category term="ライブラリ"/>
	<trackback:ping>http://txqz.net/blog/2007/07/07/2106/tb</trackback:ping>
	<published>2007-07-07T21:06:00+09:00</published>
	<updated>2007-08-09T19:34:19+09:00</updated>
	<rights>Attribution-Noncommercial-Share Alike 3.0 Unported</rights>
</entry>