DocumentBuilder.parseにDTD参照を無視させる


82

このメソッドで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 2017

回答:


59

@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 2013年

悲しいことに、これは私にとってはうまくいきませんでした。まだエラーが発生しました。@jtは私のためにそれをしました。
nils-o-mat

解決策をありがとう、これはorg.xmlが推奨するアプローチだと思います。このトピックに関する資料はたくさんあるようです。xerces.apache.org/xml-commons/components/resolver/…、またはen.wikipedia.org/wiki/XML_Catalogjavadocsaxproject.org/apidoc/org/xml/sax/EntityResolver.htmlおよびsaxproject.org/を
aliopi 2017

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

1
私にとってはload-external-dtd設定で十分でした。
chris 2015

上記のすべての機能を使用すると、コードも失敗します。最後の2つの機能(検証なし)を使用するだけで、コードが機能します。
Purus 2016

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宣言を削除するためのJavaDOM実装

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.