python lxml 根据子元素文本函数将 sub_element 添加到父项与 class
python lxml add sub_element to parent based on subelement text function vs. class
抱歉,这有点啰嗦,但我想尽可能详细。
我有以下示例 xml 文件:
<root>
<input_file>
<type>x</type>
</input_file>
<input_file>
<type>y</type>
</input_file>
</root>
并希望使用 python3.9 中的 python lxml 包添加基于 <type>
标签的子元素,以便 xml 文件看起来像这样:
<root>
<input_file>
<type>x</type>
<path>hi</path>
</input_file>
<input_file>
<type>y</type>
<path>hi_again</path>
</input_file>
</root>
以下代码有效:
from lxml import etree as LET
xml_file = 'test.xml'
tree = LET.parse(xml_file)
root = tree.getroot()
for input_file in root.findall('input_file'):
type_element = input_file.find('type')
if type_element.text == 'x':
c = LET.SubElement(input_file, 'path')
c.text = 'hi'
elif type_element.text == 'y':
c = LET.SubElement(input_file, 'path')
c.text = 'hi_again'
LET.indent(root, space=" ")
tree.write(xml_file)
当我尝试从以下 class 执行此操作时,我创建了(文件 XMLReader.py):
from lxml import etree as LET
import string
class XMLReader(object):
def __init__(self, file_path):
self.file_path = file_path
self.tree = LET.parse(self.file_path)
self.root = self.tree.getroot()
def set_sub_element(self, parent_tag, tag, info):
child = LET.SubElement(parent_tag, tag)
child.text = self.clean_string(info)
self.root.append(child)
LET.indent(self.root, space=" ")
self.tree.write(self.file_path)
def get_all_elements(self, tag):
try:
return self.root.findall(tag)
except AttributeError:
return None
def clean_string(self, s):
return ''.join(filter(lambda x: x in string.printable, s))
使用以下代码:
from XMLReader import XMLReader
items = {'x':'hi', 'y': 'hi_again'}
xml_file = 'test.xml'
xml_test = XMLReader(xml_file)
input_file_tags = xml_test.get_all_elements('input_file')
for input_file in input_file_tags:
type_element = input_file.find('type')
if type_element.text in items:
item = items[type_element.text]
xml_test.set_sub_element(input_file, 'path', item)
我得到以下结果文件:
<root>
<input_file>
<type>x</type>
</input_file>
<input_file>
<type>y</type>
</input_file>
<path>hi</path>
<path>hi_again</path>
</root>
我想知道我在这里做错了什么以获得与上面相同的结果,其中生成的 <path></path>
不是 <input_file></input_file> based on the <type></type>
值的子元素。
作为练习,这里有一个相对简单的方法:
#start with your `items`
items = {'x':'hi', 'y': 'hi_again'}
tags = ['input_file','type']
for v in items.keys():
destination = root.xpath(f'//{tags[0]}/{tags[1]}[text()="{v}"]/..')[0]
new_elem=LET.fromstring(f'<path>{items[v]}</path>')
destination.insert(1,new_elem)
LET.indent(root, space=" ")
print(LET.tostring(root).decode())
输出:
<root>
<input_file>
<type>x</type>
<path>hi</path>
</input_file>
<input_file>
<type>y</type>
<path>hi_again</path>
</input_file>
</root>
抱歉,这有点啰嗦,但我想尽可能详细。
我有以下示例 xml 文件:
<root>
<input_file>
<type>x</type>
</input_file>
<input_file>
<type>y</type>
</input_file>
</root>
并希望使用 python3.9 中的 python lxml 包添加基于 <type>
标签的子元素,以便 xml 文件看起来像这样:
<root>
<input_file>
<type>x</type>
<path>hi</path>
</input_file>
<input_file>
<type>y</type>
<path>hi_again</path>
</input_file>
</root>
以下代码有效:
from lxml import etree as LET
xml_file = 'test.xml'
tree = LET.parse(xml_file)
root = tree.getroot()
for input_file in root.findall('input_file'):
type_element = input_file.find('type')
if type_element.text == 'x':
c = LET.SubElement(input_file, 'path')
c.text = 'hi'
elif type_element.text == 'y':
c = LET.SubElement(input_file, 'path')
c.text = 'hi_again'
LET.indent(root, space=" ")
tree.write(xml_file)
当我尝试从以下 class 执行此操作时,我创建了(文件 XMLReader.py):
from lxml import etree as LET
import string
class XMLReader(object):
def __init__(self, file_path):
self.file_path = file_path
self.tree = LET.parse(self.file_path)
self.root = self.tree.getroot()
def set_sub_element(self, parent_tag, tag, info):
child = LET.SubElement(parent_tag, tag)
child.text = self.clean_string(info)
self.root.append(child)
LET.indent(self.root, space=" ")
self.tree.write(self.file_path)
def get_all_elements(self, tag):
try:
return self.root.findall(tag)
except AttributeError:
return None
def clean_string(self, s):
return ''.join(filter(lambda x: x in string.printable, s))
使用以下代码:
from XMLReader import XMLReader
items = {'x':'hi', 'y': 'hi_again'}
xml_file = 'test.xml'
xml_test = XMLReader(xml_file)
input_file_tags = xml_test.get_all_elements('input_file')
for input_file in input_file_tags:
type_element = input_file.find('type')
if type_element.text in items:
item = items[type_element.text]
xml_test.set_sub_element(input_file, 'path', item)
我得到以下结果文件:
<root>
<input_file>
<type>x</type>
</input_file>
<input_file>
<type>y</type>
</input_file>
<path>hi</path>
<path>hi_again</path>
</root>
我想知道我在这里做错了什么以获得与上面相同的结果,其中生成的 <path></path>
不是 <input_file></input_file> based on the <type></type>
值的子元素。
作为练习,这里有一个相对简单的方法:
#start with your `items`
items = {'x':'hi', 'y': 'hi_again'}
tags = ['input_file','type']
for v in items.keys():
destination = root.xpath(f'//{tags[0]}/{tags[1]}[text()="{v}"]/..')[0]
new_elem=LET.fromstring(f'<path>{items[v]}</path>')
destination.insert(1,new_elem)
LET.indent(root, space=" ")
print(LET.tostring(root).decode())
输出:
<root>
<input_file>
<type>x</type>
<path>hi</path>
</input_file>
<input_file>
<type>y</type>
<path>hi_again</path>
</input_file>
</root>