7

空の要素がある場合とない場合があるスクリプトによって生成された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」サブ要素の空のものを取り出しましたが、2番目の要素では何も取り出していませんでした。現在、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を使用してこれを行う方法を知っている人はいますか、それとももっと簡単な方法の期間がありますか?また、すべての要素が空の場合は、2番目の「govId」要素全体を削除したいと思います。

4

1 に答える 1

15

まず第一に、あなたのコードの問題は、あなたが繰り返しているが、繰り返してcustomersいないということgovIdsです。3行目では、すべての顧客に対して最初 govIdの行を取得し、その子を繰り返し処理します。したがって、forコードが意図したとおりに機能するには、別のループが必要になります。

質問の最後にあるこの小さな文は、問題をかなり複雑にします。また、すべての要素が空の場合は、2番目の「govId」要素全体を削除したいと思います。

つまり、1つのレベルのネストをチェックするだけでハードコーディングする場合を除いて、要素とその子が空であるかどうかを再帰的にチェックする必要があります。たとえば、次のようになります。

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

all()組み込みのを使用しているため、Python2.5以降。

次に、コードを次のように変更して、ドキュメント内の空の要素をすべて削除できます。

# 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>

実行したいことの1つif e.text:は、再帰関数の条件を調整することです。現在、これはNone空の文字列を空と見なしますが、スペースや改行のような空白は考慮しません。str.strip()それが「空」の定義の一部である場合に使用します。


編集:@Daveが指摘しているように、再帰関数はジェネレータ式を使用することで改善できます:

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

これはrecursively_empty(c)一度にすべての子供を評価するのではなく、一人一人を怠惰に評価します。all()は最初の要素で反復を停止するためFalse、これはパフォーマンスの大幅な向上を意味する可能性があります。

編集2e.iterchildren() :の代わりにを使用すると、式をさらに最適化できますe.getchildren()。これは、lxmletreeAPIおよびobjectifyAPIで機能します。

于 2012-10-02T16:52:15.637 に答える