【问题标题】:Using Python and lxml to validate XML against an external DTD使用 Python 和 lxml 针对外部 DTD 验证 XML
【发布时间】:2014-04-18 23:42:06
【问题描述】:

我正在尝试根据 doctype 标记中引用的外部 DTD 验证 XML 文件。具体来说:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export3.dtd">
...the rest of the document...

我正在使用 Python 3.3 和 lxml 模块。从阅读 http://lxml.de/validation.html#validation-at-parse-time 开始,我把它放在一起:

enexFile = open(sys.argv[2], mode="rb") # sys.argv[2] is the path to an XML file in local storage.
enexParser = etree.XMLParser(dtd_validation=True)
enexTree = etree.parse(enexFile, enexParser)

根据我对validation.html 的理解,lxml 库现在应该负责检索DTD 并执行验证。但相反,我得到了这个:

$ ./mapwrangler.py validate notes.enex
Traceback (most recent call last):
  File "./mapwrangler.py", line 27, in <module>
    enexTree = etree.parse(enexFile, enexParser)
  File "lxml.etree.pyx", line 3239, in lxml.etree.parse (src/lxml/lxml.etree.c:69955)
  File "parser.pxi", line 1769, in lxml.etree._parseDocument (src/lxml/lxml.etree.c:102257)
  File "parser.pxi", line 1789, in lxml.etree._parseFilelikeDocument (src/lxml/lxml.etree.c:102516)
  File "parser.pxi", line 1684, in lxml.etree._parseDocFromFilelike (src/lxml/lxml.etree.c:101442)
  File "parser.pxi", line 1134, in lxml.etree._BaseParser._parseDocFromFilelike (src/lxml/lxml.etree.c:97069)
  File "parser.pxi", line 582, in lxml.etree._ParserContext._handleParseResultDoc (src/lxml/lxml.etree.c:91275)
  File "parser.pxi", line 683, in lxml.etree._handleParseResult (src/lxml/lxml.etree.c:92461)
  File "parser.pxi", line 622, in lxml.etree._raiseParseError (src/lxml/lxml.etree.c:91757)
lxml.etree.XMLSyntaxError: Validation failed: no DTD found !, line 3, column 43

这让我很吃惊,因为如果我关闭验证,那么文档解析得很好,我可以通过print(enexTree.docinfo.doctype) 来获取

$ ./mapwrangler.py validate notes.enex
<!DOCTYPE en-export SYSTEM "http://xml.evernote.com/pub/evernote-export3.dtd">

所以在我看来,找到 DTD 应该没有任何问题。

感谢您的帮助。

【问题讨论】:

  • 在构造解析器对象的时候加上no_network=False会怎样?请参阅此处的“解析器选项”:lxml.de/parsing.html#parsers
  • 啊,非常感谢@mjzn!就是这样。你能把它写在答案中,这样我就可以奖励你的声誉了吗?

标签: python xml validation lxml dtd


【解决方案1】:

由于我仍然不知道的原因,我的问题与 XML 目录在我的本地文件系统上的位置有关。

就我而言,我使用与组件内容管理系统(CCMS,在本例中为 SDL Trisoft 2011 R2)紧密集成的 XML 编辑器。当编辑器连接到 CCMS 时,DTD、目录文件和一堆其他文件会同步。这些文件最终位于以下位置的本地文件系统中:

C:\Users\[username]\AppData\Local\Trisoft\InfoShare Client\[id]\Config\DocTypes\catalog.xml

我无法让它工作。只需将整个目录复制到另一个位置即可解决问题,这很有效:

f = r"path/to/my/file.xml"
# set XML catatog file path
os.environ['XML_CATALOG_FILES'] = r'C:\DATA\Mydoctypes\catalog.xml'
# configure parser
parser = etree.XMLParser(dtd_validation=True, no_network=True)
# validate
try:
   valid = etree.parse(f, parser=parser)
    print("This file is valid against the DTD.")
except etree.XMLSyntaxError, error:
   print("This file is INVALID against the DTD!")
   print(error)

显然这并不理想,但它确实有效。

这可能与文件权限有关,或者可能是 Windows 中那个古老的“文件路径太长”问题?我还没有尝试过符号链接是否可以工作。

我使用的是Windows 7,Python 2.7.11,lxml的版本是(3.6.0)。

【讨论】:

    【解决方案2】:

    构造解析器对象时需要添加no_network=False。此选项默认设置为True

    来自http://lxml.de/parsing.html#parsers的解析器选项文档:

    no_network - 在查找外部文档时阻止网络访问(默认开启)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-01
      • 1970-01-01
      • 2012-08-21
      • 2020-08-07
      • 2014-10-06
      • 2011-06-14
      • 2015-03-04
      相关资源
      最近更新 更多