使DocumentBuilder.parse忽略DTD引用
当我parsing我的xml文件(variablesf)在这个方法中,我得到一个错误
C:\ Documents and Settings \ joe \ Desktop \ aicpcudev \ OnlineModule \ map.dtd(系统找不到指定的path)
我知道我没有dtd,也不需要它。 如何parsing这个File对象到一个Document对象中而忽略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; }
类似于@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上设置function:
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(); ...
最终,我认为这些选项是特定于parsing器实现的。 如果有帮助, 这里是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; } } });
我知道我没有dtd,也不需要它。
我怀疑这个说法。 你的文件是否包含实体引用? 如果是这样,你一定需要DTD。
无论如何,防止这种情况发生的通常方法是使用XML目录来定义“map.dtd”的本地path。
这里有另一个用户谁得到了同样的问题: http : //forums.sun.com/thread.jspa?threadID=284209&forumID=34
用户ddssot在该post上说
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; } });
用户进一步提到“正如你所看到的,当parsing器碰到DTD时,实体parsing器被调用,我用我们的特定ID识别我的DTD,并返回一个空的XML文档,而不是真正的DTD,停止所有的validation…”
希望这可以帮助。
源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>
Java DOM实现接受上面的XML作为string和删除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(不含DTD)
<MYACCSERVICE> <REQ_PAYLOAD> <ACCOUNT>1234567890</ACCOUNT> <BRANCH>001</BRANCH> <CURRENCY>USD</CURRENCY> <TRANS_REFERENCE>201611100000777</TRANS_REFERENCE> </REQ_PAYLOAD> </MYACCSERVICE>