尝试使用 python 在 XML 中插入一个元素,但我的代码没有作为单独的元素添加,而是作为子元素添加
Trying to Insert an element in XML using python, but instead of getting added as separate Element my code is adding as SubElement
我有如下示例 xml 文件,我想在 <item>Production</item>
之后添加一个元素 <item>DEV</item>
之前 (Sample.xml)
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
<resource>
预期输出 (Output.xml)
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production</item>
<item>DEV</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
<resource>
这是我的示例代码
import xml.etree.ElementTree as ET
mytree = ET.parse("Sample.xml")
root = mytree.getroot()
for child in root.iter('item'):
if child.text == "Production":
new = ET.SubElement(child,'item')
new.text = "DEV"
mytee.write("Output.xml")
我得到的结果是
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production<item>DEV</item></item>
<item>DEV</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
<resource>
要解决您的问题,您可以收集文本为“Production”的节点的父节点。您还需要具有文本“Production”的节点索引:您可以使用函数 enumerate()
获取它。你可以这样编码:
import xml.etree.ElementTree as ET
mytree = ET.parse("Sample.xml")
root = mytree.getroot()
for child in root.iter():
for i, elt in enumerate(child.getchildren()):
if elt.text == "Production":
new = ET.Element('item')
new.text = "DEV"
child.insert(i+1, new)
mytree.write("Output.xml")
Can you please share some example on how to use lxml for adding a new element. I tried with solution @Pierre-Loic shared and it works fine but after adding new Element it does not create new line.
下面是在lxml中使用addnext()
方法的核心示例...
from lxml import etree
tree = etree.parse("input.xml")
try:
target_elem = tree.xpath("./string-array/item[.='Production']")[0]
new_elem = etree.fromstring("<item>DEV</item>") # Could also construct a new Element and set .text.
target_elem.addnext(new_elem)
except IndexError:
print("Unable to find target element.")
tree.write("output.xml")
但是正如您将看到的,这也会在与其兄弟相同的行上输出新的 item
...
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production</item><item>DEV</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
</resource>
这纯粹是格式化,但如果你想“重置”漂亮的打印,我建议将树序列化为一个字符串,然后使用 XMLParser 解析该字符串以去除所有空格,然后编写新的漂亮打印树到文件...
from lxml import etree
tree = etree.parse("input.xml")
try:
target_elem = tree.xpath("./string-array/item[.='Production']")[0]
new_elem = etree.fromstring("<item>DEV</item>") # Could also construct a new Element and set .text.
target_elem.addnext(new_elem)
except IndexError:
print("Unable to find target element.")
# "Reset" pretty printing and write to file.
parser = etree.XMLParser(remove_blank_text=True)
etree.ElementTree(etree.fromstring(etree.tostring(tree),
parser=parser)).write("output.xml",
pretty_print=True)
输出...
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production</item>
<item>DEV</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
</resource>
Can we add indentation to the Elements. The requirement is to have <item>...</item>
with 4 indentations. Right now i see with only 2 for all elements. The original file has 4 but this script after adding new Element, it is changing the indentation to 2.
如果您使用的是 lxml 4.5 或更高版本,您可以使用 indent() function...
from lxml import etree
tree = etree.parse("input.xml")
try:
target_elem = tree.xpath("./string-array/item[.='Production']")[0]
new_elem = etree.fromstring("<item>DEV</item>") # Could also construct a new Element and set .text.
target_elem.addnext(new_elem)
except IndexError:
print("Unable to find target element.")
# "Reset" pretty printing.
parser = etree.XMLParser(remove_blank_text=True)
new_tree = etree.ElementTree(etree.fromstring(etree.tostring(tree), parser=parser))
# Indent 4 spaces instead of the default 2.
etree.indent(new_tree, space=" ")
# Write to file.
new_tree.write("output.xml", pretty_print=True)
输出...
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production</item>
<item>DEV</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
</resource>
我有如下示例 xml 文件,我想在 <item>Production</item>
<item>DEV</item>
之前 (Sample.xml)
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
<resource>
预期输出 (Output.xml)
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production</item>
<item>DEV</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
<resource>
这是我的示例代码
import xml.etree.ElementTree as ET
mytree = ET.parse("Sample.xml")
root = mytree.getroot()
for child in root.iter('item'):
if child.text == "Production":
new = ET.SubElement(child,'item')
new.text = "DEV"
mytee.write("Output.xml")
我得到的结果是
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production<item>DEV</item></item>
<item>DEV</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
<resource>
要解决您的问题,您可以收集文本为“Production”的节点的父节点。您还需要具有文本“Production”的节点索引:您可以使用函数 enumerate()
获取它。你可以这样编码:
import xml.etree.ElementTree as ET
mytree = ET.parse("Sample.xml")
root = mytree.getroot()
for child in root.iter():
for i, elt in enumerate(child.getchildren()):
if elt.text == "Production":
new = ET.Element('item')
new.text = "DEV"
child.insert(i+1, new)
mytree.write("Output.xml")
Can you please share some example on how to use lxml for adding a new element. I tried with solution @Pierre-Loic shared and it works fine but after adding new Element it does not create new line.
下面是在lxml中使用addnext()
方法的核心示例...
from lxml import etree
tree = etree.parse("input.xml")
try:
target_elem = tree.xpath("./string-array/item[.='Production']")[0]
new_elem = etree.fromstring("<item>DEV</item>") # Could also construct a new Element and set .text.
target_elem.addnext(new_elem)
except IndexError:
print("Unable to find target element.")
tree.write("output.xml")
但是正如您将看到的,这也会在与其兄弟相同的行上输出新的 item
...
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production</item><item>DEV</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
</resource>
这纯粹是格式化,但如果你想“重置”漂亮的打印,我建议将树序列化为一个字符串,然后使用 XMLParser 解析该字符串以去除所有空格,然后编写新的漂亮打印树到文件...
from lxml import etree
tree = etree.parse("input.xml")
try:
target_elem = tree.xpath("./string-array/item[.='Production']")[0]
new_elem = etree.fromstring("<item>DEV</item>") # Could also construct a new Element and set .text.
target_elem.addnext(new_elem)
except IndexError:
print("Unable to find target element.")
# "Reset" pretty printing and write to file.
parser = etree.XMLParser(remove_blank_text=True)
etree.ElementTree(etree.fromstring(etree.tostring(tree),
parser=parser)).write("output.xml",
pretty_print=True)
输出...
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production</item>
<item>DEV</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
</resource>
Can we add indentation to the Elements. The requirement is to have
<item>...</item>
with 4 indentations. Right now i see with only 2 for all elements. The original file has 4 but this script after adding new Element, it is changing the indentation to 2.
如果您使用的是 lxml 4.5 或更高版本,您可以使用 indent() function...
from lxml import etree
tree = etree.parse("input.xml")
try:
target_elem = tree.xpath("./string-array/item[.='Production']")[0]
new_elem = etree.fromstring("<item>DEV</item>") # Could also construct a new Element and set .text.
target_elem.addnext(new_elem)
except IndexError:
print("Unable to find target element.")
# "Reset" pretty printing.
parser = etree.XMLParser(remove_blank_text=True)
new_tree = etree.ElementTree(etree.fromstring(etree.tostring(tree), parser=parser))
# Indent 4 spaces instead of the default 2.
etree.indent(new_tree, space=" ")
# Write to file.
new_tree.write("output.xml", pretty_print=True)
输出...
<resource xmlns:ns0="http://schemas.android.com/apk" xmlns:ns1="http://schemas.android">
<string-array name="selectable_environment" ns1:ignore="InconsistenArray">
<item>QA</item>
<item>SIT</item>
<item>Staging</item>
<item>Production</item>
<item>DEV</item>
<item>RQA</item>
<item>PTE</item>
</string-array>
</resource>