python之如何从 lxml 正确使用 xmlfile api

thcjp 阅读:26 2024-09-07 23:24:14 评论:0

我有一个大的(超过 5 个演出)XML 文件,我需要对其进行解析、执行一些操作并编写一个新的 XML 文件。

虚拟.xml

<?xml version="1.0" encoding="UTF-8"?> 
<catalog xmlns="http://www.namespace.com" catalog-id="test-catalog"> 
    <header> 
        <name>Product Catalog</name> 
    </header> 
 
    <product product-id="1234"> 
        <available-flag>false</available-flag> 
        <name>product1</name> 
    </product> 
    <product product-id="5678"> 
        <available-flag>false</available-flag> 
        <name>product1</name> 
    </product> 
    <product product-id="9999"> 
        <available-flag>false</available-flag> 
        <name>product1</name> 
    </product>     
</catalog> 

如您所见,上面的 XML 有 3 个 product标签,我需要根据预定义的 ID 列表过滤一些产品 ID。

我正在使用 lxml iterparse迭代地解析 XML 并想使用 xmlfile以增量方式创建新 XML 以保持低内存占用的 API。因此,我的动机是过滤掉不符合条件的产品标签,并按原样复制其余的 XML 标签。

from lxml import etree 
f = './dummy.xml' 
 
f1 = './test.xml' 
context = etree.iterparse(f, events=('start',)) 
productsToExport = ['1234'] 
 
 
with etree.xmlfile(f1, encoding='utf-8') as xf: 
    xf.write_declaration() 
    with xf.element('catalog xmlns="http://www.namespace.com" catalog-id="test-catalog"'): 
        for event, element in context: 
            tagName = etree.QName(element.tag).localname 
            if (tagName == 'product'): 
                pid = element.get('product-id') 
                if (pid in productsToExport): 
                    xf.write(element) 
            elif (tagName == 'header'): 
                xf.write(element) # copy existing header tag as it is 

上面的代码工作正常并生成如下的 XML

<?xml version='1.0' encoding='utf-8'?> 
<catalog xmlns="http://www.namespace.com" catalog-id="test-catalog"> 
    <header xmlns="http://www.namespace.com"> 
        <name>Product Catalog</name> 
    </header> 
 
    <product xmlns="http://www.namespace.com" product-id="1234"> 
        <available-flag>false</available-flag> 
        <name>product1</name> 
    </product> 
</catalog xmlns="http://www.namespace.com" catalog-id="test-catalog"> 

如果您观察上面的 XML,它几乎没有问题:

  • 关闭 <catalog>标签有 xmlns & catalog-id出现在里面
  • 所有标签如 header, productxmlns其中存在的属性

我检查了xmlfile api documentation但找不到解决上述问题的方法。

编辑:

我设法通过使用以下方法解决了第一个问题

attribs = {'xmlns' : 'http://www.namespace.com', 'catalog-id' : 'test-catalog'} 
 with xf.element('catalog', attribs): 
     # previous logic 

因此,现在只剩下从每个元素中删除 namespace 了。

请您参考如下方法:

考虑使用 lxml.etree 方法而不是 xmlfile API 简单地重建 XML 树,仍然在 iterparse 的上下文中:

from lxml import etree 
 
f = './dummy.xml' 
f1 = './test.xml'     
productsToExport = ['1234'] 
 
# ROOT ELEMENT WITH DEFUALT NAMESPACE 
my_nmsp = {None: 'http://www.namespace.com'} 
 
# INITIALIZE ITERATOR 
context = etree.iterparse(f, events=('start',)) 
 
for event, element in context:     
    tagName = etree.QName(element.tag).localname    
 
    for prod in productsToExport: 
        root = etree.Element('catalog', nsmap=my_nmsp) 
        root.text = '\n\t' 
        root.attrib['catalog-id'] = "test-catalog" 
 
        # PRODUCT ELEMENT 
        if tagName == 'product': 
            pid = element.get('product-id') 
 
            if pid == prod: 
                root.append(element) 
 
        # HEADER ELEMENT         
        elif (tagName == 'header'): 
            root.append(element) 
 
        # OUTPUT TREE TO FILE 
        with open(f1, 'wb') as f: 
            f.write(etree.tostring(root, pretty_print=True)) 

输出

<catalog xmlns="http://www.namespace.com" catalog-id="test-catalog"> 
    <header> 
        <name>Product Catalog</name> 
    </header> 
 
    <product product-id="1234"> 
        <available-flag>false</available-flag> 
        <name>product1</name> 
    </product>  
</catalog> 


标签:Python
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号