Python lxml - 如何删除空的重复标签

标签 python xml lxml

我有一些由脚本生成的 XML,这些 XML 可能包含也可能不包含空元素。我被告知现在我们不能在 XML 中包含空元素。这是一个例子:

<customer>  
    <govId>
       <id>@</id>
       <idType>SSN</idType>
           <issueDate/>
           <expireDate/>
           <dob/>
           <state/>
           <county/>
           <country/>
    </govId>
    <govId>
        <id/>
        <idType/>
        <issueDate/>
        <expireDate/>
        <dob/>
        <state/>
        <county/>
        <country/>
    </govId>
</customer>

输出应该是这样的:

<customer>  
    <govId>
       <id>@</id>
       <idType>SSN</idType>        
    </govId>        
</customer>

我需要删除所有空元素。您会注意到我的代码取出了“govId”子元素中的空内容,但没有取出第二个中的任何内容。我现在正在使用 lxml.objectify。

这基本上是我正在做的:

root = objectify.fromstring(xml)
for customer in root.customers.iterchildren():
    for e in customer.govId.iterchildren():
        if not e.text:
            customer.govId.remove(e)

有谁知道用 lxml objectify 做这个的方法还是有更简单的方法?如果第二个“govId”元素的所有元素都是空的,我还想完全删除它。

最佳答案

首先,您的代码存在的问题是您迭代的是customers,而不是govIds。在第三行,您为每个客户获取 first govId,并迭代其子项。因此,您需要另一个 for 循环才能使代码按预期运行。

问题末尾的这个小句子使问题变得更加复杂:如果第二个“govId”元素的所有元素都是空的,我还想将其全部删除。

这意味着,除非您只想硬编码检查一层嵌套,否则您需要递归检查元素及其子元素是否为空。例如:

def recursively_empty(e):
   if e.text:
       return False
   return all((recursively_empty(c) for c in e.iterchildren()))

注意:Python 2.5+ 因为使用了 all() builtin .

然后您可以将代码更改为类似这样的代码,以删除文档中一直为空的所有元素。

# Walk over all elements in the tree and remove all
# nodes that are recursively empty
context = etree.iterwalk(root)
for action, elem in context:
    parent = elem.getparent()
    if recursively_empty(elem):
        parent.remove(elem)

示例输出:

<customer>
  <govId>
    <id>@</id>
    <idType>SSN</idType>
  </govId>
</customer>

您可能想要做的一件事是优化递归函数中的条件 if e.text:。目前,这会将 None 和空字符串视为空,但不会像空格和换行符那样考虑空白。使用 str.strip()如果这是您对“空”的定义的一部分。


编辑:正如@Dave 所指出的,可以通过使用 generator expression 来改进递归函数。 :

return all((recursively_empty(c) for c in e.getchildren()))

这不会立即为所有 child 计算 recursively_empty(c),而是延迟地为每个 child 计算它。由于 all() 将在第一个 False 元素上停止迭代,这可能意味着显着的性能改进。

编辑 2:可以使用 e.iterchildren() 代替 e.getchildren() 进一步优化表达式。这适用于 lxml etree APIobjectify API .

关于Python lxml - 如何删除空的重复标签,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12694091/

相关文章:

python - 通过另一个数据框中的匹配索引划分数据框列

python - 我们可以使用映射来搜索而不是二分搜索吗?

java - Java从html页面获取html链接

xml - 比较对象cmdlet在文本文件中不能与 “&lt;!--”一起使用

python - 在 python basemap 中填充国家

python - 我的抽奖不起作用?

xml - OpenERP,用 XML 播种 Many2Many 关系?

python - 如何使用 lxml 解析包含前缀但没有 namespace 声明的 XML?

python - Python 和 XML 错误

Python:使用 `lxml.html` 将 HTML 内容注入(inject)到标签中