因此,我使用 ElementTree 创建一个新的子元素,其中新节点的文本应该是一个字典值,如果相应值的字典键等于同一父节点中另一个 XML 节点的文本。
XML 示例:
<ns0:scaleType xmlns:ns0="http://someURL.com/">
<scales>
<scale>
<names>
<name id="0">abc</name>
<name id="1" />
</names>
<alternativeExportValues>
</alternativeExportValues>
</scale>
<scale>
<names>
<name id="0">def</name>
<name id="1" />
</names>
<alternativeExportValues>
</alternativeExportValues>
</scale>
</scales>
</ns0:scaleType>
CSV 示例:
name;value
abc;10012
def;20025
现在的Python代码:
import xml.etree.ElementTree as ET
import csv
csvData = []
with open('myCSV.csv', 'r', encoding="utf8") as f:
reader = csv.reader(f, delimiter=";")
for row in reader:
csvData.append({'name': row[0], 'value': row[1]})
tree = ET.parse('myXml.xml')
root = tree.getroot()
def my_Function():
for p in csvData:
for name in root.findall(".//name[@id='0']"):
text = name.text
if p['name'] == text:
value = p['value']
return value
my_Function()
for elem in root.iter('alternativeExportValues'):
newNode = ET.SubElement(elem, 'alternativeExportValue')
newNode.text =
tree.write("myNewXML.xml", encoding="utf-8")
预期结果:
<ns0:scaleType xmlns:ns0="http://someURL.com/">
<scales>
<scale>
<names>
<name id="0">abc</name>
<name id="1" />
</names>
<alternativeExportValues>
<alternativeExportValue>10012</alternativeExportValue>
</alternativeExportValues>
</scale>
<scale>
<names>
<name id="0">def</name>
<name id="1" />
</names>
<alternativeExportValues>
<alternativeExportValue>20025</alternativeExportValue>
</alternativeExportValues>
</scale>
</scales>
</ns0:scaleType>
我尝试放置创建 alternativeExportValue
的 for 循环节点位于 my_Function
,但最终在 newNode.text
中获得相同的值或陷入无限循环。
正如您在预期结果中看到的,我希望 dict.value 作为新创建节点的文本(如果它与
<name id="0">
匹配)同一父级中的innerText <scale>
.
最佳答案
我不太确定 my_Function
应该做什么,但请考虑以下逻辑:
- 读取/处理 CSV 数据。 (您已经这样做了,但请考虑使用 DictReader。这将使用第一行中的键将值映射到字典。)
- 处理每个
scale
元素。 - 使用“value”值创建一个新的
alternativeExportValue
元素。 - 检查
id
属性值为“0”的name
元素是否与当前“name”条目匹配。 - 如果是,请附加新的
alternativeExportValue
元素。
示例...
import xml.etree.ElementTree as ET
import csv
with open('myCSV.csv', 'r', encoding="utf8") as csvfile:
tree = ET.parse('myXml.xml')
for row in csv.DictReader(csvfile, delimiter=";"):
name = row.get("name")
new_aev_elem = ET.Element("alternativeExportValue")
new_aev_elem.text = row.get("value")
for scale in tree.findall(".//scale"):
name0 = scale.find("names/name[@id='0']")
if name0.text == name:
aevs_elem = scale.find("alternativeExportValues")
aevs_elem.append(new_aev_elem)
break
tree.write("myNewXML.xml", encoding="utf-8")
这可以工作,但效率不高,因为您必须处理要修改的实际 scale
元素之前的每个 scale
元素。
更糟糕的是,如果删除 break
,它将处理 XML 中的每个 scale
元素(对于 CSV 的每一行!)。
如果可以切换到lxml ,您可以使用稍微复杂一点的 XPath*,它只会处理需要修改的 scale
元素...
from lxml import etree
import csv
with open('myCSV.csv', 'r', encoding="utf8") as csvfile:
tree = etree.parse('myXml.xml')
uc = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
lc = "abcdefghijklmnopqrstuvwxyz"
for row in csv.DictReader(csvfile, delimiter=";"):
name = row.get("name").lower()
new_aev_elem = etree.Element("alternativeExportValue")
new_aev_elem.text = row.get("value")
aevs_elem = tree.xpath(f".//scale[translate(names/name[@id='0'],'{uc}','{lc}')='{name}']/alternativeExportValues")[0]
aevs_elem.append(new_aev_elem)
tree.write("myNewXML.xml", encoding="utf-8")
*XPath support ElementTree 中的内容是有限的。
关于python - 如果 dict.key 等于同一父级中的其他 XML 节点,则将 ET.SubElement.text 设置为 dict.value,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59290381/