使用DTD验证XML无法使用lxml导入实体

时间:2010-10-06 16:26:00

标签: python xml dtd lxml

我有一个生成NewsML类型XML文件的工具,我想在生成文件后验证它们。 我收到一个错误:

Attempt to load network entity http://www.w3.org/TR/ruby/xhtml-ruby-1.mod

python调用是:

parser = etree.XMLParser(load_dtd=True, dtd_validation=True)
treeObject = etree.parse(f, parser)

首先我不确定我是否需要“load_dtd = True,dtd_validation = True”,但无论如何我都在使用它。 第二个错误似乎来自导入的nitf-3-4.dtd,其定义为:

<!ENTITY % xhtml-ruby.mod PUBLIC 
    "-//W3C//ELEMENTS XHTML Ruby 1.0//EN" "http://www.w3.org/TR/ruby/xhtml-ruby-1.mod">
%xhtml-ruby.mod;

lxml会出去检索这个xhtml-ruby-1.mod还是我必须在本地拥有所有的DTD文件。

1 个答案:

答案 0 :(得分:4)

尝试使用no_network=False构建解析器。如documentation中所述:

  

no_network - 在查找外部文档时阻止网络访问(默认情况下已启用)

导入的dtd模块应该由lxml检索,但是如果不允许网络访问,它将无法执行此操作(这不计入文档本身,仅用于加载外部引用的文档。事实上,我希望加载dtd本身会出错,所以我假设文档引用了该dtd的本地可用副本,并且只有dtd本身引用了远程资源?)

您还可以使用目录来使用本地可用的副本(不仅可以解决这个问题,而且还可以提高性能,对w3c服务器更友好;-))。 Libxml2(由lxml使用)将检查/etc/xml/catalog中的目录是否存在,以及XML_CATALOG_FILES环境变量(请参阅Libxml2 docs

(也可以为lxml编写自己的resolvers来拦截和处理请求,但在这种情况下这可能有点过分了)

请注意,除了解析时间验证之外还有另一个选项:使用DTD class分别加载dtd,并将​​其用作验证器。

这将使用提供的dtd验证解析的文档,无论doctype声明引用哪个dtd(如果有)(这可能很方便:并非每个有效的xml文件都必须根据dtd 想要)。

因为dtd只需要检索和解析一次,如果你要验证很多文件,这应该更快),并且(如果我没弄错),你不会遇到no_network问题

这方面的另一个好处是:你甚至可以在序列化它们之前验证你的元素/元素树(如果你的生产工具使用的是lxml)。

最后一点:如果您在分析时有权访问dtd(无法解析的实体......),则只能解析某些文档。如果可以,请避免这样做。 (并且,尽管不是每个人都同意:如果可能的话,完全避免使用doctype声明。)