xml.parsers.expat — 使用 Expat 的快速 XML 解析 — Python 文档

来自菜鸟教程
Python/docs/3.8/library/pyexpat
跳转至:导航、​搜索

xml.parsers.expat — 使用 Expat 的快速 XML 解析


警告

pyexpat 模块对于恶意构建的数据并不安全。 如果您需要解析不受信任或未经身份验证的数据,请参阅 XML 漏洞 。


xml.parsers.expat 模块是 Expat 非验证 XML 解析器的 Python 接口。 该模块提供了一个单一的扩展类型 xmlparser,它表示 XML 解析器的当前状态。 创建 xmlparser 对象后,可以将对象的各种属性设置为处理函数。 当 XML 文档随后被提供给解析器时,将调用处理函数来处理 XML 文档中的字符数据和标记。

该模块使用 pyexpat 模块提供对 Expat 解析器的访问。 不推荐直接使用 pyexpat 模块。

该模块提供了一个异常和一个类型对象:

exception xml.parsers.expat.ExpatError
Expat 报告错误时引发的异常。 有关解释 Expat 错误的更多信息,请参阅 ExpatError Exceptions 部分。
exception xml.parsers.expat.error
ExpatError 的别名。
xml.parsers.expat.XMLParserType
ParserCreate() 函数返回值的类型。

xml.parsers.expat 模块包含两个函数:

xml.parsers.expat.ErrorString(errno)
返回给定错误号 errno 的解释性字符串。
xml.parsers.expat.ParserCreate(encoding=None, namespace_separator=None)

创建并返回一个新的 xmlparser 对象。 encoding(如果指定)必须是命名 XML 数据使用的编码的字符串。 Expat 不支持像 Python 那样多的编码,并且它的编码库无法扩展; 它支持 UTF-8、UTF-16、ISO-8859-1 (Latin1) 和 ASCII。 如果给出 encoding 1,它将覆盖文档的隐式或显式编码。

Expat 可以选择为您执行 XML 命名空间处理,通过为 namespace_separator 提供值来启用。 该值必须是一个单字符的字符串; 如果字符串具有非法长度(None 被视为与遗漏相同),则会引发 ValueError。 启用命名空间处理时,将扩展属于命名空间的元素类型名称和属性名称。 传递给元素处理程序 StartElementHandler 和 EndElementHandler 的元素名称将是名称空间 URI、名称空间分隔符和名称的本地部分的串联。 如果命名空间分隔符是一个零字节 (chr(0)),那么命名空间 URI 和本地部分将在没有任何分隔符的情况下连接起来。

例如,如果 namespace_separator 设置为空格字符 (' ') 并且解析以下文档:

<?xml version="1.0"?>
<root xmlns    = "http://default-namespace.org/"
      xmlns:py = "http://www.python.org/ns/">
  <py:elem1 />
  <elem2 xmlns="" />
</root>

StartElementHandler 将为每个元素接收以下字符串:

http://default-namespace.org/ root
http://www.python.org/ns/ elem1
elem2

由于 pyexpat 使用的 Expat 库的限制,返回的 xmlparser 实例只能用于解析单个 XML 文档。 为每个文档调用 ParserCreate 以提供唯一的解析器实例。

也可以看看

Expat XML 解析器
Expat 项目的主页。


XMLParser 对象

xmlparser 对象有以下方法:

xmlparser.Parse(data[, isfinal])
解析字符串 data 的内容,调用适当的处理函数来处理解析的数据。 isfinal 在最终调用此方法时必须为真; 它允许在片段中解析单个文件,而不是提交多个文件。 data 可以随时为空字符串。
xmlparser.ParseFile(file)
解析从对象 文件 读取的 XML 数据。 file 只需要提供 read(nbytes) 方法,当没有更多数据时返回空字符串。
xmlparser.SetBase(base)
设置用于解析声明中系统标识符中的相对 URI 的基数。 解析相对标识符留给应用程序:该值将作为 base 参数传递给 ExternalEntityRefHandler()、NotationDeclHandler() 和 ]UnparsedEntityDeclHandler() 函数。
xmlparser.GetBase()
返回一个字符串,其中包含先前调用 SetBase() 或 None 的基集,如果 SetBase() 尚未被调用。
xmlparser.GetInputContext()
以字符串形式返回生成当前事件的输入数据。 数据采用包含文本的实体的编码。 在事件处理程序未激活时调用时,返回值为 None。
xmlparser.ExternalEntityParserCreate(context[, encoding])
创建一个“子”解析器,可用于解析由父解析器解析的内容引用的外部解析实体。 context 参数应该是传递给 ExternalEntityRefHandler() 处理函数的字符串,如下所述。 创建子解析器时,将 ordered_attributes 和 specified_attributes 设置为该解析器的值。
xmlparser.SetParamEntityParsing(flag)
控制参数实体的解析(包括外部 DTD 子集)。 可能的 标志 值为 XML_PARAM_ENTITY_PARSING_NEVER、XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE 和 XML_PARAM_ENTITY_PARSING_ALWAYS。 如果设置标志成功,则返回 true。
xmlparser.UseForeignDTD([flag])

使用 flag(默认值)的真值调用此方法将导致 Expat 调用 ExternalEntityRefHandler 和 None 的所有参数,以允许加载备用 DTD . 如果文档不包含文档类型声明,仍会调用 ExternalEntityRefHandler,但不会调用 StartDoctypeDeclHandler 和 EndDoctypeDeclHandler。

为 flag 传递假值将取消先前传递真值的调用,否则无效。

此方法只能在调用 Parse() 或 ParseFile() 方法之前调用; 在其中任何一个被调用后调用它会导致 ExpatError 被引发,code 属性设置为 errors.codes[errors.XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING]。

xmlparser 对象具有以下属性:

xmlparser.buffer_size
buffer_text 为真时使用的缓冲区大小。 可以通过为该属性分配新的整数值来设置新的缓冲区大小。 当大小改变时,缓冲区将被刷新。
xmlparser.buffer_text
将此设置为 true 会导致 xmlparser 对象缓冲由 Expat 返回的文本内容,以避免尽可能多次调用 CharacterDataHandler() 回调。 这可以显着提高性能,因为 Expat 通常在每一行结尾处将字符数据分成块。 此属性默认为 false,并且可以随时更改。
xmlparser.buffer_used
如果启用 buffer_text,则缓冲区中存储的字节数。 这些字节表示 UTF-8 编码的文本。 当 buffer_text 为 false 时,此属性没有有意义的解释。
xmlparser.ordered_attributes
将此属性设置为非零整数会导致将属性报告为列表而不是字典。 属性按文档文本中的顺序显示。 对于每个属性,显示两个列表条目:属性名称和属性值。 (此模块的旧版本也使用此格式。)默认情况下,此属性为 false; 它可以随时更改。
xmlparser.specified_attributes
如果设置为非零整数,解析器将仅报告在文档实例中指定的那些属性,而不报告从属性声明派生的那些属性。 设置此项的应用程序需要特别小心,以根据需要使用声明中可用的附加信息,以符合 XML 处理器的行为标准。 默认情况下,此属性为 false; 它可以随时更改。

以下属性包含与 xmlparser 对象最近遇到的错误相关的值,并且只有在对 Parse() 或 ParseFile() 的调用引发 时才会有正确的值]xml.parsers.expat.ExpatError 异常。

xmlparser.ErrorByteIndex
发生错误的字节索引。
xmlparser.ErrorCode
指定问题的数字代码。 该值可以传递给 ErrorString() 函数,或与 errors 对象中定义的常量之一进行比较。
xmlparser.ErrorColumnNumber
发生错误的列号。
xmlparser.ErrorLineNumber
发生错误的行号。

以下属性包含与 xmlparser 对象中的当前解析位置相关的值。 在报告解析事件的回调期间,它们指示生成事件的字符序列中第一个的位置。 在回调之外调用时,指示的位置将刚好经过最后一个解析事件(无论是否有关联的回调)。

xmlparser.CurrentByteIndex
解析器输入中的当前字节索引。
xmlparser.CurrentColumnNumber
解析器输入中的当前列号。
xmlparser.CurrentLineNumber
解析器输入中的当前行号。

这是可以设置的处理程序列表。 要在 xmlparser 对象 o 上设置处理程序,请使用 o.handlername = func。 handlername 必须取自以下列表,并且 func 必须是接受正确数量参数的可调用对象。 除非另有说明,否则参数都是字符串。

xmlparser.XmlDeclHandler(version, encoding, standalone)
在解析 XML 声明时调用。 XML 声明是 XML 建议的适用版本的(可选)声明、文档文本的编码和可选的“独立”声明。 version 和 encoding 将是字符串,standalone 将是 1 如果文档被声明为独立,0 如果它被声明为不是独立的,如果省略了独立子句,则声明为 -1。 这仅适用于 Expat 版本 1.95.0 或更高版本。
xmlparser.StartDoctypeDeclHandler(doctypeName, systemId, publicId, has_internal_subset)
当 Expat 开始解析文档类型声明 (<!DOCTYPE ...) 时调用。 doctypeName 完全按照所提供的方式提供。 systemId 和 publicId 参数给出系统和公共标识符(如果指定),或 None 如果省略。 has_internal_subset 如果文档包含内部文档声明子集,则为真。 这需要 Expat 版本 1.2 或更高版本。
xmlparser.EndDoctypeDeclHandler()
当 Expat 完成解析文档类型声明时调用。 这需要 Expat 版本 1.2 或更高版本。
xmlparser.ElementDeclHandler(name, model)
为每个元素类型声明调用一次。 name 是元素类型的名称,model 是内容模型的表示。
xmlparser.AttlistDeclHandler(elname, attname, type, default, required)
为元素类型的每个声明的属性调用。 如果属性列表声明声明了三个属性,则此处理程序将被调用三次,每个属性调用一次。 elname 是声明适用的元素的名称,attname 是声明的属性的名称。 属性类型是作为 type 传递的字符串; 可能的值为 'CDATA'、'ID'、'IDREF'、... default 给出了文档未指定属性时使用的属性的默认值实例,或 None 如果没有默认值(#IMPLIED 值)。 如果需要在文档实例中给出该属性,则 required 将为 true。 这需要 Expat 版本 1.95.0 或更高版本。
xmlparser.StartElementHandler(name, attributes)
调用每个元素的开始。 name 是包含元素名称的字符串,attributes 是元素属性。 如果 ordered_attributes 为真,则这是一个列表(有关完整说明,请参阅 ordered_attributes)。 否则,它是一个将名称映射到值的字典。
xmlparser.EndElementHandler(name)
调用每个元素的结尾。
xmlparser.ProcessingInstructionHandler(target, data)
为每个处理指令调用。
xmlparser.CharacterDataHandler(data)
调用字符数据。 这将为普通字符数据、CDATA 标记内容和可忽略的空白调用。 必须区分这些情况的应用程序可以使用 StartCdataSectionHandler、EndCdataSectionHandler 和 ElementDeclHandler 回调来收集所需的信息。
xmlparser.UnparsedEntityDeclHandler(entityName, base, systemId, publicId, notationName)
调用未解析 (NDATA) 实体声明。 这仅适用于 Expat 库的 1.2 版; 对于更新的版本,请改用 EntityDeclHandler。 (Expat 库中的底层函数已被声明为过时。)
xmlparser.EntityDeclHandler(entityName, is_parameter_entity, value, base, systemId, publicId, notationName)
为所有实体声明调用。 对于参数和内部实体,value 将是一个字符串,给出实体的声明内容; 对于外部实体,这将是 None。 notationName 参数对于已解析实体将是 None,对于未解析实体则是符号名称。 is_parameter_entity 实体为参数实体时为真,一般实体为假(大多数应用只需要关心一般实体)。 这仅从 Expat 库的 1.95.0 版开始可用。
xmlparser.NotationDeclHandler(notationName, base, systemId, publicId)
调用符号声明。 notationName、base 和 systemId 和 publicId 是字符串(如果给定)。 如果省略公共标识符,publicId 将是 None。
xmlparser.StartNamespaceDeclHandler(prefix, uri)
当元素包含命名空间声明时调用。 命名空间声明在为放置声明的元素调用 StartElementHandler 之前处理。
xmlparser.EndNamespaceDeclHandler(prefix)
当到达包含命名空间声明的元素的结束标记时调用。 对于元素上的每个命名空间声明,按照与调用 StartNamespaceDeclHandler 的顺序相反的顺序调用一次,以指示每个命名空间声明的范围的开始。 对该处理程序的调用是在元素末尾的相应 EndElementHandler 之后进行的。
xmlparser.CommentHandler(data)
征求意见。 data 是注释的文本,不包括开头的 '<!--' 和结尾的 '-->'。
xmlparser.StartCdataSectionHandler()
在 CDATA 部分的开头调用。 需要此和 EndCdataSectionHandler 才能识别 CDATA 部分的句法开始和结束。
xmlparser.EndCdataSectionHandler()
在 CDATA 部分的末尾调用。
xmlparser.DefaultHandler(data)
为 XML 文档中未指定适用处理程序的任何字符调用。 这意味着作为结构的一部分的字符可以被报告,但没有为其提供处理程序。
xmlparser.DefaultHandlerExpand(data)
这与 DefaultHandler() 相同,但不禁止内部实体的扩展。 实体引用不会传递给默认处理程序。
xmlparser.NotStandaloneHandler()
如果 XML 文档尚未声明为独立文档,则调用。 当存在外部子集或对参数实体的引用时,会发生这种情况,但 XML 声明未在 XML 声明中独立设置为 yes。 如果此处理程序返回 0,则解析器将引发 XML_ERROR_NOT_STANDALONE 错误。 如果未设置此处理程序,则解析器不会针对此条件引发异常。
xmlparser.ExternalEntityRefHandler(context, base, systemId, publicId)

调用外部实体的引用。 base 是当前基数,由先前对 SetBase() 的调用设置。 公共和系统标识符,systemId 和 publicId,如果给定,则是字符串; 如果没有给出公共标识符,publicId 将是 None。 context 值是不透明的,只能按如下所述使用。

对于要解析的外部实体,必须实现此处理程序。 它负责使用 ExternalEntityParserCreate(context) 创建子解析器,使用适当的回调对其进行初始化,并解析实体。 这个处理程序应该返回一个整数; 如果它返回 0,解析器将引发 XML_ERROR_EXTERNAL_ENTITY_HANDLING 错误,否则解析将继续。

如果未提供此处理程序,则外部实体将通过 DefaultHandler 回调(如果提供)报告。


ExpatError 异常

ExpatError 异常有许多有趣的属性:

ExpatError.code

Expat 特定错误的内部错误编号。 errors.messages 字典将这些错误编号映射到 Expat 的错误消息。 例如:

from xml.parsers.expat import ParserCreate, ExpatError, errors

p = ParserCreate()
try:
    p.Parse(some_xml_document)
except ExpatError as err:
    print("Error:", errors.messages[err.code])

errors 模块还提供错误消息常量和字典 codes 将这些消息映射回错误代码,见下文。

ExpatError.lineno
检测到错误的行号。 第一行编号为 1。
ExpatError.offset
字符偏移到发生错误的行中。 第一列编号为 0。


例子

下面的程序定义了三个处理程序,它们只是打印出它们的参数。

import xml.parsers.expat

# 3 handler functions
def start_element(name, attrs):
    print('Start element:', name, attrs)
def end_element(name):
    print('End element:', name)
def char_data(data):
    print('Character data:', repr(data))

p = xml.parsers.expat.ParserCreate()

p.StartElementHandler = start_element
p.EndElementHandler = end_element
p.CharacterDataHandler = char_data

p.Parse("""<?xml version="1.0"?>
<parent id="top"><child1 name="paul">Text goes here</child1>
<child2 name="fred">More text</child2>
</parent>""", 1)

这个程序的输出是:

Start element: parent {'id': 'top'}
Start element: child1 {'name': 'paul'}
Character data: 'Text goes here'
End element: child1
Character data: '\n'
Start element: child2 {'name': 'fred'}
Character data: 'More text'
End element: child2
Character data: '\n'
End element: parent

内容模型描述

使用嵌套元组描述内容模型。 每个元组包含四个值:类型、量词、名称和子元组。 子项只是附加的内容模型描述。

前两个字段的值是在 xml.parsers.expat.model 模块中定义的常量。 这些常量可以分为两组:模型类型组和量词组。

模型类型组中的常量是:

xml.parsers.expat.model.XML_CTYPE_ANY
由模型名称命名的元素被声明为具有 ANY 的内容模型。
xml.parsers.expat.model.XML_CTYPE_CHOICE
命名元素允许从多个选项中进行选择; 这用于内容模型,例如 (A | B | C)。
xml.parsers.expat.model.XML_CTYPE_EMPTY
声明为 EMPTY 的元素具有此模型类型。
xml.parsers.expat.model.XML_CTYPE_MIXED
xml.parsers.expat.model.XML_CTYPE_NAME
xml.parsers.expat.model.XML_CTYPE_SEQ
代表一系列模型的模型用此模型类型表示。 用于 (A, B, C) 等型号。

量词组中的常量是:

xml.parsers.expat.model.XML_CQUANT_NONE
没有给出修饰符,所以它只能出现一次,如 A。
xml.parsers.expat.model.XML_CQUANT_OPT
模型是可选的:它可以出现一次,也可以根本不出现,如A?。
xml.parsers.expat.model.XML_CQUANT_PLUS
模型必须出现一次或多次(如 A+)。
xml.parsers.expat.model.XML_CQUANT_REP
模型必须出现零次或多次,如 A*。


Expat 错误常量

xml.parsers.expat.errors 模块中提供了以下常量。 这些常量可用于解释发生错误时引发的 ExpatError 异常对象的某些属性。 由于向后兼容的原因,常量的值是错误 message 而不是数字错误 code,你可以通过比较它的 code 属性和 errors.codes[errors.XML_ERROR_CONSTANT_NAME]。

errors 模块具有以下属性:

xml.parsers.expat.errors.codes

将字符串描述映射到其错误代码的字典。

3.2 版中的新功能。

xml.parsers.expat.errors.messages

将数字错误代码映射到其字符串描述的字典。

3.2 版中的新功能。

xml.parsers.expat.errors.XML_ERROR_ASYNC_ENTITY
xml.parsers.expat.errors.XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF
属性值中的实体引用引用外部实体而不是内部实体。
xml.parsers.expat.errors.XML_ERROR_BAD_CHAR_REF
字符引用指的是 XML 中非法的字符(例如,字符 0 或 '&#0;')。
xml.parsers.expat.errors.XML_ERROR_BINARY_ENTITY_REF
实体引用引用了用符号声明的实体,因此无法解析。
xml.parsers.expat.errors.XML_ERROR_DUPLICATE_ATTRIBUTE
一个属性在一个开始标签中被多次使用。
xml.parsers.expat.errors.XML_ERROR_INCORRECT_ENCODING
xml.parsers.expat.errors.XML_ERROR_INVALID_TOKEN
当输入字节无法正确分配给字符时引发; 例如,UTF-8 输入流中的 NUL 字节(值 0)。
xml.parsers.expat.errors.XML_ERROR_JUNK_AFTER_DOC_ELEMENT
在文档元素之后出现了除空格以外的其他东西。
xml.parsers.expat.errors.XML_ERROR_MISPLACED_XML_PI
在输入数据的开头以外的其他地方发现了 XML 声明。
xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS
该文档不包含任何元素(XML 要求所有文档只包含一个顶级元素)。
xml.parsers.expat.errors.XML_ERROR_NO_MEMORY
Expat 无法在内部分配内存。
xml.parsers.expat.errors.XML_ERROR_PARAM_ENTITY_REF
在不允许的地方找到了参数实体引用。
xml.parsers.expat.errors.XML_ERROR_PARTIAL_CHAR
在输入中发现不完整的字符。
xml.parsers.expat.errors.XML_ERROR_RECURSIVE_ENTITY_REF
实体引用包含对同一实体的另一个引用; 可能通过不同的名称,也可能是间接的。
xml.parsers.expat.errors.XML_ERROR_SYNTAX
遇到一些未指定的语法错误。
xml.parsers.expat.errors.XML_ERROR_TAG_MISMATCH
结束标签与最里面的开放开始标签不匹配。
xml.parsers.expat.errors.XML_ERROR_UNCLOSED_TOKEN
某些标记(例如开始标记)在流结束或遇到下一个标记之前未关闭。
xml.parsers.expat.errors.XML_ERROR_UNDEFINED_ENTITY
引用了一个未定义的实体。
xml.parsers.expat.errors.XML_ERROR_UNKNOWN_ENCODING
Expat 不支持文档编码。
xml.parsers.expat.errors.XML_ERROR_UNCLOSED_CDATA_SECTION
未关闭 CDATA 标记部分。
xml.parsers.expat.errors.XML_ERROR_EXTERNAL_ENTITY_HANDLING
xml.parsers.expat.errors.XML_ERROR_NOT_STANDALONE
解析器确定该文档不是“独立的”,尽管它在 XML 声明中声明了自己,并且设置了 NotStandaloneHandler 并返回了 0。
xml.parsers.expat.errors.XML_ERROR_UNEXPECTED_STATE
xml.parsers.expat.errors.XML_ERROR_ENTITY_DECLARED_IN_PE
xml.parsers.expat.errors.XML_ERROR_FEATURE_REQUIRES_XML_DTD
请求了一个需要编译 DTD 支持的操作,但 Expat 被配置为没有 DTD 支持。 xml.parsers.expat 模块的标准构建永远不应该报告这种情况。
xml.parsers.expat.errors.XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING
解析开始后请求行为更改,只能在解析开始之前更改。 这(目前)仅由 UseForeignDTD() 引发。
xml.parsers.expat.errors.XML_ERROR_UNBOUND_PREFIX
启用命名空间处理时发现未声明的前缀。
xml.parsers.expat.errors.XML_ERROR_UNDECLARING_PREFIX
该文档试图删除与前缀关联的命名空间声明。
xml.parsers.expat.errors.XML_ERROR_INCOMPLETE_PE
参数实体包含不完整的标记。
xml.parsers.expat.errors.XML_ERROR_XML_DECL
该文档根本不包含文档元素。
xml.parsers.expat.errors.XML_ERROR_TEXT_DECL
解析外部实体中的文本声明时出错。
xml.parsers.expat.errors.XML_ERROR_PUBLICID
在公共 ID 中发现不允许的字符。
xml.parsers.expat.errors.XML_ERROR_SUSPENDED
请求的操作是在暂停的解析器上进行的,但不被允许。 这包括尝试提供额外的输入或停止解析器。
xml.parsers.expat.errors.XML_ERROR_NOT_SUSPENDED
当解析器没有被挂起时,尝试恢复解析器。
xml.parsers.expat.errors.XML_ERROR_ABORTED
这不应报告给 Python 应用程序。
xml.parsers.expat.errors.XML_ERROR_FINISHED
请求的操作是在已完成解析输入的解析器上进行的,但不被允许。 这包括尝试提供额外的输入或停止解析器。
xml.parsers.expat.errors.XML_ERROR_SUSPEND_PE

脚注

1
XML 输出中包含的编码字符串应符合相应的标准。 例如,“UTF-8”有效,但“UTF8”无效。 参见 https://www.w3.org/TR/2006/REC-xml11-20060816/#NT-EncodingDecl 和 https://www.iana.org/assignments/character-sets /character-sets.xhtml。