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

我有一个生成NewsML类型XML文件的工具,我想在生成文件后对其进行验证.
我收到一个错误:

尝试加载网络实体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文件.

解决方法:

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

no_network – prevent network access when looking up external documents (on by default)

导入的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声明).

上一篇:起点中文网小说爬取-etree,xpath,os


下一篇:如何通过网络抓取NBA的首发阵容?