提问人:Bushido_T 提问时间:11/18/2023 最后编辑:TimelessBushido_T 更新时间:11/18/2023 访问量:79
需要在 Python 中用其他元素的子重复一个 XML 元素
Need to repeat one XML element with other element's subs in Python
问:
我有一些晦涩难懂的XML文件,其中包含一些大量嵌套的元素。我能够解析元素并获取所有内容,但遇到了无法解决的问题。可能有更好的方法,但我在解析 XML 方面还不是很精通。
XML 文件
<NAXML-MaintenanceRequest xmlns:vxt="urn:vfi-sapphire:np.naxmlext.2005-06-24" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.4" xmlns="http://www.naxml.org/POSBO/Vocabulary/2003-10-16">
<TransmissionHeader>
<StoreLocationID>7500</StoreLocationID>
<VendorName>PDI</VendorName>
<VendorModelVersion>PDI/Enterprise 11.9.01</VendorModelVersion>
</TransmissionHeader>
<ItemListMaintenance>
<TableAction type="initialize" />
<RecordAction type="addchange" confirm="no" />
<ILTDetail>
<RecordAction type="addchange" confirm="no" />
<ItemListID>100</ItemListID>
<ItemListDescription>MM\Dasani 1L</ItemListDescription>
<ItemListEntry>
<ItemCode>
<POSCodeFormat format="gtin" checkDigit="present" />
<POSCode>00049000026566</POSCode>
<POSCodeModifier name="EACH10">0</POSCodeModifier>
</ItemCode>
</ItemListEntry>
</ILTDetail>
<ILTDetail>
<RecordAction type="addchange" confirm="no" />
<ItemListID>101</ItemListID>
<ItemListDescription>MM\Vitamin Water 20oz</ItemListDescription>
<ItemListEntry>
<ItemCode>
<POSCodeFormat format="gtin" checkDigit="present" />
<POSCode>00786162150004</POSCode>
<POSCodeModifier name="EACH5">0</POSCodeModifier>
</ItemCode>
</ItemListEntry>
<ItemListEntry>
<ItemCode>
<POSCodeFormat format="gtin" checkDigit="present" />
<POSCode>00786162002976</POSCode>
<POSCodeModifier name="EACH5">0</POSCodeModifier>
</ItemCode>
</ItemListEntry>
</ILTDetail>
</ItemListMaintenance>
</NAXML-MaintenanceRequest>
我正在尝试获取 ItemListID 和分配给它的任何相应 POSCode。当我尝试时,我只能获得每个值,但不能将它们放在一起。我确信我的方法步骤太多,但这是我所能理解的当前状态。
import pandas as pd
import xml.etree.ElementTree as ET
import numpy as np
import os, os.path, sys
import csv
itemFile = "myfilepathhere.xml"
tree = ET.parse(itemFile)
root = tree.getroot()
# Returns key value pairs #
def extract_elements(element, path='', elements=None):
if elements is None:
elements = []
path = '/'.join([path, element.tag]) if path else element.tag
for child in element:
if len(child) == 0:
elements.append({'Path': child.tag, 'Value': child.text})
else:
extract_elements(child, path, elements)
return elements
all_elements = []
for record in root:
all_elements.extend(extract_elements(record))
df = pd.DataFrame(all_elements)
print(df)
如果有更好的道路,我将不胜感激。理想情况下,结果是
ItemListID | POSCode |
---|---|
100 | 00049000026566 |
101 | 00786162150004 |
101 | 00786162002976 |
答:
1赞
erny
11/18/2023
#1
您可以使用 or 方法并通过 XPATH 进行搜索,例如(示例已更新,感谢 @mzjn):findall
iterfind
tree = ET.parse('<xml file>')
details = tree.findall('.//{*}ILTDetail')
for detail in detail:
itemListID, POSCode = detail[1].text, detail[3][0][1].text
...
这些索引是关于获得第 n 个子项的,即 意思是:获取细节的第4个子项,获取结果的第一个子项,然后获取最后一个结果的第二个子项。(索引从 0 开始)detail[3][0][1]
除此之外,lxml 库还提供了一个 ElementTree 接口,它的用法与 xml.etree 非常相似。但它更易于使用:
from lxml import etree as ET
tree = ET.parse('<xml file>')
details = tree.findall(".//{*}ILTDetail")
评论
1赞
mzjn
11/18/2023
您可以为命名空间使用通配符:stackoverflow.com/a/62117710/407651。
0赞
erny
11/18/2023
@mzjn:太酷了,谢谢。我更新了示例。
0赞
Bushido_T
11/18/2023
谢谢你,lxml确实有一些易于使用的功能,我现在正在研究。
1赞
Timeless
11/18/2023
#2
遍历每个 ,制作一个字典列表并将其传递给 DataFrame
构造函数:ILTDetail
import xml.etree.ElementTree as ET
import pandas as pd
elems = ET.parse("file.xml").findall(".//{*}ILTDetail")
df = pd.DataFrame(
[
{
"ItemListID": det.findtext("{*}ItemListID"),
"POSCode": psc.text
} for det in elems for psc in det.findall(".//{*}POSCode")
]
)
输出:
print(df)
ItemListID POSCode
0 100 00049000026566
1 101 00786162150004
2 101 00786162002976
[3 rows x 2 columns]
评论
1赞
Bushido_T
11/18/2023
非常感谢你!我能够完全按照我的需要提取所有值。
2赞
LMC
11/18/2023
#3
Pandas 唯一的解决方案
与功能一起使用,然后“重塑”数据帧。
每个元素最多考虑 3 个元素pandas.read_xml()
iterparse
POSCode
ItemListID
iterdict = {"ILTDetail": ["ItemListID", "POSCode", "POSCode", "POSCode"]}
names = ["ItemListID", "POSCode1", "POSCode2","POSCode3"]
df_tmp = pd.read_xml('tmp2', iterparse=iterdict, dtype=object, names=names)
df = pd.melt(df_tmp, id_vars=names[0], value_vars=names[1:], value_name="POSCode").dropna()[["ItemListID","POSCode"]
结果
0 100 00049000026566
1 101 00786162150004
2 102 00786162003458
4 101 00786162002976
5 102 00786162004621
8 102 00786162021870
评论