IT TIP

DocumentBuilder.parse가 DTD 참조를 무시하도록합니다.

itqueen 2020. 10. 15. 22:08
반응형

DocumentBuilder.parse가 DTD 참조를 무시하도록합니다.


이 메서드에서 내 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;
}

@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를 반환하는 것만으로도 잘 작동한다는 것을 알았습니다.


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

궁극적으로 옵션은 파서 구현에 고유하다고 생각합니다. 도움이된다면 Xerces2에 대한 몇 가지 문서가 있습니다 .


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

소스 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>

위의 XML을 문자열로 받아들이고 DTD 선언을 제거하기위한 Java DOM 구현

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> 

나는 dtd가 없다는 것을 알고 있으며 필요하지도 않습니다.

나는이 진술이 의심 스럽습니다. 문서에 엔티티 참조가 포함되어 있습니까? 그렇다면 반드시 DTD가 필요합니다.

어쨌든 이것을 방지하는 일반적인 방법은 XML 카탈로그를 사용하여 "map.dtd"에 대한 로컬 경로를 정의하는 것입니다.


같은 문제가 발생한 다른 사용자가 있습니다. 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;
          }
});

The user further mentions "As you can see, when the parser hits the DTD, the entity resolver is called. I recognize my DTD with its specific ID and return an empty XML doc instead of the real DTD, stopping all validation..."

Hope this helps.

참고URL : https://stackoverflow.com/questions/155101/make-documentbuilder-parse-ignore-dtd-references

반응형