【问题标题】:Remove Empty XML Elements - Python删除空 XML 元素 - Python
【发布时间】:2021-05-19 20:32:14
【问题描述】:

我正在尝试从 XML 中删除空 XML 元素,但是对于具有属性但没有文本值的元素存在问题。我可以成功删除空 XML 元素,但无法在最终 XML 中保留具有属性的元素。我想基本上清理 XML 并完全删除没有文本值的空节点,但保留具有属性的节点。

以下是我正在使用的脚本,以及输入和(所需的)输出 XML……任何帮助都非常感谢!

脚本:

from lxml import etree
import os

path = "C:\\users\\mdl518\\Desktop\\"

### Removing empty XML elements
tree = etree.parse(os.path.join(path,"my_file.xml"))

for elem in tree.xpath('//*[not(node())]'):
   elem.getparent().remove(elem):

with open(".//new_file.xml","wb") as f:
    f.write(etree.tostring(tree, xml_declaration=True, encoding='utf-8')) ## Removes empty XML elements, including the elements with attributes

输入 XML:

<?xml version='1.0' encoding='utf-8'?>
<nas:metadata xmlns:nas="http://www.arcgis.com/schema/nas/base"   
xmlns:mcc="http://standards.org/iso/19115/-3/mcc/1.0"    
xmlns:mdl="http://standards.org/iso/19115/-3/mdl/1.0" 
xmlns:mnl="http://standards.org/iso/19115/-3/mnl/1.0">
xmlns:lan="http://standards.org/iso/19115/-3/lan/1.0">
xmlns:lis="http://standards.org/iso/19115/-3/lis/1.0">
xmlns:gam="http://standards.org/iso/19115/-3/gam/1.0">

  <mdl:metadataIdentifier>
    <mcc:MD_Identifier>
        <mnl:type>
          <gam:String>The Metadata File</gam:String>
        </mnl:type>
          <mnl:description codeList="http://arcgis.com/codelist/ScopeCode" codeListValue="dataset"/>
         <mnl:address>
          <mnl:defaultLocale>
          </mnl:defaultLocale>
         </mnl:address>
         <lan:language>
           <lan:type>
             <lis:name>English</lis:name>
           </lan:type>
          </lan:language>
      </mcc:MD_Identifier>
      <mcc:contactInfo>
        <mdl:POC>
          <mnl:name>
            <lis:person>Tom</lis:person>
          </mnl:name>
          <mnl:age>
          </mnl:age>
          <mnl:status>
          </mnl:status>
        </mdl:POC>
      </mcc:contactInfo>
    </mdl:metadataIdentifier>
 </nas:metadata>

输出 XML:

<?xml version='1.0' encoding='utf-8'?>
<nas:metadata xmlns:nas="http://www.arcgis.com/schema/nas/base"   
xmlns:mcc="http://standards.org/iso/19115/-3/mcc/1.0"    
xmlns:mdl="http://standards.org/iso/19115/-3/mdl/1.0" 
xmlns:mnl="http://standards.org/iso/19115/-3/mnl/1.0">
xmlns:lan="http://standards.org/iso/19115/-3/lan/1.0">
xmlns:lis="http://standards.org/iso/19115/-3/lis/1.0">
xmlns:gam="http://standards.org/iso/19115/-3/gam/1.0">

  <mdl:metadataIdentifier>
    <mcc:MD_Identifier>
        <mnl:type>
          <gam:String>The Metadata File</gam:String>
        </mnl:type>
        <mnl:description codeList="http://arcgis.com/codelist/ScopeCode" codeListValue="dataset"/>
      <lan:language>
        <lan:type>
          <lis:name>English</lis:name>
        </lan:type>
       </lan:language>
     </mcc:MD_Identifier>
     <mcc:contactInfo>
       <mdl:POC>
         <mnl:name>
           <lis:person>Tom</lis:person>
         </mnl:name>
       </mdl:POC>
     </mcc:contactInfo>
   </mdl:metadataIdentifier>
 </nas:metadata>

【问题讨论】:

    标签: python xml parsing automation lxml


    【解决方案1】:

    xml 是您的问题格式不正确,但假设已修复,请尝试更改此行

    for elem in tree.xpath('//*[not(node())]'):
    

    到这里:

    for elem in tree.xpath('//*[not(node())][not(count(./@*))>0]'):
    

    看看它是否有效。

    编辑:

    问题中已编辑的 XML 格式仍然不正确。我尝试修复它,然后应用以下内容:

    xml_str = """<?xml version='1.0' encoding='utf-8'?>
    <nas:metadata xmlns:nas="http://www.arcgis.com/schema/nas/base"   
    xmlns:mcc="http://standards.org/iso/19115/-3/mcc/1.0"    
    xmlns:mdl="http://standards.org/iso/19115/-3/mdl/1.0" 
    xmlns:mnl="http://standards.org/iso/19115/-3/mnl/1.0"
    xmlns:lan="http://standards.org/iso/19115/-3/lan/1.0"
    xmlns:lis="http://standards.org/iso/19115/-3/lis/1.0"
    xmlns:gam="http://standards.org/iso/19115/-3/gam/1.0">
    
      <mdl:metadataIdentifier>
        <mcc:MD_Identifier>
            <mnl:type>
              <gam:String>The Metadata File</gam:String>
            </mnl:type>
              <mnl:description codeList="http://arcgis.com/codelist/ScopeCode" codeListValue="dataset"/>
             <mnl:address>
              <mnl:defaultLocale>
              </mnl:defaultLocale>
             </mnl:address>
             <lan:language>
               <lan:type>
                 <lis:name>English</lis:name>
               </lan:type>
              </lan:language>
          </mcc:MD_Identifier>
          <mcc:contactInfo>
            <mdl:POC>
              <mnl:name>
                <lis:person>Tom</lis:person>
              </mnl:name>
              <mnl:age>
              </mnl:age>
              <mnl:status>
              </mnl:status>
            </mdl:POC>
          </mcc:contactInfo>
        </mdl:metadataIdentifier>
     </nas:metadata>
    
    """
    doc = etree.XML(xml_str.encode())
    for elem in doc.xpath('//*[not(count(./@*))>0][not(normalize-space(.))]'):
        elem.getparent().remove(elem)
    print(etree.tostring(doc, xml_declaration=True, encoding='utf-8').decode())
    

    我从上面得到的输出是问题中想要的输出。

    【讨论】:

    • 嘿,@Jack,我更新了 XML 以使其成为有效格式。我尝试了您更新的脚本,但没有成功。我尝试根据所述条件“打印(elem)”,但它没有产生任何元素。它对你有用吗?再次感谢您一直以来的帮助!
    • 谢谢,@Jack,您的解决方案在输入 XML 上效果很好!对于它的价值,我正在尝试将相同的脚本应用于更大的文件,并且它仍在删除具有属性的元素及其父元素。我将不得不继续解决为什么会这样,因为上面的示例 XML 遵循类似的结构,但我会确认您的答案是正确的解决方案 - 再次感谢!
    • 您应该可以只使用[not(@*)] 而不是[not(count(./@*))&gt;0]。无需统计属性。
    猜你喜欢
    • 2016-08-26
    • 1970-01-01
    • 2012-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多