【问题标题】:Make DocumentBuilder.parse ignore DTD references使 DocumentBuilder.parse 忽略 DTD 引用
【发布时间】:2010-09-14 09:10:23
【问题描述】:

当我在这个方法中解析我的 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;
}

【问题讨论】:

  • 我相信 jt 有这个问题的最佳答案。

标签: java document dtd


【解决方案1】:

尝试在 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();
...

最终,我认为这些选项是特定于解析器实现的。 Here is some documentation for Xerces2 如果有帮助的话。

【讨论】:

  • 最后一个 (load-external-dtd) 为我解决了问题 - 谢谢。
  • 在尝试此操作时,我得到了一个 DOMException: NAMESPACE_ERR: 尝试以不正确的命名空间方式创建或更改对象。。我用dbf.setNamespaceAware(true); 解决了这个问题
  • 只是让您知道,最后一个功能设置(如 @Amarghosh 所述)非常适合 SAXParserFactory。
  • 对我来说,load-external-dtd 设置就足够了。
  • 使用上述所有功能也会使代码失败。只需使用最后两个功能(非验证)即可使我的代码正常工作。
【解决方案2】:

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

我发现简单地返回一个空的 InputSource 也一样有效?

【讨论】:

【解决方案3】:

我发现 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;
         }
      }
});

【讨论】:

    【解决方案4】:

    源 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>
    

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

    目标 XML(无 DTD)

    <MYACCSERVICE>
       <REQ_PAYLOAD>
          <ACCOUNT>1234567890</ACCOUNT>
          <BRANCH>001</BRANCH>
          <CURRENCY>USD</CURRENCY>
          <TRANS_REFERENCE>201611100000777</TRANS_REFERENCE>
       </REQ_PAYLOAD>
    </MYACCSERVICE> 
    

    【讨论】:

      【解决方案5】:

      我知道我没有 dtd,也不需要它。

      我对这种说法持怀疑态度;您的文档是否包含任何实体引用?如果是这样,您肯定需要 DTD。

      无论如何,防止这种情况发生的常用方法是使用 XML 目录为“map.dtd”定义本地路径。

      【讨论】:

        【解决方案6】:

        这是另一个遇到相同问题的用户:http://forums.sun.com/thread.jspa?threadID=284209&forumID=34

        该帖子上的用户 ddssot 说

        myDocumentBuilder.setEntityResolver(new EntityResolver() {
                  public InputSource resolveEntity(java.lang.String publicId, java.lang.String systemId)
                         throws SAXException, java.io.IOException
                  {
                    if (publicId.equals("--myDTDpublicID--"))
                      // this deactivates the open office DTD
                      return new InputSource(new ByteArrayInputStream("<?xml version='1.0' encoding='UTF-8'?>".getBytes()));
                    else return null;
                  }
        });
        

        用户进一步提到“如您所见,当解析器命中 DTD 时,会调用实体解析器。我通过其特定 ID 识别出我的 DTD,并返回一个空的 XML 文档而不是真正的 DTD,从而停止所有验证。 ..”

        希望这会有所帮助。

        【讨论】:

          【解决方案7】:

          我正在使用 sonarqube,并且 eclipse 的 sonarlint 向我展示了 不信任的 XML 应该在不解析外部数据的情况下进行解析 (squid:S2755)

          我设法解决了这个问题:

              factory = DocumentBuilderFactory.newInstance();
          
              factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
          
              // If you can't completely disable DTDs, then at least do the following:
              // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
              // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
              // JDK7+ - http://xml.org/sax/features/external-general-entities
              factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
          
              // Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
              // Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
              // JDK7+ - http://xml.org/sax/features/external-parameter-entities
              factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
          
              // Disable external DTDs as well
              factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
          
              // and these as well, per Timothy Morgan's 2014 paper: "XML Schema, DTD, and Entity Attacks"
              factory.setXIncludeAware(false);
              factory.setExpandEntityReferences(false);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-10-15
            • 2023-03-22
            • 1970-01-01
            • 2012-07-04
            • 2018-08-22
            • 2011-04-23
            相关资源
            最近更新 更多