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


81

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

1
나는 jt가이 질문에 대한 최선의 답을 가지고 있다고 믿습니다.
simgineer

답변:


58

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


4
DocumentBuilderFactory에서 기능을 설정하는 것이 저에게 효과적이었습니다. 이 게시물의 솔루션이 작동하지 않았습니다.
Kai Mechel

4
이것은 또한 내가 SAX 사용하지 않은 생각에도 불구하고, 나를 위해 완벽하게 일
devnull69

슬프게도 이것은 나를 위해 작동하지 않았습니다. 여전히 오류가 있습니다. @jt는 나를 위해 그것을했습니다.
닐스 - 오 - 매트

솔루션에 감사드립니다 . 이것이 제가 생각 하는 org.xml에서 권장하는 접근 방식 입니다. 이 주제에 대한 자료가 많은 것 같습니다. 참조 xerces.apache.org/xml-commons/components/resolver/... , 또는 en.wikipedia.org/wiki/XML_Catalog 와 javadoc의 saxproject.org/apidoc/org/xml/sax/EntityResolver.htmlsaxproject.org/을 apidoc / org / xml / sax / ext / EntityResolver2.html
aliopi

135

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에 대한 몇 가지 문서가 있습니다 .


21
마지막 ( load-external-dtd)이 나를 위해 트릭을했습니다. 감사합니다.
Amarghosh 2009

1
이것을 시도하는 동안 DOMException : NAMESPACE_ERR : 네임 스페이스와 관련하여 잘못된 방식으로 개체를 만들거나 변경하려고 시도했습니다. . 이 문제를 해결했습니다dbf.setNamespaceAware(true);
Tim Van Laer 2013 년

알려 드리기 위해 마지막 기능 설정 (@Amarghosh에서 언급 한대로)은 SAXParserFactory에서 잘 작동합니다.
Alexis Leclerc 2014 년

1
저에게는 load-external-dtd설정이 충분했습니다.
chris

위의 모든 기능을 사용하면 코드가 실패합니다. 마지막 두 기능 (비 검증) 만 사용하면 코드가 작동합니다.
푸 루스

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

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>

위의 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> 

2

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

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

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


2

동일한 문제가 발생한 다른 사용자가 있습니다. 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를 인식하고 실제 DTD 대신 빈 XML 문서를 반환하여 모든 유효성 검사를 중지합니다 ..."

도움이 되었기를 바랍니다.


0

나는 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);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.