首页 > 解决方案 > Python: how to edit element of XML file?

问题描述

I have an XML file, This file includes many named elements, each element has several nodes under it:

<name search = "select ARG: write">
    <version id = "1.0.0">
        <value>myVal</value>
        <method>myMethod</method>
    </version>
</name>
<name search = "select ARG: bla">
    <version id = "2.0.0">
        <value>myVal</value>
        <method>myMethod</method>
    </version>
</name>

I want to search this XML file and in case this name search value starts with select ARG (in my example this the first value is select ARG: write) i want to create this new named element but this time the value that was select ARG: write should be selected ARG: write. This is what I have tried:

from xml.dom import minidom

xamlfile = r'C:\file.xml'
newxamlfile = r'C:\new.xml'

dom = minidom.parse(xamlfile)

# Fetch the desired elements in the tree.
res = dom.getElementsByTagName('name')

# Loop through all.
for element in res:
    search_name_value = element.getAttribute('search')

    # Filter for the attribute and value.
    if search_name_value.startswith('select ARG:'):
        # In case of match, replace.
        element.setAttribute('search_name', search_name_value.replace('select ARG:', 'selected ARG:'))

# Store the file.
with open(newxamlfile, 'w') as f:
    f.write(dom.toxml())

Here, I have replaced the desired string and not added the new one, editing the elements that I want instead of creating new ones and adding them to the file.

Any suggestions how to do that?

UPDATE

This is my file before:

<project version="4">
<name search="select ARG: write">
    <version id="1.0.0">
        <value>myVal</value>
        <method>myMethod</method>
    </version>
</name>
<name search="select ARG: bla">
    <version id="2.0.0">
        <value>myVal</value>
        <method>myMethod</method>
    </version>
</name>
</project>

This is how i want my file will be:

<project version="4">
<name search="select ARG: write">
    <version id="1.0.0">
        <value>myVal</value>
        <method>myMethod</method>
    </version>
</name>
<name search="selected ARG: write">
    <version id="1.0.0">
        <value>myVal</value>
        <method>myMethod</method>
    </version>
</name>
<name search="select ARG: bla">
    <version id="2.0.0">
        <value>myVal</value>
        <method>myMethod</method>
    </version>
</name>
<name search="selected ARG: bla">
    <version id="2.0.0">
        <value>myVal</value>
        <method>myMethod</method>
    </version>
</name>
</project>

EDIT

According @DirtyBit suggestion:

xmldoc = minidom.parse(xamlfile)

tags = xmldoc.getElementsByTagName("name")

for item in tags:
    str = item.attributes["search"].value
    if 'select ARG' in str:
        item.attributes["search"].value = item.attributes["search"].value.replace('select ARG', 'selected ARG')

with open(xamlfile, "a+") as f:
    xmldoc.writexml(f)

This works fine but i have 2 issues:

  1. As you can see i added if statement because i want to duplicate and create new node only in the value is with select ARG (and replace it with selected ARG) and not duplicate the others that did not mach this conditions.

  2. At he middle of the new XML file i have this line:

    </element><?xml version="1.0" ?><element>

标签: pythonxml

解决方案


替换部分属性的解决方案(在使用新要求更新之前):

import xml.etree.ElementTree as ET

tree = ET.parse('example.xml')

for name in tree.getroot().iterfind('name'):
    if name.attrib['search'].startswith('select ARG'):
        name.attrib['search'] = name.attrib['search'].replace(
            'select ARG', 'selected ARG')

tree.write('example.xml')

在属性上添加与上述解决方案相同的替换属性的新相同块的解决方案:

import xml.etree.ElementTree as ET

tree = ET.parse('example.xml')

for name in tree.getroot().iterfind('name'):
    if name.attrib['search'].startswith('select ARG'):
        new = ET.Element(name.tag)
        new.attrib['search'] = name.attrib['search'].replace(
            'select ARG', 'selected ARG')
        tree.getroot().append(new)
        for version in name.iterfind('version'):
            new.append(version)

tree.write('example.xml')

来自ElementTree 文档

parse(source, parser=None)
将外部 XML 部分加载到此元素树中。source 是文件名或文件对象。parser 是一个可选的解析器实例。如果未给出,则使用标准 XMLParser 解析器。返回节根元素。

getroot()
返回此树的根元素。

iterfind(match)
按标签名称或路径查找所有匹配的子元素。与 getroot().iterfind(match) 相同。返回一个iterable,产生文档顺序中的所有匹配元素。

attrib
包含元素属性的字典。请注意,虽然 attrib 值始终是一个真正的可变 Python 字典,但 ElementTree 实现可能会选择使用另一种内部表示,并且仅在有人要求时才创建字典。要利用此类实现,请尽可能使用以下字典方法。

class xml.etree.ElementTree.Element(tag, attrib={}, **extra)
元素类。该类定义了 Element 接口,并提供了该接口的参考实现。

元素名称、属性名称和属性值可以是字节字符串或 Unicode 字符串。tag 是元素名称。attrib 是一个可选字典,包含元素属性。extra 包含附加属性,作为关键字参数给出。

append(subelement)
将元素子元素添加到此元素的末尾 子元素的内部列表

write(file, encoding="us-ascii", xml_declaration=None, default_namespace=None, method="xml")
将元素树以 XML 格式写入文件。file 是文件名,或为写入而打开的文件对象。encoding [1] 是输出编码(默认为 US-ASCII)。xml_declaration 控制是否应将 XML 声明添加到文件中。使用 False 表示从不,True 表示永远,None 仅在不是 US-ASCII 或 UTF-8 时使用(默认为 None)。default_namespace 设置默认的 XML 命名空间(用于“xmlns”)。方法是“xml”、“html”或“text”(默认为“xml”)。返回一个编码的字符串。


推荐阅读