使DocumentBuilder.parse忽略DTD引用

joe*_*joe 77 java dtd document

当我在这个方法中解析我的xml文件(变量f)时,我收到一个错误

C:\ Documents and Settings\joe\Desktop\aicpcudev\OnlineModule\map.dtd(系统找不到指定的路径)

我知道我没有dtd,也不需要它.如何在忽略DTD引用错误的同时将此File对象解析为Document对象?

private static Document getDoc(File f, String docId) throws Exception{
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    Document doc = db.parse(f);


    return doc;
}
Run Code Online (Sandbox Code Playgroud)

jt.*_*jt. 128

尝试在DocumentBuilderFactory上设置功能:

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

dbf.setValidating(false);
dbf.setNamespaceAware(true);
dbf.setFeature("http://xml.org/sax/features/namespaces", false);
dbf.setFeature("http://xml.org/sax/features/validation", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

DocumentBuilder db = dbf.newDocumentBuilder();
...
Run Code Online (Sandbox Code Playgroud)

最后,我认为这些选项特定于解析器实现.以下是Xerces2的一些文档,如果有帮助的话.

  • 最后一个(`load-external-dtd`)为我做了诀窍 - 谢谢. (20认同)
  • 对我来说,`load-external-dtd` 设置就足够了。 (2认同)

too*_*kit 57

@anjanb建议的方法类似

    builder.setEntityResolver(new EntityResolver() {
        @Override
        public InputSource resolveEntity(String publicId, String systemId)
                throws SAXException, IOException {
            if (systemId.contains("foo.dtd")) {
                return new InputSource(new StringReader(""));
            } else {
                return null;
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

我发现只返回一个空的InputSource也能正常工作?

  • 设置DocumentBuilderFactory上的功能对我有用.这篇文章的解决方案不起作用. (4认同)
  • 这对我来说也很完美,尽管我认为我没有使用SAX (4认同)

小智 5

我发现一个问题,其中DTD文件与XML一起位于jar文件中。我根据此处的示例解决了该问题,如下所示:-

DocumentBuilder db = dbf.newDocumentBuilder();
db.setEntityResolver(new EntityResolver() {
    public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
        if (systemId.contains("doc.dtd")) {
             InputStream dtdStream = MyClass.class
                     .getResourceAsStream("/my/package/doc.dtd");
             return new InputSource(dtdStream);
         } else {
             return null;
         }
      }
});
Run Code Online (Sandbox Code Playgroud)


Sho*_*han 5

源 XML(带 DTD)

<!DOCTYPE MYSERVICE SYSTEM "./MYSERVICE.DTD">
<MYACCSERVICE>
   <REQ_PAYLOAD>
      <ACCOUNT>1234567890</ACCOUNT>
      <BRANCH>001</BRANCH>
      <CURRENCY>USD</CURRENCY>
      <TRANS_REFERENCE>201611100000777</TRANS_REFERENCE>
   </REQ_PAYLOAD>
</MYACCSERVICE>
Run Code Online (Sandbox Code Playgroud)

Java DOM 实现,用于接受上述 XML 作为字符串并删除 DTD 声明

public Document removeDTDFromXML(String payload) throws Exception {

    System.out.println("### Payload received in XMlDTDRemover: " + payload);

    Document doc = null;
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {

        dbf.setValidating(false);
        dbf.setNamespaceAware(true);
        dbf.setFeature("http://xml.org/sax/features/namespaces", false);
        dbf.setFeature("http://xml.org/sax/features/validation", false);
        dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false);
        dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

        DocumentBuilder db = dbf.newDocumentBuilder();

        InputSource is = new InputSource();
        is.setCharacterStream(new StringReader(payload));
        doc = db.parse(is); 

    } catch (ParserConfigurationException e) {
        System.out.println("Parse Error: " + e.getMessage());
        return null;
    } catch (SAXException e) {
        System.out.println("SAX Error: " + e.getMessage());
        return null;
    } catch (IOException e) {
        System.out.println("IO Error: " + e.getMessage());
        return null;
    }
    return doc;

}
Run Code Online (Sandbox Code Playgroud)

目标 XML(无 DTD)

<MYACCSERVICE>
   <REQ_PAYLOAD>
      <ACCOUNT>1234567890</ACCOUNT>
      <BRANCH>001</BRANCH>
      <CURRENCY>USD</CURRENCY>
      <TRANS_REFERENCE>201611100000777</TRANS_REFERENCE>
   </REQ_PAYLOAD>
</MYACCSERVICE> 
Run Code Online (Sandbox Code Playgroud)