Saya sedang berurusan dengan file XML yang sebagiannya ditampilkan di bawah ini:

<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>

Yang ingin saya lakukan adalah mengulang melalui node dan membandingkan nilai elemen "AnID". Jika nilai "AnID " ditampilkan lebih dari sekali, maka saya ingin mencetak teks dari AnID dan JrID yang sesuai. Jadi yang ingin saya cetak ketika melihat kode terlampir adalah:

    <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>

Saya sudah mencobanya sendiri dan menggunakan fungsi int() untuk mengonversi teks menjadi bilangan bulat dan mencoba dan mengulang melalui semua simpul, tetapi saya membuat kesalahan seperti 'indeks string harus bilangan bulat'.

Saat ini saya menggunakan kode berikut untuk mengumpulkan dan mencetak nilai AnID dan 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)

Ini memberikan hasil berikut:

    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

Tapi saya tidak tahu bagaimana hanya mencetak AnID (dengan JrID yang sesuai) yang nomornya muncul lebih dari sekali.

-1
Murcie 4 Januari 2021, 03:37

3 jawaban

Jawaban Terbaik

Oke, jadi saya mencobanya:

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>')

Ini mencetak

<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>

Saya kira itu yang Anda inginkan, bukan?

Memperbarui:

BeautifulSoup tidak menyediakan fungsi untuk membaca file/halaman web secara langsung.

Jika Anda memiliki data secara lokal, sebagai file data.xml, Anda dapat melakukan hal berikut (ini mengasumsikan file berada di folder yang sama dengan skrip - gunakan jalur relatif):

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

Jika Anda ingin menggunakan data online, lakukan hal berikut:

import requests

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

(kira-kira harus berfungsi, belum mencobanya, jadi Anda mungkin harus mengubahnya di sana-sini)

0
Balduin 13 Januari 2021, 01:02

Saya tidak berpikir ada banyak alasan untuk mengubahnya menjadi integer, Anda dapat membandingkan nilai string juga.

Anda dapat mencoba yang berikut ini:

  • buat kamus
  • loop di atas setiap <tblSampleParts>
    • gunakan string dalam <AnID> sebagai k dan string <JrID> sebagai v
    • jika kunci tidak ada dalam dict, tambahkan kunci k dan daftar [v] sebagai nilai pada dict
    • jika kuncinya ada di dict, tambahkan v ke daftar
  • loop pada setiap pasangan nilai-kunci dalam dict
    • jika daftar dalam nilai hanya berisi satu elemen, lewati saja
    • jika daftar berisi lebih banyak elemen, itulah salah satu kasus yang Anda cari.

Saya yakin, ada cara yang lebih baik, lebih efisien, dan lebih Pythonic untuk melakukannya. Tapi ini harus bekerja, setidaknya.

Bagaimanapun, untuk solusi ini, Anda dapat menggunakan string "5" serta bilangan bulat 5 sebagai kunci.
Namun, jika Anda bersikeras untuk mengubah string menjadi bilangan bulat, dan terus mendapatkan kesalahan, Anda mungkin ingin melihat apa string itu, yang menyebabkan kesalahan ini.

0
Balduin 4 Januari 2021, 01:09

Ini agak berbelit-belit, tetapi dapat dilakukan menggunakan 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())

Outputnya harus yang ditunjukkan dalam pertanyaan Anda.

0
Jack Fleeting 4 Januari 2021, 16:21