Pergunta

Quando eu analisar meu arquivo xml (variável f) neste método, eu recebo um erro

C: \ Documents and Settings \ Joe \ Desktop \ aicpcudev \ OnlineModule \ map.dtd (O sistema não pode encontrar o caminho especificado)

Eu sei que eu não tenho o DTD, nem eu precisar dele. Como posso analisar esse objeto File em um objeto Document, ignorando erros de referência 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;
}
Foi útil?

Solução

Uma abordagem semelhante ao sugerido por @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;
            }
        }
    });

Eu achei que simplesmente devolver um InputSource vazio funcionou tão bem?

Outras dicas

Tente configurar recursos na 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();
...

Em última análise, acho que as opções são específicas para a implementação de analisador. Aqui está alguma documentação para Xerces2 se isso ajuda.

Eu encontrei um problema onde o arquivo DTD estava no arquivo jar junto com o XML. Eu resolvi o problema com base nos exemplos aqui, como segue: -

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

Eu sei que eu não tenho o DTD, nem eu precisar dele.

Estou desconfiado desta declaração; se seu documento contém quaisquer referências de entidade? Se assim for, você definitivamente precisa o DTD.

De qualquer forma, a forma usual de impedir que isso aconteça é usar um catálogo de XML para definir um caminho local para "map.dtd".

aqui está outro usuário que tem o mesmo problema: http: // fóruns. sun.com/thread.jspa?threadID=284209&forumID=34

ddssot utilizador nesse post diz

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

O usuário menciona ainda "Como você pode ver, quando o analisador atinge o DTD, o resolvedor entidade é chamado. Eu reconheço meu DTD com o seu ID específico e retornar um documento XML vazio em vez do real DTD, parando todas as validação. .. "

Espero que isso ajude.

XML Fonte (Com 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>

implementação Java DOM para aceitar acima XML como cordas e remoção de declaraçã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 Destino (Sem DTD)

<MYACCSERVICE>
   <REQ_PAYLOAD>
      <ACCOUNT>1234567890</ACCOUNT>
      <BRANCH>001</BRANCH>
      <CURRENCY>USD</CURRENCY>
      <TRANS_REFERENCE>201611100000777</TRANS_REFERENCE>
   </REQ_PAYLOAD>
</MYACCSERVICE> 
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top