【问题标题】:Ignoring DTD when parsing XML解析 XML 时忽略 DTD
【发布时间】:2023-03-22 04:37:01
【问题描述】:

如何在使用 XOM xml 库解析文件时忽略 DTD 声明。我的文件有以下行:

<?xml version="1.0"?>
<!DOCTYPE BlastOutput PUBLIC "-//NCBI//NCBI BlastOutput/EN" "NCBI_BlastOutput.dtd">
//rest of stuff here 

当我尝试 build() 我的文档时,我得到 DTD 文件的 filenotfound 异常。我知道我没有这个文件,我也不关心它,那么在使用 XOM 时如何删除它呢?

这是一个代码sn-p:

public BlastXMLParser(String filePath) {
    Builder b = new Builder(false);
     //not a good idea to have exception-throwing code in constructor
    try {

        _document = b.build(filePath);
    } catch (ParsingException ex) {
        Logger.getLogger(BlastXMLParser.class.getName()).log(Level.SEVERE,"err", ex);
    } catch (IOException ex) {
        //
    }

private Elements getBlastReads() {
    Element root = _document.getRootElement();
    Elements rootChildren = root.getChildElements();

    for (int i = 0; i < rootChildren.size(); i++) {
        Element child = rootChildren.get(i);
        if (child.getLocalName().equals("BlastOutput_iterations")) {

            return child.getChildElements();
        }
    }

    return null;
}
}

我在这一行得到一个 NullPointerException:

Element root = _document.getRootElement();

从源 XML 文件中删除 DTD 行后,我可以成功解析它,但这不是最终生产系统中的选项。

【问题讨论】:

  • 你能显示用于解析的code吗?

标签: java xml xom


【解决方案1】:

首选的解决方案是实现EntityResolver,它拦截对 DTD 的请求并将这些请求重定向到嵌入的副本。如果你

  1. 无权访问 DTD 和
  2. 绝对确定您不需要它(除了验证之外,它还可能声明文档中使用的字符实体)并且
  3. 您正在使用 Xerces XML Parser 实现

您可以通过设置相应的 SAX 功能来禁用 DTD 提取。在 XOM 中,这应该可以通过将 XMLReader 传递给 Builder 构造函数来实现,如下所示:

import org.xml.sax.XMLReader;
import org.xml.sax.helpers.XMLReaderFactory;

...

XMLReader xmlreader = XMLReaderFactory.createXMLReader();
xmlreader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
Builder builder = new Builder(xmlreader);

【讨论】:

  • 这行得通,否则我的 xmlreader 在看到 DOCTYPE 声明后会永远挂起
【解决方案2】:

如果不使用 XOM 而只是使用 JAXP,则只需将上述解决方案调整为

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(...);

【讨论】:

    【解决方案3】:

    根据他们的文档,这是无需任何验证即可解析文档的方式。

    try {
      Builder parser = new Builder();
      Document doc = parser.build("http://www.cafeconleche.org/");
    }
    catch (ParsingException ex) {
      System.err.println("Cafe con Leche is malformed today. How embarrassing!");
    }
    catch (IOException ex) {
      System.err.println("Could not connect to Cafe con Leche. The site may be down.");
    }
    

    如果您确实想验证 XML 架构,您必须调用 new Builder(true):

    try {
      Builder parser = new Builder(true);
      Document doc = parser.build("http://www.cafeconleche.org/");
    }
    catch (ValidityException ex) {
      System.err.println("Cafe con Leche is invalid today. (Somewhat embarrassing.)");
    }
    catch (ParsingException ex) {
      System.err.println("Cafe con Leche is malformed today. (How embarrassing!)");
    }
    catch (IOException ex) {
      System.err.println("Could not connect to Cafe con Leche. The site may be down.");
    }
    

    注意现在可以抛出另一个异常:ValidityException

    【讨论】:

    • 请查看我的代码 sn-p。即使按照文档中所写的内容,我也无法使其正常工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    • 2016-04-23
    • 1970-01-01
    • 2016-02-04
    • 2019-06-09
    • 2012-10-15
    • 2014-09-28
    相关资源
    最近更新 更多