如果dict.key等于同一父项中的其他XML节点,则将ET.SubElement.text设置为dict.value

时间:2019-12-11 16:41:59

标签: python xml elementtree

因此,我正在用ElementTree创建一个新的子元素,其中新节点的文本应为dict值,如果对应值的dict键等于同一父节点内另一个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中创建my_Function节点的for循环放入,但最终在newNode.text中获得相同的值,或者陷入无限循环。

如预期结果所示,如果dict.value与同一父级<name id="0">中的
<scale> innerText匹配,我希望dict.value作为新创建的Node的文本。

1 个答案:

答案 0 :(得分:1)

我不确定my_Function应该做什么,但是请考虑以下逻辑:

  • 读取/处理CSV数据。 (您已经在执行此操作,但可以考虑使用DictReader。这将使用第一行中的键将值映射到dict。)
  • 处理每个scale元素。
  • 使用“值”值创建一个新的alternativeExportValue元素。
  • 检查具有name属性值“ 0”的id元素是否与当前的“名称”条目匹配。
  • 如果有,请附加新的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 *,该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")

* ElementTree中的XPath support受限制。