python中lxml.etree 和 ElementTree 的区别还是很明显的。
1.导入方式不同
# etree from lxml.etree import Element # ElementTree from elementtree.ElementTree import Element # ElementTree in the Python 2.5 standard library from xml.etree.ElementTree import Element
2.lxml.etree 提供了更多的功能,例如 XPath、XSLT、Relax NG、 和 XML 模式支持,这是 (c)ElementTree 不提供的。
3.etree 对 Python unicode 字符串的想法与 ElementTree 不同。 在 API 的大多数部分中,ElementTree 使用纯字符串和 unicode 字符串 就像他们一样。这包括 Element.text、Element.tail 和许多其他 地方。但是,默认情况下,ElementTree 分析器假定任何字符串 (str?或?unicode)包含 ASCII 数据。如果出现以下情况,它们会引发异常 字符串与预期的编码不匹配。
etree 对纯字符串 (str) 的想法与 ElementTree 相同。为 但是,对于 unicode 字符串,etree 在整个 API 中都假定它们是 Python unicode 编码的字符串,而不是字节数据。这包括 解析 器。因此,将 XML unicode 数据传递到 Python unicode 字符串形式的 etree 解析器。这是一个错误,在 另一方面,如果 Unicode 字符串在其 XML 声明中指定了编码, 因为这与 Python unicode 的特征编码相冲突 字符串。
4.eTree 允许通过?getParent() 方法导航到节点的父节点,并通过调用?getNext() 和?getPrevious()?导航到同级节点。 这在 ElementTree 中是不可能的,因为基础树模型不能 有这个信息。
5.当尝试使用__setitem__实际上不是 元素,但其他一些对象,etree 会引发 TypeError,而 ElementTree 引发 AssertionError。这也适用于其他一些地方 应用程序接口。一般来说,etree 会尽量避免 AssertionErrors,而倾向于 更具体地说明异常的原因。
6.当解析失败时?iterparse()?中,ElementTree 最高可达版本 1.2.x 会引发低级?ExpatError,而不是像其他解析器那样引发?SyntaxError。lxml 和 ElementTree 1.3 都会为解析器错误引发?ParseError。
7.lxml 中的?iterparse()?函数是基于 libxml2 实现的 解析器和树生成器。这意味着对文档的修改 在解析过程中,root 或当前元素的祖先可能会刺激 解析器甚至段错误。虽然这在 Python 对象中不是问题 ElementTree 使用的结构,lxml 底层的 C 树受其影响。 因此,lxml 上?iterparse()?的黄金法则是:不要触摸 解析器稍后必须再次触及的任何内容。请参阅 LXML 解析器文档。
8.ElementTree 在解析 XML 时忽略注释和处理指令, 而 etree 将读入它们并将它们视为 Comment 或 ProcessingInstruction 元素。这一点尤为明显 在文本内容中找到注释,然后由 Comment 元素。
您可以通过将布尔值?remove_comments?和/或?remove_pis?关键字参数传递给您使用的解析器来禁用此行为。为 为了方便和支持可移植代码,您还可以使用?etree。ETCompatXMLParser?而不是默认的?etree。XMLParser。它 尝试提供与 ElementTree 解析器最接近的默认设置 尽可能。
9.lxml.etree?的?TreeBuilder?类使用不同的?start()?方法的签名。它接受额外的 参数?nsmap?来传播 元素。确保兼容性 使用 ElementTree(不支持此参数),lxml 检查 如果该方法在调用它之前接受 3 个参数,否则 删除命名空间映射。这应该适用于大多数现有的 ElementTree 代码,尽管可能仍然存在冲突的情况。
10.ElementTree 1.2 在序列化空注释(无文本)时有一个错误 参数给定)添加到 XML,etree 会成功序列化它。
11.ElementTree 在序列化的注释周围添加空格,而 lxml 则这样做 不。这意味着 ElementTree 序列化为的注释文本“text” 在 lxml 中,“<!-- text -->”将变为“<!--text-->”。
12.当字符串 '*'?在?Element.iter() 和?.find*()?方法中用作标签过滤器时,ElementTree 返回树中的所有元素,包括 注释和处理说明。lxml.etree 只返回 real 元素, 即具有字符串标签名称的树节点。如果没有过滤器,两个库 遍历所有节点。
请注意,目前只有 lxml.etree 支持传递?Element?工厂 用作过滤器以仅选择元素。两个库都支持传递?Comment?和?ProcessingInstruction?工厂来选择 各自的树节点。
13.ElementTree 将处理指令的目标合并到?PI.text?中, 而 lxml.etree 将其放入?.target?属性中并将其排除在?.text?属性。因此,ElementTree 中的?pi.text?对应于?lxml.etree 中的 pi.target + “ ” + pi.text。
14.因为 etree 是建立在 libxml2 之上的,libxml2 是命名空间前缀感知的, etree 保留命名空间声明和前缀,而 ElementTree 则倾向于 提出自己的前缀(ns0、ns1 等)。当没有命名空间前缀时 但是,etree 也会创建 ElementTree 样式前缀。
15.etree 在元素上有一个“prefix”属性(只读),使元素的 前缀,如果这是已知的,否则为 None(如果 all,或默认命名空间)。
16.etree 进一步允许将 'nsmap' 字典传递给 Element 和 SubElement 元素工厂,用于显式映射命名空间前缀 命名空间 URI。这些将被转换为 那个元素。这意味着在极少数情况下,您需要 构造一个名为“nsmap”的属性,您需要注意,与 ElementTree,则不能将其作为关键字参数传递给 Element 和 SubElement 工厂。
17.ElementTree 允许 QName 对象作为属性值,并解析其 序列化的前缀(例如,如果“p”是“myns”的命名空间前缀,则属性值?QName(“{myns}myname”)?变为“p:myname”)。lxml.etree 还允许您从 QName 实例(以及 .text)设置属性值 值),但它会立即解析它们的前缀并存储纯文本 价值。因此,如果以后修改前缀,例如将子树移动到 不同的树(重新分配前缀映射),文本值将 未更新,最终可能会得到一个未定义的前缀。
18.eTree 元素可以使用 copy.deepcopy() 和?copy.copy()?进行复制,?就像 ElementTree 一样。但是,copy.copy()?不会创建一个 在树之间共享元素的浅拷贝,因为这毫无意义 在 libxml2 树的上下文中。请注意,lxml 可以深层复制树 比 ElementTree 快得多,因此深度复制可能仍然很快 足以替换您案例中的浅层副本。