java - 如何跳过 well-formed for java DOM 解析器

标签 java dom saxparser domparser

我知道这已被多次询问,但我有一个不同的问题来处理它。在我的例子中,应用程序接收到一个作为字符串传递的格式不正确的 dom 结构。这是一个示例:

<div class='video yt'><div class='yt_url'>http://www.youtube.com/watch?v=U_QLu_Twd0g&feature=abcde_gdata</div></div>

如您所见,内容格式不正确。现在,如果我尝试使用普通的 SAX 或 DOM 解析进行解析,它会抛出一个可以理解的异常。

org.xml.sax.SAXParseException:对实体“feature”的引用必须以“;”结尾分隔符。

根据要求,我需要阅读此文档,添加一些额外的 div 标签并将内容作为字符串发回。这通过使用 DOM 解析器非常有效,因为我可以读取输入结构并在所需位置添加额外的标签。

我尝试使用像 JTidy 这样的工具进行预处理,然后进行解析,但这会导致将文档转换为完全成熟的 html,这是我不想要的。这是示例代码:


StringWriter writer = new StringWriter();
Tidy tidy = new Tidy(); // obtain a new Tidy instance
tidy.setXHTML(true);
tidy.parse(new ByteArrayInputStream(content.getBytes()), writer);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(new ByteArrayInputStream(writer.toString().getBytes()));
// Traverse thru the content and add new tags
....
Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
transformer.transform(source, result);

这会将输入完全转换为格式良好的 html 文档。然后很难手动删除 html 标签。我尝试的另一个选择是使用 SAX2DOM,它也创建了一个 HTML 文档。这是示例代码。


ByteArrayInputStream is = new ByteArrayInputStream(content.getBytes());     
Parser p = new Parser();
p.setFeature(IContentExtractionConstant.SAX_NAMESPACE,true);
SAX2DOM sax2dom = new SAX2DOM();
p.setContentHandler(sax2dom);
p.parse(new InputSource(is));
Document doc = (Document)sax2dom.getDOM();

如果有人可以分享他们的想法,我将不胜感激。

谢谢

最佳答案

最简单的方法是用相应的 xml 实体替换 xml 保留字符。您可以手动执行此操作:

content.replaceAll("&", "&amp;");

如果您不想在解析之前修改您的字符串,我可以向您推荐另一种使用 SaxParser 的方法,但这种解决方案更加复杂。基本上你必须:

  1. 写一个LexicalHandler在 结合 ContentHandler
  2. 告诉解析器继续它的 fatal error 后执行( ErrorHandler 是不够的)
  3. 将未声明的实体视为简单实体 正文

更新
根据您的评论,我将添加有关第二种解决方案的一些细节。我写了一个扩展 DefaulHandler 的类(EntityResolverDTDHandlerContentHandler 的默认实现ErrorHandler) 并实现 LexicalHandler。我扩展了 ErrorHandlerfatalError 方法(我的实现除了抛出异常外什么都不做)和 ContentHandlercharacters 方法与 LexicalHandlerstartEntity 方法结合使用。

public class MyHandler extends DefaultHandler implements LexicalHandler {

    private String currentEntity = null;

    @Override
    public void fatalError(SAXParseException e) throws SAXException {
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        String content = new String(ch, start, length);
        if (currentEntity != null) {
            content = "&" + currentEntity + content;
            currentEntity = null;
        }
        System.out.print(content);
    }

    @Override
    public void startEntity(String name) throws SAXException {
        currentEntity = name;
    }

    @Override
    public void endEntity(String name) throws SAXException {
    }

    @Override
    public void startDTD(String name, String publicId, String systemId)
            throws SAXException {
    }

    @Override
    public void endDTD() throws SAXException {
    }

    @Override
    public void startCDATA() throws SAXException {
    }

    @Override
    public void endCDATA() throws SAXException {
    }

    @Override
    public void comment(char[] ch, int start, int length) throws SAXException {
    }
}

这是我的 main,它解析格式不正确的 xml。 setFeature 非常重要,因为如果没有它,解析器将抛出 SaxParseException,尽管 ErrorHandler 是空实现。

public static void main(String[] args) throws ParserConfigurationException,
        SAXException, IOException {
    String xml = "<div class='video yt'><div class='yt_url'>http://www.youtube.com/watch?v=U_QLu_Twd0g&feature=abcde_gdata</div></div>";
    SAXParser saxParser = SAXParserFactory.newInstance().newSAXParser();
    XMLReader xmlReader = saxParser.getXMLReader();
    MyHandler myHandler = new MyHandler();
    xmlReader.setContentHandler(myHandler);
    xmlReader.setErrorHandler(myHandler);
    xmlReader.setProperty("http://xml.org/sax/properties/lexical-handler",
            myHandler);
    xmlReader.setFeature(
            "http://apache.org/xml/features/continue-after-fatal-error",
            true);
    xmlReader.parse(new InputSource(new StringReader(xml)));
}

这个主要打印出包含错误的 div 元素的内容:

http://www.youtube.com/watch?v=U_QLu_Twd0g&feature=abcde_gdata

请记住,这是一个适用于您的输入的示例,也许您必须完成它...例如,如果您正确转义了一些字符,您应该添加一些代码行来处理这种情况等。

希望这对您有所帮助。

关于java - 如何跳过 well-formed for java DOM 解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5618262/

相关文章:

java - Eclemma 总是报告 0% 的代码覆盖率

javascript - document.createElement() 被忽略

android - 如何保存和更新xml文件中的值?

java - 如何将当前时间存储到外部存储器?

java - 如何在 java SWT 中显示 PNG 图像?

javascript - 查找动态加载的 HTML 页面的标题

php - Laravel - 将 HTML Dom-Parser 响应保存到数据库

java - 使用 SAX XML 解析器的问题

java - org.xml.sax.SAXParseException : Invalid byte 2 of 3-byte UTF-8 sequence

java - 包含外部项目的 NoClassDefFoundError - JBoss 7.1