【问题标题】:Obtain DTD information from XML using Python使用 Python 从 XML 中获取 DTD 信息
【发布时间】:2016-10-21 05:21:17
【问题描述】:

我正在尝试使用 Python 最好是标准库从 XML 文档中提取 DTD 信息。乍一看,xml.sax.handler.DTDHandler 似乎是要走的路,所以我编写了以下示例代码来提取一个琐碎的 DocBook v4 文档的 DTD:

import xml.sax
from contextlib import closing

XML_CODE = '''<!DOCTYPE example PUBLIC 
    "-//OASIS//DTD DocBook XML V4.1.2//EN"
    "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">
<example><title>Hello World in Python</title>
<programlisting>
print('Hello World!')
</programlisting>
</example>'''

class DTDPrinter(xml.sax.handler.DTDHandler):
    def notationDecl(self, name, publicId, systemId):
        print('name={}, publicId={}'.format(name, publicId))

if __name__ == '__main__':
    with closing(xml.sax.make_parser()) as parser:
        parser.setFeature(xml.sax.handler.feature_external_pes, False)
        parser.setFeature(xml.sax.handler.feature_validation, False)
        parser.setDTDHandler(DTDPrinter())
        print('---------- before feed')
        parser.feed(XML_CODE)
        print('---------- after feed')

我的期望是,当使用 Python 3.5 运行此代码时,输​​出将类似于:

---------- before feed
name=example, publicId=-//OASIS//DTD DocBook XML V4.1.2//EN
---------- after feed

相反,我得到的输出似乎与各种图像格式相关,但与文档中指定的格式无关:

---------- before feed
name=BMP, publicId=+//ISBN 0-7923-9432-1::Graphic Notation//NOTATION Microsoft Windows bitmap//EN
name=CGM-CHAR, publicId=ISO 8632/2//NOTATION Character encoding//EN
name=CGM-BINARY, publicId=ISO 8632/3//NOTATION Binary encoding//EN
...
name=WMF, publicId=+//ISBN 0-7923-9432-1::Graphic Notation//NOTATION Microsoft Windows Metafile//EN
name=WPG, publicId=None
name=linespecific, publicId=None
---------- after feed

虽然名称为 linespecific 的最后一个条目可能以残缺的方式引用文档 DTD?

我还注意到,尽管文档很简单,但在最后一次输出之后延迟了几秒钟。也许解析器试图连接到互联网?我试图通过设置功能来禁用它

        parser.setFeature(xml.sax.handler.feature_external_pes, False)
        parser.setFeature(xml.sax.handler.feature_validation, False)

但无济于事。

如何说服 DTDHandler 对文档中出现的 DTD 做出反应而不连接到 Internet?

【问题讨论】:

  • 你永远不会调用类的定义方法 notationDecl 来打印输出。
  • @Parfait 那是因为我希望 SAX 解析器在遇到 &lt;!DOCTYPE ...&gt; 时调用它。回调使用parser.setDTDHandler(DTDPrinter()) 行设置。
  • @Parfait 我想我知道你在说什么:在将我的原始代码简化为最小示例时,我从未调用过大部分代码,因为!= 放错了位置。然而,主要问题仍然存在。我用获得的新见解更新了这个问题。
  • “我怎样才能说服 DTDHandler 对文档中出现的 DTD 做出反应而不连接到 Internet?” “文档中”没有 DTD。您在文档中拥有的是一个 DOCTYPE 声明,其中引用了oasis-open.org/docbook/xml/4.1.2/docbookx.dtd 上提供的实际 DTD。要获取 DTD,解析器必须连接到 Internet。

标签: python xml sax dtd


【解决方案1】:

由于在过去 2 周内我没有收到答案并且无法使其正常工作,我诉诸暴力并简单地使用正则表达式来提取信息。这很丑陋,无法正确处理表达 DTD 的所有有效方式,但对于我的目的来说已经足够了。

import re
DTD_REGEX = re.compile(
    r'<!DOCTYPE\s+(?P<name>[a-zA-Z][a-zA-Z-]*)\s+PUBLIC\s+"(?P<public_id>.+)"')
dtd_match = DTD_REGEX.match(XML_CODE)
if dtd_match is not None:
    public_id = dtd_match.group('public_id')
    print(public_id)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-24
    • 1970-01-01
    • 2017-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多