pythonlxml如何删除空的重复标记

2024-09-28 22:24:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一些由脚本生成的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>

输出应如下所示:

^{pr2}$

我需要移除所有的空元素。您会注意到,我的代码去掉了“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”元素的所有元素都是空的,我还想删除它的全部内容。在


Tags: 脚本id元素内容customerxmlcountryobjectify
1条回答
网友
1楼 · 发布于 2024-09-28 22:24:53

首先,您的代码的问题是您正在迭代customers,而不是govIds。在第三行中,为每个客户取第一个第一个govId,并迭代其子级。因此,您需要另一个for循环才能让代码像您预期的那样工作。在

问题末尾的这句话让问题变得更加复杂了:如果第二个“govId”元素的所有元素都是空的,那么我还想删除它的全部内容。

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

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

注意:Python2.5+因为使用了^{} builtin。在

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

^{pr2}$

样本输出:

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

您可能需要做的一件事是优化递归函数中的条件if e.text:。目前,它将None和空字符串视为空,而不是像空格和换行符那样的空白。如果这是“空”定义的一部分,请使用^{}。在


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

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

这不会同时为所有子级计算recursively_empty(c),而是惰性地为每个子级计算它。由于all()将停止对第一个False元素的迭代,这可能意味着显著的性能改进。在

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

相关问题 更多 >