使用python修改XML中基于另一个子元素的子元素



我有以下XML文件:

<root>
<input_file>
<type>x</type>
<path>hi</path>
</input_file>
<input_file>
<type>y</type>
<path>hi_again</path>
</input_file>
</root>

和我试图修改基于<type>值的<path>值,这样:

<root>
<input_file>
<type>x</type>
<path>bye</path>
</input_file>
<input_file>
<type>y</type>
<path>bye_again</path>
</input_file>
</root>

我有以下代码:

items = {'x':'bye', 'y': 'bye_again'}
tags = ['input_file','type']
for v in items.keys():
destination = root.xpath(f'//{tags[0]}/{tags[1]}[text()="{v}"]/..')[0]
new_elem=LET.fromstring(f'<path>{items[v]}</path>')
destination.replace('path', new_elem)
LET.indent(root, space="  ")
print(LET.tostring(root).decode())

没有成功。是不是有什么我不明白的地方?我应该修改这个值而不是替换它吗?

谢谢。

使用xpath和lxml,尝试:

for target in root.xpath(f'//{tags[0]}'):
old = target.xpath(f'./{tags[1]}/text()')[0]
target.xpath('./path')[0].text=items[old]
print(etree.tostring(root).decode())

输出应该是你期望的输出。

基于XSLT的解决方案。

剩下的部分就是在Python中启动XSLT转换。

输入XML

<root>
<input_file>
<type>x</type>
<path>hi</path>
</input_file>
<input_file>
<type>y</type>
<path>hi_again</path>
</input_file>
</root>
XSLT>
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" encoding="utf-8" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="path">
<xsl:copy>
<xsl:choose>
<xsl:when test="preceding-sibling::type='x'">bye</xsl:when>
<xsl:when test="preceding-sibling::type='y'">bye_again</xsl:when>
<xsl:otherwise>unknown</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>

输出XML

<root>
<input_file>
<type>x</type>
<path>bye</path>
</input_file>
<input_file>
<type>y</type>
<path>bye_again</path>
</input_file>
</root>

见下-只是一个简单的循环(不需要外部库)

import xml.etree.ElementTree as ET

items = {'x':'bye', 'y': 'bye_again'}
xml = '''<root>
<input_file>
<type>x</type>
<path>hi</path>
</input_file>
<input_file>
<type>y</type>
<path>hi_again</path>
</input_file>
</root>'''
root = ET.fromstring(xml)
for f in root.findall('.//input_file'):
f.find('path').text = items.get(f.find('type').text,'unknown')
ET.dump(root)

输出
<root>
<input_file>
<type>x</type>
<path>bye</path>
</input_file>
<input_file>
<type>y</type>
<path>bye_again</path>
</input_file>
</root>

相关内容

最新更新