Python 3 XML 如果找不到另一个元素,则复制并重命名元素
Python 3 XML Duplicate and rename element if another element is not found
我有一个 IN.xml 文件要修复,这让我很头疼:)
要解决的问题是在 IN.xml 文件中查找 "Donnees_Releve" 元素中是否至少存在一个 "Classe_Temporelle_Distributeur"。
如果没有,则复制一个 "Classe_Temporelle" 元素(始终存在)并将其重命名为 "Classe_Temporelle_Distributeur"。
下面的示例带有 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 文件
注意:如果元素 "Classe_Temporelle_Distributeur" 不存在于 "Donnees_Releve" 节点中,则添加该元素,它是 Classe_Temporelle 节点的副本。
每个元素可以有 1-n 个子元素
每个 Classe_Temporelle 应该有一个对应的 Classe_Temporelle_Distributeur,(每个 Classe_Temporelle 不包含相同的数据。)
<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_Releve 的第一个元素 "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')
你能帮帮我吗?
请考虑 XSLT, the special purpose language designed to transform XML files, and avoid any procedural XML mappings at the general purpose level here being Python. While Python's built-in module, etree
, does not support XSLT, it's third-party module, lxml
确实支持 XSLT 1.0 和完整的 XPath 1.0。
或者,Python 调用任何外部 XSLT 1.0 - 3.0 processor,如 Saxon 或 Xalan,甚至使用任何其他通用语言 运行 XSLT 转换(即 Java , Javascript, C#, C++, PHP, Perl, R, VB) 因为每个都有自己的 XSLT 库。
扩展您的示例以突出前三位 Python and XSLT Whosebug 金徽章用户,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_Temporelle
Classe_Temporelle_Distributeur 的元素,无论这
元素存在(在这种情况下不应进行复制)。
我有一个 IN.xml 文件要修复,这让我很头疼:)
要解决的问题是在 IN.xml 文件中查找 "Donnees_Releve" 元素中是否至少存在一个 "Classe_Temporelle_Distributeur"。
如果没有,则复制一个 "Classe_Temporelle" 元素(始终存在)并将其重命名为 "Classe_Temporelle_Distributeur"。
下面的示例带有 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 文件
注意:如果元素 "Classe_Temporelle_Distributeur" 不存在于 "Donnees_Releve" 节点中,则添加该元素,它是 Classe_Temporelle 节点的副本。
每个元素可以有 1-n 个子元素 每个 Classe_Temporelle 应该有一个对应的 Classe_Temporelle_Distributeur,(每个 Classe_Temporelle 不包含相同的数据。)
<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_Releve 的第一个元素 "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')
你能帮帮我吗?
请考虑 XSLT, the special purpose language designed to transform XML files, and avoid any procedural XML mappings at the general purpose level here being Python. While Python's built-in module, etree
, does not support XSLT, it's third-party module, lxml
确实支持 XSLT 1.0 和完整的 XPath 1.0。
或者,Python 调用任何外部 XSLT 1.0 - 3.0 processor,如 Saxon 或 Xalan,甚至使用任何其他通用语言 运行 XSLT 转换(即 Java , Javascript, C#, C++, PHP, Perl, R, VB) 因为每个都有自己的 XSLT 库。
扩展您的示例以突出前三位 Python and XSLT Whosebug 金徽章用户,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_Temporelle Classe_Temporelle_Distributeur 的元素,无论这 元素存在(在这种情况下不应进行复制)。