将具有相同文本的XML变量替换为python中的另一个文本变量



我使用python3和beautifulsoup4、pandas、counter将一个XML文件转换为CSV文件此Xml中有数千个产品。我遇到了一个特别的问题。XML中的许多产品都是父产品的子产品,但父产品本身不是XML。每个子产品都有一个具有相同值(parent-id(的特殊父标记,因此我们可以知道它们是子产品。<parent>x</parent>Xml结构如下:

<product>
<id>1</id>
<parent>x</parent>
</product>
<product>
<id>2</id>
<parent>x</parent>
</product>
<product>
<id>3</id>
<parent>x</parent>
</product>
<product>
<id>4</id>
</product>
<product>
<id>5</id>
<parent>y</parent>
</product>
<product>
<id>6</id>
<parent>y</parent>
</product>

您可以看到id为4的产品没有parent标签,因此不是子产品。前3个产品有一个值为x的parent,后两个产品有另一个值值为Y的parent等等7000多个产品。出于我的目的,我需要将每个<parent/>标记替换为具有相同值的第一个id。我想要的结果:

<product>
<id>1</id>
<parent>1</parent>
</product>
<product>
<id>2</id>
<parent>1</parent>
</product>
<product>
<id>3</id>
<parent>1</parent>
</product>
<product>
<id>4</id>
</product>
<product>
<id>5</id>
<parent>5</parent>
</product>
<product>
<id>6</id>
<parent>5</parent>
</product>

到目前为止,我还需要用csv将每个值转换为各自的列和行。

#test.py
def parse_xml(xml_data):
# Initializing soup variable
soup = BeautifulSoup(xml_data, 'xml')
# Creating column for table
df = pd.DataFrame(columns=['id', 'parent'])
# Here I get all duplacates of the same tag
lst = soup.select('parent')
d =  Counter(lst) 
resultparent = [k for k, v in d.items() if v > 1]
#I spleat on seperate text to get all duplicate x and y as one 
def a():
for index, i in enumerate(resultparent):
a = i.text
return a
# I get also id or every x an y    
def b():
for index, i in enumerate(resultparent):
c = i.find_previous('id').text
return c
# now I start writing csv
all_products = soup.findAll('product')   
product_length = len(all_products)
for index, product in enumerate(all_products):
parent = product.find('parent')
if parent is None:
parent = ""
else:  
parent = parent.text
# here I wanted to check if I could find duplicate values with existing, I hope that if 
# there will be let say parent tag is x  will replace with 1  (don't work) 
if parent == def a():
parent = def b()
product_id = product.find('id').text
# then I write all in csv 
row = [{
'id': product_id,
'parent': parent}]

df = df.append(row, ignore_index=True)
print(f'Appending row %s of %s' % (index+1, product_length))

return df
df = parse_xml(xml_data)
df.to_csv('test.csv')

上面的这些代码不能正常工作——当用CSV编写时,它只将第一个值x x x替换为1 1 1,但不替换-y值和其他值。谢谢你的帮助。

给定以下input.xml文件:

<products>
<product>
<id>1</id>
<parent>x</parent>
</product>
<product>
<id>2</id>
<parent>x</parent>
</product>
<product>
<id>3</id>
<parent>x</parent>
</product>
<product>
<id>4</id>
</product>
<product>
<id>5</id>
<parent>y</parent>
</product>
<product>
<id>6</id>
<parent>y</parent>
</product>
</products>

这里有一种获得正确匹配的方法:

import pandas as pd
df = pd.read_xml("input.xml")
pairs = (
df.groupby("parent")
.agg(list)
.pipe(lambda df_: df_["id"].apply(lambda x: str(x[0])))
.to_dict()
)
print(pairs)  # {'x': '1', 'y': '5'}

然后,使用Python标准库XML模块:

import xml.etree.ElementTree as ET
tree = ET.parse("file.xml")
for product in tree.getroot():
for child in product:
if child.tag == "parent":
child.text = pairs[child.text]
tree.write("output.xml")

output.xml:中

<products>
<product>
<id>1</id>
<parent>1</parent>
</product>
<product>
<id>2</id>
<parent>1</parent>
</product>
<product>
<id>3</id>
<parent>1</parent>
</product>
<product>
<id>4</id>
</product>
<product>
<id>5</id>
<parent>5</parent>
</product>
<product>
<id>6</id>
<parent>5</parent>
</product>
</products>

最新更新