Đặt DocumentBuilder.parse bỏ qua các tham chiếu DTD


81

Khi tôi phân tích cú pháp tệp xml (biến f) trong phương pháp này, tôi gặp lỗi

C: \ Documents and Settings \ joe \ Desktop \ aicpcudev \ OnlineModule \ map.dtd (Hệ thống không thể tìm thấy đường dẫn được chỉ định)

Tôi biết tôi không có dtd, và tôi cũng không cần nó. Làm cách nào để phân tích cú pháp đối tượng Tệp này thành đối tượng Tài liệu trong khi bỏ qua lỗi tham chiếu DTD?

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

1
Tôi tin rằng jt có câu trả lời tốt nhất cho câu hỏi này.
simgineer 14/1217

Câu trả lời:


58

Cách tiếp cận tương tự với cách được @anjanb đề xuất

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

Tôi thấy rằng chỉ cần trả lại một InputSource trống cũng hoạt động tốt?


4
Thiết lập các tính năng trên DocumentBuilderFactory phù hợp với tôi. Giải pháp trong bài đăng này đã không hoạt động.
Kai Mechel

4
Điều này cũng làm việc một cách hoàn hảo đối với tôi, mặc dù tôi nghĩ rằng tôi đã không sử dụng SAX
devnull69

Đáng buồn thay, điều này không hiệu quả với tôi. Tôi vẫn có lỗi. @jt đã làm điều đó cho tôi.
Nils-o-mat,

Cảm ơn vì giải pháp, tôi nghĩ đây là cách tiếp cận được đề xuất bởi org.xml . Có vẻ như có rất nhiều tài liệu về chủ đề này. xem xerces.apache.org/xml-commons/components/resolver/… hoặc en.wikipedia.org/wiki/XML_Catalog và javadoc saxproject.org/apidoc/org/xml/sax/EntityResolver.htmlsaxproject.org/ apidoc / org / xml / sax / ext / EntityResolver2.html
aliopi

135

Thử cài đặt các tính năng trên 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();
...

Cuối cùng, tôi nghĩ rằng các tùy chọn dành riêng cho việc triển khai trình phân tích cú pháp. Đây là một số tài liệu cho Xerces2 nếu điều đó hữu ích.


21
người cuối cùng ( load-external-dtd) đã thực hiện thủ thuật cho tôi - cảm ơn.
Amarghosh

1
Trong khi thử điều này, tôi nhận được DOMException: NAMESPACE_ERR: Cố gắng tạo hoặc thay đổi một đối tượng theo cách không chính xác đối với không gian tên. . Tôi cố định này vớidbf.setNamespaceAware(true);
Tim Van Laer

Xin thông báo cho bạn biết, cài đặt tính năng cuối cùng (như @Amarghosh đã nêu) hoạt động hiệu quả với SAXParserFactory.
Alexis Leclerc,

1
Đối với tôi, load-external-dtdthiết lập là đủ.
chris

Sử dụng tất cả các tính năng trên cũng làm cho mã bị lỗi. Chỉ cần sử dụng hai tính năng cuối cùng (không xác thực) làm cho mã của tôi hoạt động.
Purus

5

Tôi đã tìm thấy sự cố trong đó tệp DTD nằm trong tệp jar cùng với XML. Tôi đã giải quyết vấn đề dựa trên các ví dụ ở đây, như sau: -

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

Nguồn XML (Với 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>

Triển khai Java DOM để chấp nhận XML ở trên dưới dạng Chuỗi và loại bỏ khai báo 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 đích (Không có DTD)

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

2

Tôi biết tôi không có dtd, và tôi cũng không cần nó.

Tôi nghi ngờ về tuyên bố này; tài liệu của bạn có chứa bất kỳ tham chiếu thực thể nào không? Nếu vậy, bạn chắc chắn cần DTD.

Dù sao, cách thông thường để ngăn điều này xảy ra là sử dụng một danh mục XML để xác định một đường dẫn cục bộ cho "map.dtd".


2

đây là một người dùng khác gặp sự cố tương tự: http://forums.sun.com/thread.jspa?threadID=284209&forumID=34

người dùng ddssot trên bài đăng đó nói

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

Người dùng đề cập thêm "Như bạn có thể thấy, khi trình phân tích cú pháp truy cập vào DTD, trình phân giải thực thể được gọi. Tôi nhận ra DTD của mình bằng ID cụ thể của nó và trả về một tài liệu XML trống thay vì DTD thực, dừng tất cả xác thực ..."

Hi vọng điêu nay co ich.


0

Tôi đang làm việc với sonarqube và sonarlint cho nhật thực đã cho tôi thấy XML không đáng tin cậy sẽ được phân tích cú pháp mà không cần giải quyết dữ liệu bên ngoài (ink: S2755)

Tôi đã quản lý để giải quyết nó bằng cách sử dụng:

    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);
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.