首页 > 解决方案 > 尝试在 Java 中实现 HTML 文件比较,但在 saxon 开始元素中出现 NULL 指针异常

问题描述

我正在尝试实现 java 程序来比较两个 HTML 文件。我在互联网上浏览了很多资源,但对我来说一切都止于一处。那就是我低于异常

Exception in thread "main" java.lang.NullPointerException
at net.sf.saxon.event.ReceivingContentHandler.startElement(ReceivingContentHandler.java:279)
at org.outerj.daisy.diff.html.HtmlSaxDiffOutput.generateOutput(Unknown Source)
at org.outerj.daisy.diff.html.HTMLDiffer.diff(Unknown Source)
at com.interac.api.emt.noti.DaizyDiff.main(DaizyDiff.java:63)

我的完整代码:

public class DaizyDiff {

    static String html1 = "<html class='foobar'>Hello</html>";
    static String html2 = "<html>Bye</html>";

    public static void main(String args[]) throws TransformerConfigurationException, IOException, SAXException {

        final StringWriter finalResult = new StringWriter();
        final SAXTransformerFactory tf = (SAXTransformerFactory) TransformerFactory.newInstance();

        final TransformerHandler result = tf.newTransformerHandler();
        result.getTransformer().setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        result.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes");
        result.getTransformer().setOutputProperty(OutputKeys.METHOD, "html");
        result.getTransformer().setOutputProperty(OutputKeys.ENCODING, "UTF-8");
        result.setResult(new StreamResult(finalResult));

        final ContentHandler postProcess = result;

        final Locale locale = Locale.getDefault();
        final String prefix = "diff";

        final NekoHtmlParser cleaner = new NekoHtmlParser();

        final InputSource oldSource = new InputSource(new StringReader(html1));
        final InputSource newSource = new InputSource(new StringReader(html2));

        final DomTreeBuilder oldHandler = new DomTreeBuilder();
        cleaner.parse(oldSource, oldHandler);
        final TextNodeComparator leftComparator = new TextNodeComparator(oldHandler, locale);

        final DomTreeBuilder newHandler = new DomTreeBuilder();
        cleaner.parse(newSource, newHandler);
        final TextNodeComparator rightComparator = new TextNodeComparator(newHandler, locale);

        final HtmlSaxDiffOutput output = new HtmlSaxDiffOutput(postProcess, prefix);

        final HTMLDiffer differ = new HTMLDiffer(output);
        differ.diff(leftComparator, rightComparator);

        System.out.println(finalResult.toString());

        System.out.println(finalResult.toString());
    }

标签: javasaxon

解决方案


您使用的是哪个撒克逊版本?在当前版本 (9.9) 中,该方法ReceivingContentHandler.startElement()与第 279 行相去甚远,这表明您使用的是相当旧的版本。

然而,很有可能 DaisyDiff 并没有ContentHandler以它期望的方式调用 Saxon's。不幸的是,XML 解析器对 a 的调用顺序ContentHandler取决于 XML 解析器的配置方式,而典型的ContentHandler实现(如 Saxon 的)需要ContentHandler以特定方式配置 XML 解析器(或其他事件发送方)。

这样做的原因是,ContentHandler典型的 Saxon 用例是一个对性能非常关键的接口,并且该startElement()方法在每次调用时对提供的参数进行全面验证将是一个巨大的开销;它必须信任调用者。

除非您准备好深入研究 DaisyDiff 和 Saxon 源代码以找出不匹配的原因(并且可能编写一个过滤器来坐在它们之间并解决不匹配问题),否则您最好将 DaisyDiff 输出输入到词法 XML 中,并重新解析 XML 以将其发送给 Saxon。

进一步看,您实际上TransformerHandler只是将其用作 XML 序列化程序。DaisyDiff(查看 GitHub 上的源代码)正在对其写入的 TransformerHandler/ContentHandler 做出各种假设(例如,它似乎没有对startDocument()or进行任何调用endDocument())。我的猜测是,它可能只TransformerHandler在 JDK 附带的实现上进行了测试,它可能很好地与TransformerHandler. TransformerFactory.newInstance()我认为您在这里没有做任何真正需要 Saxon 的事情,我认为您只是因为它恰好在类路径上而选择它,而您最好的前进方式可能是确保您的电话接听JDK 变压器工厂而不是撒克逊。所以使用的版本newInstance()它需要一个工厂类名称作为它的第一个参数,提供"com.sun.org.apache.xalan.internal.processor.TransformerFactoryImpl".


推荐阅读