循环遍历XML节点并在Python中比较其元素的文本

2024-09-29 23:29:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在处理一个XML文件,其中一部分如下所示:

<tblSampleParts>
    <AnID>1</AnID>
    <JrID>11</JrID>
</tblSampleParts>
<tblSampleParts>
    <AnID>2</AnID>
    <JrID>16</JrID>
</tblSampleParts>
<tblSampleParts>
    <AnID>2</AnID>
    <JrID>28</JrID>
</tblSampleParts>
<tblSampleParts>
    <AnID>2</AnID>
    <JrID>29</JrID>
<tblSampleParts>
    <AnID>3</AnID>
    <JrID>5</JrID>
</tblSampleParts>
<tblSampleParts>
    <AnID>4</AnID>
    <JrID>22</JrID>
</tblSampleParts>
<tblSampleParts>
    <AnID>5</AnID>
    <JrID>12</JrID>
</tblSampleParts>
<tblSampleParts>
    <AnID>5</AnID>
    <JrID>18</JrID>
<tblSampleParts>
    <AnID>6</AnID>
    <JrID>6</JrID>
</tblSampleParts>

我要做的是循环遍历节点并比较“AnID”元素的值。如果一个“AnID”的值被多次显示,那么我想打印AnID的文本和相应的JrID。因此,在查看随附代码时,我希望打印的内容是:

    <AnID>2</AnID>
    <JrID>16</JrID>

    <AnID>2</AnID>
    <JrID>28</JrID>

    <AnID>2</AnID>
    <JrID>29</JrID>

    <AnID>5</AnID>
    <JrID>12</JrID>

    <AnID>5</AnID>
    <JrID>18</JrID>

我自己也尝试过,并使用int()函数将文本转换为整数,然后尝试通过所有节点循环,但我遇到了类似“字符串索引必须是整数”这样的错误

目前,我正在使用以下代码收集和打印AnID和JrID的值:

import pandas as pd
from lxml import objectify
path='0458510148.xml'
parsed=objectify.parse(open(path))
root=parsed.getroot()


data=[]
skip_fields=['tblProjects','tblMeasurementPoints']

for elt in root.tblSampleParts:
    el_data={}
    for child in elt.getchildren():
        el_data[child.tag]=child.pyval
    data.append(el_data)


perf=pd.DataFrame(data)
print(perf)

结果如下:

    AnID  JrID
0      1    11
1      2    16
2      2    28
3      3     5
4      4    22
5      5    12
6      6     6
7      7     1
8      8    17
9      9    18
10    10    10
11    10    13
12    10    24
13    11     2
14    11     8
15    11    14
16    11    25
17    12    10
18    13    13
19    14    24

但我不知道如何只打印AnID(及其对应的JrID),其编号会出现多次


Tags: path代码文本importchilddata节点整数
3条回答

这有点复杂,但可以使用xpath完成:

from lxml import etree

ids = """<root>[your xml above[</root>""" #note: the xml in the question is not well formed; it needs to be wrapped in a root element

uniq_anids = {id for id in doc.xpath('//AnID/text()')}
targets = [u_a for u_a in uniq_anids if doc.xpath(f'count(//AnID[text()="{u_a}"])')>1]
for target in targets:
    for tsp in doc.xpath(f'//tblSampleParts[./AnID[text()="{target}"]]/*'):
        print(etree.tostring(tsp).decode())

输出应该是您问题中指出的输出

好的,我试了一下:

import lxml
from bs4 import BeautifulSoup

sample_data = """
<xml>
    <tblSampleParts>
        <AnID>1</AnID>
        <JrID>11</JrID>
    </tblSampleParts>
    <tblSampleParts>
        <AnID>2</AnID>
        <JrID>16</JrID>
    </tblSampleParts>
    <tblSampleParts>
        <AnID>2</AnID>
        <JrID>28</JrID>
    </tblSampleParts>
    <tblSampleParts>
        <AnID>2</AnID>
        <JrID>29</JrID>
    <tblSampleParts>
        <AnID>3</AnID>
        <JrID>5</JrID>
    </tblSampleParts>
    <tblSampleParts>
        <AnID>4</AnID>
        <JrID>22</JrID>
    </tblSampleParts>
    <tblSampleParts>
        <AnID>5</AnID>
        <JrID>12</JrID>
    </tblSampleParts>
    <tblSampleParts>
        <AnID>5</AnID>
        <JrID>18</JrID>
    <tblSampleParts>
        <AnID>6</AnID>
        <JrID>6</JrID>
    </tblSampleParts>
</xml>
"""

soup = BeautifulSoup(sample_data, 'xml')

parts = soup.find_all('tblSampleParts')

AnIDs = []
JrIDs = []
for p in parts:
    an = p.AnID.text
    AnIDs.append(an)
    jr = p.JrID.text
    JrIDs.append(jr)

for i, a in enumerate(AnIDs):
    if AnIDs.count(a) > 1:
        print(f'<AnID>{a}</AnID>\n<JrID>{JrIDs[i]}</JrID>')

这张照片

<AnID>2</AnID>
<JrID>16</JrID>
<AnID>2</AnID>
<JrID>28</JrID>
<AnID>2</AnID>
<JrID>29</JrID>
<AnID>5</AnID>
<JrID>12</JrID>
<AnID>5</AnID>
<JrID>18</JrID>

我猜这应该是你想要的,对吧

更新:

BeautifulSoup不提供直接读取文件/网页的功能

如果数据以文件data.xml的形式存在于本地,则可以执行以下操作(假设文件与脚本位于同一文件夹中-使用相对路径):

with open('data.xml', 'r') as f:
    contents = f.read()
    soup = BeautifulSoup(contents, 'xml')

如果要使用联机数据,请执行以下操作:

import requests

url = "http://some.url.com/data.xml"
req = requests.get(url)
soup = BeautifulSoup(req.content, 'xml')

(应该大致可行,但还没有尝试过,因此您可能需要在这里和那里进行调整)

我认为没有太多的理由将其转换为整数,您也可以比较字符串值

您可以尝试以下方法:

  • 创建字典
  • 在每个<tblSampleParts>上循环
    • 使用<AnID>中的字符串作为k,使用<JrID>中的字符串作为v
    • 如果键不在dict中,则将键k和列表[v]作为值添加到dict中
    • 如果键在dict中,则将v附加到列表中
  • 在dict中的每个键值对上循环
    • 如果值中的列表仅包含一个元素,请跳过它
    • 如果列表中包含更多元素,这就是您要查找的情况之一

我敢肯定,有更好、更有效、更通情达理的方法可以做到这一点。但这至少应该是可行的

在任何情况下,对于此解决方案,您都可以使用字符串"5"以及整数5作为键。
但是,如果您坚持将字符串转换为整数,并且不断出现错误,那么您可能需要了解导致这些错误的字符串是什么

相关问题 更多 >

    热门问题