解析 XML 时忽略 DTD

2022-09-04 22:00:57

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

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

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

下面是一个代码片段:

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行后,我可以成功解析它,但这在最终生产系统中不是一个选项。


答案 1

首选解决方案是实现一个实体解析器,该解析器拦截对 DTD 的请求,并将这些请求重定向到嵌入式副本。如果您

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

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

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);

答案 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(...);

推荐