エラーを含んだXMLをルーズにパースする
各種ブログのRSSのようなWeb上のXMLリソースをdom4jやJDOMなどで読み込むと、パースに失敗するケースがとても多いです。というのも、こういうXMLは基本的に、validであることをあまり期待できないからです(エスケープ漏れがあったり、"<!--"で始まったコメントの直後に"-"が来たりする[追記: これはinvalidな例じゃなく非well-formedな例でした])。ひどいときはwell-formedですらないこともあります。
こういう問題がある場合、HTMLであれば、MayaaやS2JSFでも採用されているNekoHTMLというライブラリを使って、エラーを出さずにルーズにパースできます。このNekoHTMLを、HTMLではなくXMLに適用する方法を調べたので、メモしておきます。
パーサを以下のような構成にすると、XMLの解析に適した状態になります。
- NekoHTML側ではなくXerces側のDOMParserを使う(NekoHTMLのDOMParserを使うと要素名と属性名が強制的に大文字になってしまう)
- DOMParserで"elems"と"attrs"プロパティを"default"にする
- DOMParserで"balance-tags"機能をオフにする
- DOMParserで"filters"プロパティを空にする
コード例は以下です。
import java.io.IOException; import java.io.InputStream; import org.apache.xerces.parsers.DOMParser; import org.apache.xerces.xni.parser.XMLDocumentFilter; import org.cyberneko.html.HTMLConfiguration; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * @author Kaisei Hamamoto */ public class LooseXMLParser { public Document parse(InputStream in, String encoding) throws SAXException, IOException { HTMLConfiguration config = new HTMLConfiguration(); DOMParser parser = new DOMParser(config); parser.setProperty("http://cyberneko.org/html/properties/names/elems", "default"); parser.setProperty("http://cyberneko.org/html/properties/names/attrs", "default"); parser.setFeature("http://cyberneko.org/html/features/balance-tags", false); parser.setProperty("http://cyberneko.org/html/properties/filters", new XMLDocumentFilter[0]); InputSource source = new InputSource(in); source.setEncoding(encoding); parser.parse(source); return parser.getDocument(); } }