我目前正在编写一个使用Java 1.6的工具,它汇集了许多XML文件。所有文件都验证了DocBook 4.5 DTD(我使用xmllint检查了这一点,并将DocBook 4.5 DTD指定为--dtdvalid参数),但并非所有文件都包含DOCTYPE声明。
我将每个XML文件加载到DOM中以执行所需的操作,如下所示:
private Document fileToDocument( File input ) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringElementContentWhitespace(false);
factory.setIgnoringComments(false);
factory.setValidating(false);
factory.setExpandEntityReferences(false);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse( input );
}
在大多数情况下,这一点非常有效,我可以使用他返回的对象来导航树并执行所需的操作,然后将文档写回。我遇到问题的地方是文件:
在这种情况下,使用消息从builder.parse(...)调用抛出异常:
[Fatal Error] :5:15: The entity "mdash" was referenced, but not declared.
很公平,没有宣布。在这个实例中我理想的做法是将DocumentBuilderFactory设置为始终使用DocBook 4.5 DTD,无论文件中是否指定了一个。
我确实尝试使用DocBook 4.5架构进行验证,但发现这会产生许多与XML无关的错误。似乎模式可能在功能上不等同于DTD,至少对于此版本的DocBook规范而言。
我能想到的另一个选择是读取文件,尝试并检测是否设置了doctype,然后在实际将XML解析到DOM之前设置了一个。
所以,我的问题是,是否有一种更聪明的方式,我没有看到告诉解析器使用特定的DTD或确保解析继续进行尽管实体没有解析(不仅仅是& emdash;示例,但任何实体在XML中 - 有大量的潜力)?
答案 0 :(得分:1)
可以使用EntityResolver2并实施EntityResolver2.getExternalSubset()帮助吗?
...此方法也可用于没有DOCTYPE声明的文档。遇到根元素但未看到DOCTYPE声明时,将调用此方法。如果它返回外部子集的值,则将该根元素声明为根元素,从而产生在文档的序言末尾拼接DOCTYPE声明的效果,否则该元素无效。 ...