CyberNeko HTML Parser関係Tips

サンプルソースコード

特定URLのHTMLの内容をDOMで取り出してAuto-Discovery URLを取得するイメージで。

package sample.parser;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

import javax.xml.transform.TransformerException;

import org.cyberneko.html.parsers.DOMParser;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import com.sun.org.apache.xpath.internal.XPathAPI;

public class DOMParserSample {
    public Document parse(InputStream in) throws SAXException, IOException {
        
        DOMParser parser = new DOMParser();
        parser.setFeature("http://xml.org/sax/features/namespaces", false);
        parser.setFeature("http://cyberneko.org/html/features/scanner/notify-builtin-refs", true);
//        parser.setFeature("http://cyberneko.org/html/features/scanner/ignore-specified-charset", true);
//        parser.setProperty("http://cyberneko.org/html/properties/default-encoding", encoding);
        parser.parse(new InputSource(in));
 
        Document document = parser.getDocument();
        return document;
    }
    
    public static void main(String[] args) {
        String url = "http://d.hatena.ne.jp/terazzo/";
        
        Document document = null;
        InputStream in = null;
        DOMParserSample sample = new DOMParserSample();
        try {
            in = new URL(url).openStream();
            document = sample.parse(in);
            
            // RSS 1.0用のAuto-Discovery URLを取得する
            Node rssNode = XPathAPI.selectSingleNode(document.getDocumentElement(), 
                    "//LINK[@rel='alternate'][@type='application/rss+xml'][@title='RSS']/@href");
            if (rssNode != null) {
                System.err.println("Auto-discovered URL = " + rssNode.getNodeValue());
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (TransformerException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        
    }
}

環境

  • J2SE 5.0 (1.4でも可と思う)
  • 以下のライブラリを使用
    • xercesImpl-2.7.1.jar
    • nekohtml-0.9.5.jar

こんなときは……

  • XPathで要素が見つからない
    • 要素名を大文字にする
  • Document#getDocumentElement()やXPathAPI#selectNodeList()などでHIERARCHY_REQUEST_ERRが出る
    • parser.setFeature("http://xml.org/sax/features/namespaces", false);を付ける
  • 「nbsp」が「?」に文字化け
    • parser.setFeature("http://cyberneko.org/html/features/scanner/notify-builtin-refs", true);を付ける
    • さらにEntityReference(nodeTypeがNode.ENTITY_REFERENCE_NODE)として取得できるので内容をgetNodeName()などで取り出す
  • 「〜」が「?」に文字化け
    • HTMLがShift_JISなら以下を試してみる

parser.setFeature("http://cyberneko.org/html/features/scanner/ignore-specified-charset", true);
parser.setProperty("http://cyberneko.org/html/properties/default-encoding", "Windows-31J");