如何在XML文件中添加标签使用Python

lrl1mhuk  于 2023-09-29  发布在  Python
关注(0)|答案(3)|浏览(151)

我有以下XML文件:

<user-response date="2023-09-27T12:07:10+02:00">
  <users>
    <user>
      <user-data>
        <last-name>last name1</last-name>
        <first-name>first name 1</first-name>
      </user-data>
    </user>
    <user>
      <user-data>
        <last-name>last name 2</last-name>
        <first-name>first name 2</first-name>
      </user-data>
    </user>
  </users>
</user-response>

我想在<user>之后和<user-data>之前添加一个特定的标记
我尝试了以下代码:

def modify_xml(file_name_result,file_location,file_destination):

    with open(file_location, encoding='utf-8') as f:
        tree = ET.parse(f)
        root = tree.getroot()

        for elem in root.iter():
            if elem.tag == 'user':
                ET.SubElement(elem,'validation-test')

    tree.write(file_destination, encoding='utf-8')

我也试过:

xml_text = ET.XML('''<validation-test/>''')
    for elem in tree.findall('./users/user'):
        elem.append(xml_text)

到目前为止没有错误,但标签被添加到末尾,得到以下结果:

<user-response date="2023-09-27T12:07:10+02:00">
  <users>
    <user>
      <user-data>
        <last-name>last name1</last-name>
        <first-name>first name 1</first-name>
      </user-data>
    <validation-test /></user>
    <user>
      <user-data>
        <last-name>last name 2</last-name>
        <first-name>first name 2</first-name>
      </user-data>
    </user>
  <validation-test /></users>
</user-response>

我不知道我做错了什么,有人能帮帮我吗?我希望我说得够清楚了。
Thanks in advance

atmip9wb

atmip9wb1#

您使用SubElement不起作用,因为SubElement会在指定元素后添加一个元素:
Subelement工厂。此函数创建一个元素示例,并将其追加到现有元素
你想添加一个新的子元素,可以使用.insert方法:

from lxml import etree as ET

def modify_xml(input_file, output_file):

    with open(input_file, encoding='utf-8') as f:
        tree = ET.parse(f)
        root = tree.getroot()

        for elem in root.iter():
            if elem.tag == 'user':
                elem.insert(0, ET.Element('validation-test'))

    tree.write(output_file, encoding='utf-8')

modify_xml('data.xml', 'data_patched.xml')

给定示例输入,将生成:

<user-response date="2023-09-27T12:07:10+02:00">
  <users>
    <user>
      <validation-test/><user-data>
        <last-name>last name1</last-name>
        <first-name>first name 1</first-name>
      </user-data>
    </user>
    <user>
      <validation-test/><user-data>
        <last-name>last name 2</last-name>
        <first-name>first name 2</first-name>
      </user-data>
    </user>
  </users>
</user-response>

谢谢你的回答@larsks,如果我想和不在里面的人处于同一水平呢?例如:

<user>
  <validation-test />
  <user-data>...</user-data>
</user>

这正是我在上面的回答中所展示的。这个片段和我最初的答案没有区别:<validation-test>元素包含在<user>元素内。

mspsb9vt

mspsb9vt2#

下面是用于比较的XSLT实现。
一个小型XSLT模板完成了这项工作:

<xsl:template match="user-data">
    <validation-test/>
    <xsl:copy-of select="."/>
</xsl:template>

输入XML

<user-response date="2023-09-27T12:07:10+02:00">
    <users>
        <user>
            <user-data>
                <last-name>last name1</last-name>
                <first-name>first name 1</first-name>
            </user-data>
        </user>
        <user>
            <user-data>
                <last-name>last name 2</last-name>
                <first-name>first name 2</first-name>
            </user-data>
        </user>
    </users>
</user-response>

我知道了

<?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="*"/>

    <!--Identity transform-->
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="user-data">
        <validation-test/>
        <xsl:copy-of select="."/>
    </xsl:template>
</xsl:stylesheet>

输出XML

<user-response date="2023-09-27T12:07:10+02:00">
  <users>
    <user>
      <validation-test/>
      <user-data>
        <last-name>last name1</last-name>
        <first-name>first name 1</first-name>
      </user-data>
    </user>
    <user>
      <validation-test/>
      <user-data>
        <last-name>last name 2</last-name>
        <first-name>first name 2</first-name>
      </user-data>
    </user>
  </users>
</user-response>

Python

import lxml.etree as lx

# PARSE XML AND XSLT
doc = lx.parse("Input.xml")
style = lx.parse("Style.xslt")
outfile = "output.xml"

# CONFIGURE AND RUN TRANSFORMER
transformer = lx.XSLT(style)
result = transformer(doc)

# OUTPUT TO FILE
with open(outfile, "wb") as f:
    f.write(result)
2hh7jdfx

2hh7jdfx3#

你可以在一个综合列表中这样做:

import xml.etree.ElementTree as ET

xml_str = """<user-response date="2023-09-27T12:07:10+02:00">
  <users>
    <user>
      <user-data>
        <last-name>last name1</last-name>
        <first-name>first name 1</first-name>
      </user-data>
    </user>
    <user>
      <user-data>
        <last-name>last name 2</last-name>
        <first-name>first name 2</first-name>
      </user-data>
    </user>
  </users>
</user-response>"""

root = ET.fromstring(xml_str)

# Insert element on index 0
[elem.insert(0, ET.Element('validation-test')) for elem in root.findall('.//user')]

# Nice print           
ET.indent(root, space="  ")
ET.dump(root)

# If a file is needed
#tree.write("new.xml", xml_declaration=True, encoding="utf-8")

输出量:

<user-response date="2023-09-27T12:07:10+02:00">
  <users>
    <user>
      <validation-test />
      <user-data>
        <last-name>last name1</last-name>
        <first-name>first name 1</first-name>
      </user-data>
    </user>
    <user>
      <validation-test />
      <user-data>
        <last-name>last name 2</last-name>
        <first-name>first name 2</first-name>
      </user-data>
    </user>
  </users>
</user-response>

相关问题