Xerces DOM解析器速度极慢?

3

目前,我正在尝试使用JTidy清理一个HTML文件,将其转换为XHTML并将结果提供给DOM解析器。以下代码是这些努力的结果:

public class HeaderBasedNewsProvider implements INewsProvider {

    /* ... */

    public Collection<INewsEntry> getNewsEntries() throws NewsUnavailableException {
            Document document;
        try {
            document = getCleanedDocument();
        } catch (Exception e) {
            throw new NewsUnavailableException(e);
        }
        System.err.println(document.getDocumentElement().getTextContent());
        return null;
    }

    private final Document getCleanedDocument() throws IOException, SAXException, ParserConfigurationException {
        InputStream input = inputStreamProvider.getInputStream();
        Tidy tidy = new Tidy();
        tidy.setXHTML(true);
        ByteArrayOutputStream tidyOutputStream = new ByteArrayOutputStream();
        tidy.parse(input, tidyOutputStream);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setValidating(false);
        InputStream domInputStream = new ByteArrayInputStream(tidyOutputStream.toByteArray());
        System.err.println(factory.getClass());
        return factory.newDocumentBuilder().parse(domInputStream);
    }
}

然而,我系统上的DOM解析器实现(com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl)看起来非常缓慢。即使对于像以下这样的单行文档,解析也需要2-3分钟:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html><head><title></title></head><body><div class="text"><h2>Nachricht vom 16. Juni 2011</h2><h1>Titel</h1><p>Mitteilung <a href="dokumente/medienmitteilungen/MM_NR_jglp.pdf" target="_blank">weiter</a> mehr Mitteilung</p></div></body></html>

请注意,与DOM解析器相比,JTidy的工作时间只需一秒钟。因此,我怀疑我可能在错误地使用DOM API。
提前感谢您对此问题的任何建议!

非常奇怪。在这样一个小的文档上不应该如此缓慢。而且既然你明确将验证设置为false,我不希望它从DTD中解析出任何东西。你能通过分析器运行它来找出哪些调用需要最长时间吗? - G_H
2个回答

7
即使不进行验证,XML解析器也需要获取DTD,例如支持命名字符实体。您应该考虑实现一个EntityResolver,将对DTD的请求解析为本地副本。

1
这是问题...我已经通过分析器运行了代码,发现98.9%的执行时间(共120秒)都花费在java.net.SocketInputStream.read上。这又源自于一个由JRE内部Xerces解析器中的XMLDTDScannerImpl创建的HttpURLConnection。即使禁用了标准DTD验证,它仍然需要那些实体声明。我从未使用过DTD(总是使用本地可用的模式)。+1 - G_H
1
你的建议是正确的,我在我的示例中进行了验证。为了方便起见,Xerces 允许使用功能设置禁用 DTD 获取: factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); 感谢您的快速帮助! - Pascal Kesseli
请参阅 http://xerces.apache.org/xerces2-j/features.html 以获取其他可用功能。 - PypeBros

2

HTML的DTD非常庞大,使用包含(includes)会花费很长时间。可以使用XML目录。在其中,可以将DTD存储在本地,并通过它们的系统ID进行映射。

如果您使用工具,例如Maven,则会找到足够的指针。

截取实体的优点是,如所接受的答案所建议的那样,您将收到正确的字符。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接