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。 启用命名空间处理时,将扩展属于命名空间的元素类型名称和属性名称。 传递给元素处理程序 StartElementHandlerEndElementHandler 的元素名称将是名称空间 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_attributesspecified_attributes 设置为该解析器的值。
xmlparser.SetParamEntityParsing(flag)
控制参数实体的解析(包括外部 DTD 子集)。 可能的 标志 值为 XML_PARAM_ENTITY_PARSING_NEVERXML_PARAM_ENTITY_PARSING_UNLESS_STANDALONEXML_PARAM_ENTITY_PARSING_ALWAYS。 如果设置标志成功,则返回 true。
xmlparser.UseForeignDTD([flag])

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

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 = funchandlername 必须取自以下列表,并且 func 必须是接受正确数量参数的可调用对象。 除非另有说明,否则参数都是字符串。

xmlparser.XmlDeclHandler(version, encoding, standalone)
在解析 XML 声明时调用。 XML 声明是 XML 建议的适用版本的(可选)声明、文档文本的编码和可选的“独立”声明。 versionencoding 将是字符串,standalone 将是 1 如果文档被声明为独立,0 如果它被声明为不是独立的,如果省略了独立子句,则声明为 -1。 这仅适用于 Expat 版本 1.95.0 或更高版本。
xmlparser.StartDoctypeDeclHandler(doctypeName, systemId, publicId, has_internal_subset)
当 Expat 开始解析文档类型声明 (<!DOCTYPE ...) 时调用。 doctypeName 完全按照所提供的方式提供。 systemIdpublicId 参数给出系统和公共标识符(如果指定),或 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 标记内容和可忽略的空白调用。 必须区分这些情况的应用程序可以使用 StartCdataSectionHandlerEndCdataSectionHandlerElementDeclHandler 回调来收集所需的信息。
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 将是一个字符串,给出实体的声明内容; 对于外部实体,这将是 NonenotationName 参数对于已解析实体将是 None,对于未解析实体则是符号名称。 is_parameter_entity 实体为参数实体时为真,一般实体为假(大多数应用只需要关心一般实体)。 这仅从 Expat 库的 1.95.0 版开始可用。
xmlparser.NotationDeclHandler(notationName, base, systemId, publicId)
调用符号声明。 notationNamebasesystemIdpublicId 是字符串(如果给定)。 如果省略公共标识符,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() 的调用设置。 公共和系统标识符,systemIdpublicId,如果给定,则是字符串; 如果没有给出公共标识符,publicId 将是 Nonecontext 值是不透明的,只能按如下所述使用。

对于要解析的外部实体,必须实现此处理程序。 它负责使用 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-EncodingDeclhttps://www.iana.org/assignments/character-sets /character-sets.xhtml