Python3XML复制并重命名元素(如果找不到其他元素)

2024-09-27 07:30:42 发布

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

我有一个IN.xml文件要修复,它让我头疼:)

要解决的问题是,如果在“Donnees\u Releve”元素中至少存在一个“Classe\u Temporelle\u distributor”,请查看in.xml文件

如果没有,则复制一个“Classe_Temporelle”元素(始终存在)并将其重命名为“Classe_Temporelle_distributor”

下面的示例包含IN.xml和预期的OUT.xml文件

这就是IN.xml文件的外观

<filename>
 <prm>
  <Donnees_Releve>
   <Classe_Temporelle>
    <data></data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data></data>
   </Classe_Temporelle>
  </Donnees_Releve>
 <Donnees_Releve>
   <Classe_Temporelle>
    <data></data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data></data>
   </Classe_Temporelle>
  </Donnees_Releve> 
 </prm>
<filename>

这是预期的OUT.xml文件

注:如果“Donnees\u Releve”节点中未出现元素“Classe\u Temperalle\u Distributer”,则添加元素“Classe\u Temperalle\u Distributer”,它是Classe\u Temperalle节点的副本

每个元素可以有1-n个子元素 每个临时类应具有相应的临时类分销商(每个临时类不包含相同的数据)

<filename>
     <prm>
      <Donnees_Releve>
       <Classe_Temporelle>
        <data></data>
       </Classe_Temporelle>
       <Classe_Temporelle>
        <data></data>
       </Classe_Temporelle>
       <Classe_Temporelle_Distributeur>
        <data></data>
       </Classe_Temporelle_Distributeur>
       <Classe_Temporelle_Distributeur>
        <data></data>
       </Classe_Temporelle_Distributeur>
      </Donnees_Releve>
      <Donnees_Releve>
       <Classe_Temporelle>
        <data></data>
       </Classe_Temporelle>
       <Classe_Temporelle>
        <data></data>
       </Classe_Temporelle>
       <Classe_Temporelle_Distributeur>
        <data></data>
       </Classe_Temporelle_Distributeur>
       <Classe_Temporelle_Distributeur>
        <data></data>
       </Classe_Temporelle_Distributeur>
      </Donnees_Releve> 
     </prm>
    <filename>

我写的代码

部分工作,但它只修复每个Donnees_relve的第一个元素“Classe_Temporelle”。但是它可以有很多子元素,然后它与请求不匹配

import xml.etree.ElementTree as ET


file = 'IN/IN.xml'

tree = ET.parse(file)
root = tree.getroot()

#loop on each PRM
for prm in root.iter('PRM'):


    # Loop on each Donnees_Releve

    for classeDistributeur in prm.iter('Donnees_Releve'):

        Classe_Temporelle_Distributeur = classeDistributeur.find('Classe_Temporelle_Distributeur')

        if Classe_Temporelle_Distributeur is None:
            print("Classe_Temporelle_Distributeur not found")

            # copy element Classe_Temporelle in Classe_Temporelle_Distributeur

            Classe_Temporelle = classeDistributeur.find('Classe_Temporelle')

            dupe = copy.deepcopy(Classe_Temporelle) #copy node
            classeDistributeur.append(dupe) #insert the new node

            # Rename Node
            Classe_Temporelle.tag = "Classe_Temporelle_Distributeur"


        else :
            print("Ok nothing to do")


tree.write('OUT/out.xml')

你能帮帮我吗


Tags: 文件in元素dataxmlfilenameoutprm
2条回答

考虑XSLT,用于转换XML文件的专用语言,并避免在这里使用Python的通用级别上的任何过程XML映射。Python的内置模块etree不支持XSLT,但它的第三方模块^{}支持XSLT1.0和完整的XPath1.0

< P>可替代的是,Python调用任何外部的{A3},比如Saxon或Xaln,或者甚至使用任何其他通用语言来运行XSLT转换(即java、JavaScript、C++、PH++、PHP、Perl、R、VB),因为它们各自携带自己的XSLT库。p>

将示例扩展到前三名PythonXSLTStackOverflow gold badge用户,XSLT可以使用多种模板模式轻松复制所需的节点

XSLT(另存为.xsl文件,一个特殊的.xml文件)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes" encoding="UTF-8"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Donnees_Releve">
    <xsl:copy>
      <xsl:apply-templates select="Classe_Temporelle" mode="t1"/>
      <xsl:apply-templates select="Classe_Temporelle" mode="t2"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Classe_Temporelle" mode="t1">
    <xsl:copy>
      <xsl:apply-templates select="data" />
    </xsl:copy>
  </xsl:template>

  <xsl:template match="Classe_Temporelle" mode="t2">
    <Classe_Temporelle_Distributeur>
      <xsl:apply-templates select="data" />
    </Classe_Temporelle_Distributeur>
  </xsl:template>

</xsl:stylesheet>

输入XML

<?xml version="1.0" encoding="utf-8" ?>
<filename>
 <prm>
  <Donnees_Releve>
   <Classe_Temporelle>
    <data>Martijn Pietersr</data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data>Alex Martelli</data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data>unutbu</data>
   </Classe_Temporelle>
  </Donnees_Releve>
 <Donnees_Releve>
   <Classe_Temporelle>
    <data>Dimitre Novatchev</data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data>Martin Honnen</data>
   </Classe_Temporelle>
   <Classe_Temporelle>
    <data>Michael Kay</data>
   </Classe_Temporelle>
  </Donnees_Releve> 
 </prm>
</filename>

Python(无for循环或if逻辑)

import lxml.etree as et

# INPUT XML AND XSL SOURCES
xml = et.parse('Input.xml')
xsl = et.parse('Script.xsl')

# RUN TRANSFORMATION
transformer = et.XSLT(xsl)
new_xml = transformer(xml)

# PRINT TO CONSOLE
print(new_xml)

# SAVE TO FILE
with open('Output.xml', 'wb') as f:
   f.write(new_xml)

输出XML

<?xml version="1.0" encoding="utf-16"?>
<filename>
  <prm>
    <Donnees_Releve>
      <Classe_Temporelle>
        <data>Martijn Pietersr</data>
      </Classe_Temporelle>
      <Classe_Temporelle>
        <data>Alex Martelli</data>
      </Classe_Temporelle>
      <Classe_Temporelle>
        <data>unutbu</data>
      </Classe_Temporelle>
      <Classe_Temporelle_Distributeur>
        <data>Martijn Pietersr</data>
      </Classe_Temporelle_Distributeur>
      <Classe_Temporelle_Distributeur>
        <data>Alex Martelli</data>
      </Classe_Temporelle_Distributeur>
      <Classe_Temporelle_Distributeur>
        <data>unutbu</data>
      </Classe_Temporelle_Distributeur>
    </Donnees_Releve>
    <Donnees_Releve>
      <Classe_Temporelle>
        <data>Dimitre Novatchev</data>
      </Classe_Temporelle>
      <Classe_Temporelle>
        <data>Martin Honnen</data>
      </Classe_Temporelle>
      <Classe_Temporelle>
        <data>Michael Kay</data>
      </Classe_Temporelle>
      <Classe_Temporelle_Distributeur>
        <data>Dimitre Novatchev</data>
      </Classe_Temporelle_Distributeur>
      <Classe_Temporelle_Distributeur>
        <data>Martin Honnen</data>
      </Classe_Temporelle_Distributeur>
      <Classe_Temporelle_Distributeur>
        <data>Michael Kay</data>
      </Classe_Temporelle_Distributeur>
    </Donnees_Releve>
  </prm>
</filename>

Online Demo

代码的问题是调用find,它只查找 具有给定名称的元素的第一次出现。 您应该使用findall和循环

另一个(可选)更正是使用较短的名称

因此,请更改您的代码,例如:

for dr in root.iter('Donnees_Releve'):
    if dr.find('Classe_Temporelle_Distributeur') is None:
        for ct in dr.findall('Classe_Temporelle'):
            wrk = copy.deepcopy(ct)
            wrk.tag = 'Classe_Temporelle_Distributeur'
            dr.append(wrk)

恐怕另一个解决方案会复制现有的Classe\u Temporelle 无论是否: 元素存在(在这种情况下,不应复制)

相关问题 更多 >

    热门问题